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: k
- type: text - Overrides the private key given in the define statement. Also an alias key can be used.
ttl
- short: l
- 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: p
- 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: k
- 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: l
- 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: p
- 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: