diff --git a/fhem/CHANGED b/fhem/CHANGED index 85a399ce1..e7ad0cdc3 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,8 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: Pushsafer: new option "picture", "picture2" and "picture3" for + "message" set command to send pictures from local + filesystem or a IPCAM device. See commandref for details - change: FB_CALLMONITOR: open TCP connection non-blocking, shutdown connection when disabled - bugfix: 73_km200: Experimental keys on scalar is now forbidden diff --git a/fhem/FHEM/70_Pushsafer.pm b/fhem/FHEM/70_Pushsafer.pm index 38d2708da..fdfcb9850 100755 --- a/fhem/FHEM/70_Pushsafer.pm +++ b/fhem/FHEM/70_Pushsafer.pm @@ -32,6 +32,7 @@ package main; use HttpUtils; +use MIME::Base64 qw(encode_base64 encode_base64url); use utf8; my %Pushsaver_Params = ( @@ -44,7 +45,10 @@ my %Pushsaver_Params = ( "key" => {"short" => "k", "check" => qr/^[a-zA-Z\d]{20}$/}, "urlText" => {"short" => "ut"}, "message" => {"short" => "m"}, - "ttl" => {"short" => "l", "check" => qr/^\d+$/} + "ttl" => {"short" => "l", "check" => qr/^\d+$/}, + "picture" => {"short" => "p"}, + "picture2" => {"short" => "p2"}, + "picture3" => {"short" => "p3"} ); @@ -149,7 +153,8 @@ sub Pushsafer_Set($$$@) sub Pushsafer_createBody($$) { my ($hash, $args) = @_; - + my $name = $hash->{NAME}; + my @urlParts; my @errs; @@ -157,6 +162,9 @@ sub Pushsafer_createBody($$) foreach my $item (keys %{$args}) { + my $key; + my $val; + if(exists($Pushsaver_Params{$item})) { if(exists($Pushsaver_Params{$item}{check}) and $args->{$item} !~ $Pushsaver_Params{$item}{check}) @@ -165,7 +173,8 @@ sub Pushsafer_createBody($$) } else { - push @urlParts, $Pushsaver_Params{$item}{short}."=".urlEncode($args->{$item}); + $key = $Pushsaver_Params{$item}{short}; + $val = $args->{$item} } } elsif(grep($Pushsaver_Params{$_}{short} eq $item, keys(%Pushsaver_Params))) @@ -178,19 +187,108 @@ sub Pushsafer_createBody($$) } else { - push @urlParts, $item."=".urlEncode($args->{$item}); + $key = $item; + $val = $args->{$item} } } else { - push @errs, "unsupported parameter $item"; + push @errs, "unsupported parameter: $item"; + next; } + + if($key =~/^p\d?$/) + { + if(-r $val) + { + $val = Pushsafer_createDataUrl($hash, $val); + next unless(defined($val)); + } + elsif($val =~ /^IPCAM:(\S+)$/) + { + my $ipcam = $1; + + if(!exists($defs{$ipcam}) or !exists($defs{$ipcam}{TYPE}) or $defs{$ipcam}{TYPE} ne "IPCAM") + { + Log3 $name, 3, "Pushsafer ($name) - no such IPCAM device: $ipcam. sending message without a picture..."; + next; + } + + my $path = AttrVal($ipcam, "storage",$attr{global}{modpath}."/www/snapshots"); + $path .= "/" unless($path =~ m,/$,); + $path .= ReadingsVal($ipcam, "last", ""); + + $val = Pushsafer_createDataUrl($hash, $path); + + } + } + + push @urlParts, $key."=".urlEncode($val); } return join("\n", @errs) if(@errs); return (undef, join("&", @urlParts)); } + +##################################### +# determine the image file format (reused from IPCAM module by Martin Fischer) +sub Pushsafer_guessFileFormat($) +{ + my ($src) = shift; + my $header; + my $srcHeader; + + open(my $s, "<", $src) || return undef; + $src = $s; + + my $reading = read($src, $srcHeader, 64); + return undef if(!$reading); + + local($_) = $srcHeader; + + return "image/jpeg" if /^\xFF\xD8/; + return "image/png" if /^\x89PNG\x0d\x0a\x1a\x0a/; + return "image/gif" if /^GIF8[79]a/; + return undef; +} +##################################### +# create a data URL schema from a image file +sub Pushsafer_createDataUrl($$) +{ + my ($hash, $file) = @_; + my $name = $hash->{NAME}; + + Log3 $name, 4, "Pushsafer ($name) - open image file: $file"; + + my ($err, @content) = FileRead({FileName => $file, ForceType => "file"}); + + if(defined($err)) + { + Log3 $name, 3, "Pushsafer ($name) - unable to open image file: $file - sending message without picture..."; + } + else + { + my $image = join($/, @content); + my $mime_type = Pushsafer_guessFileFormat(\$image); + + if(defined($mime_type)) + { + Log3 $name, 5, "Pushsafer ($name) - found image of type: $mime_type"; + + my $base_64 = encode_base64($image); + + return "data:$mime_type;base64,".$base_64; + } + else + { + Log3 $name, 3, "Pushsafer ($name) - unsupported image type for $file - see commandref for supported image formats"; + } + } + + return undef; +} + ############################# # sents a message via HTTP request sub Pushsafer_Send($$) @@ -333,6 +431,9 @@ sub Pushsafer_Callback($$$) urlText   - short: ut - type: text - A text that should be used to display a URL from the "url" option.
key       - short: - type: text - Overrides the private key given in the define statement. Also an alias key can be used.
ttl       - short: - type: number - Defines a "time-to-live" given in minutes after the message will be deleted on the target device(s). Possible range is between 1 - 43200 minutes (30 days).
+ picture   - short: - type: text - Attach a image to the message. This can be a file path located in your filesystem (e.g. picture=/home/user/picture.jpg) or the name of a IPCAM instance (like picture=IPCAM:<name>) to send the last snapshot image (e.g. picture=IPCAM:IpCam_Front_House). The supported image formats are JPG, PNG and GIF.
+ picture2  - short: p2 - type: text - same syntax as for option "picture"
+ picture3  - short: p3 - type: text - same syntax as for option "picture"

Examples:

@@ -424,6 +525,10 @@ sub Pushsafer_Callback($$$) urlText   - Kurzform: ut - Typ: Text - Der Text, welcher zum Anzeigen der URL benutzt werden soll anstatt der Zieladresse.
key       - Kurzform: - Typ: Text - Übersteuert den zu nutzenden Schlüssel zur Identifikation aus dem define-Kommando. Es kann hierbei auch ein Email-Alias-Schlüssel benutzt werden.
ttl       - Kurzform: - Typ: Ganzzahl - Die Lebensdauer der Nachricht in Minuten. Sobald die Lebensdauer erreicht ist, wird die Nachricht selbstständig auf allen Geräten gelöscht. Der mögliche Wertebereich liegt zwischen 1 - 43200 Minuten (entspricht 30 Tagen).
+ picture   - Kurzform: - Typ: Text - Anhängen eines Bildes zur Nachricht. Dies kann ein Dateipfad zu einer Bilddatei sein (z.B. picture=/home/user/Bild.jpg) oder der Name einer IPCAM-Instanz (im Format: picture=IPCAM:<Name>) um die letzte Aufnahme zu senden (Bsp. picture=IPCAM:IpKamera_Einganstuer). Es werden die Dateiformate JPG, PNG und GIF unterstüzt.
+ picture2  - Kurzform: p2 - Typ: Text - Gleiche Syntax wie die Option "picture".
+ picture3  - Kurzform: p3 - Typ: Text - Gleiche Syntax wie die Option "picture".
+
Beispiele: