################################################################ # # Developed with Kate # # (c) 2015 Copyright: Marko Oldenburg (leongaultier at gmail dot com) # All rights reserved # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # any later version. # # The GNU General Public License can be found at # http://www.gnu.org/copyleft/gpl.html. # A copy is found in the textfile GPL.txt and important notices to the license # from the author is found in LICENSE.txt distributed with these scripts. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # ################################################################ package main; use strict; use warnings; use Time::HiRes qw(gettimeofday); use HttpUtils; my $version = "0.5.8"; sub AMAD_Initialize($) { my ($hash) = @_; $hash->{SetFn} = "AMAD_Set"; $hash->{DefFn} = "AMAD_Define"; $hash->{UndefFn} = "AMAD_Undef"; $hash->{AttrFn} = "AMAD_Attr"; $hash->{ReadFn} = "AMAD_Read"; $hash->{AttrList} = "setOpenApp ". "setFullscreen:0,1 ". "setScreenOrientation:0,1 ". "setScreenBrightness:0,1 ". "fhemServerIP ". "root:0,1 ". "interval ". "port ". "disable:1 "; $hash->{AttrList} .= $readingFnAttributes; } sub AMAD_Define($$) { my ( $hash, $def ) = @_; my @a = split( "[ \t][ \t]*", $def ); return "too few parameters: define AMAD " if ( @a != 3 ); my $name = $a[0]; my $host = $a[2]; my $port = 8090; my $interval = 180; $hash->{HOST} = $host; $hash->{PORT} = $port; $hash->{INTERVAL} = $interval; $hash->{VERSION} = $version; Log3 $name, 3, "AMAD ($name) - defined with host $hash->{HOST} on port $hash->{HOST} and interval $hash->{INTERVAL} (sec)"; AMAD_GetUpdateLocal($hash); InternalTimer(gettimeofday()+$hash->{INTERVAL}, "AMAD_GetUpdateTimer", $hash, 0); $hash->{STATE} = "initialized"; readingsSingleUpdate ($hash,"deviceState","online",0); return undef; } sub AMAD_Undef($$) { my ($hash, $arg) = @_; RemoveInternalTimer($hash); return undef; } sub AMAD_Attr(@) { my ( $cmd, $name, $attrName, $attrVal) = @_; my $hash = $defs{$name}; if ($attrName eq "disable") { if($cmd eq "set") { if($attrVal eq "0") { RemoveInternalTimer($hash); InternalTimer(gettimeofday()+2, "AMAD_GetUpdateTimer", $hash, 0) if ($hash->{STATE} eq "disabled"); $hash->{STATE}='active'; Log3 $name, 3, "AMAD ($name) - enabled"; } else { $hash->{STATE} = 'disabled'; RemoveInternalTimer($hash); Log3 $name, 3, "AMAD ($name) - disabled"; } } elsif ($cmd eq "del") { RemoveInternalTimer($hash); InternalTimer(gettimeofday()+2, "AMAD_GetUpdateTimer", $hash, 0) if ($hash->{STATE} eq "disabled"); $hash->{STATE}='active'; Log3 $name, 3, "AMAD ($name) - enabled"; } else { if($cmd eq "set") { $attr{$name}{$attrName} = $attrVal; Log3 $name, 3, "AMAD ($name) - $attrName : $attrVal"; } elsif ($cmd eq "del") { } } } if ($attrName eq "interval") { if ($cmd eq "set") { if ($attrVal < 60) { Log3 $name, 3, "AMAD ($name) - interval too small, please use something > 60 (sec), default is 180 (sec)"; return "interval too small, please use something > 60 (sec), default is 180 (sec)"; } else { $hash->{INTERVAL} = $attrVal; Log3 $name, 3, "AMAD ($name) - set interval to $attrVal"; } } elsif ($cmd eq "del") { $hash->{INTERVAL} = 180; Log3 $name, 3, "AMAD ($name) - set interval to default"; } else { if($cmd eq "set") { $attr{$name}{$attrName} = $attrVal; Log3 $name, 3, "AMAD ($name) - $attrName : $attrVal"; } elsif ($cmd eq "del") { } } } if ($attrName eq "port") { if ($cmd eq "set") { $hash->{PORT} = $attrVal; Log3 $name, 3, "AMAD ($name) - set port to $attrVal"; } elsif ($cmd eq "del") { $hash->{PORT} = 8090; Log3 $name, 3, "AMAD ($name) - set port to default"; } else { if($cmd eq "set") { $attr{$name}{$attrName} = $attrVal; Log3 $name, 3, "AMAD ($name) - $attrName : $attrVal"; } elsif ($cmd eq "del") { } } } return undef; } sub AMAD_GetUpdateLocal($) { my ($hash) = @_; my $name = $hash->{NAME}; AMAD_RetrieveAutomagicInfo($hash); return 1; } sub AMAD_GetUpdateTimer($) { my ($hash) = @_; my $name = $hash->{NAME}; AMAD_RetrieveAutomagicInfo($hash) if (ReadingsVal($name,"deviceState","online") eq "online" && $hash->{STATE} ne "disabled"); # deviceState muß von Hand online/offline gesetzt werden z.B. über RESIDENZ Modul InternalTimer(gettimeofday()+$hash->{INTERVAL}, "AMAD_GetUpdateTimer", $hash, 1); Log3 $name, 4, "AMAD ($name) - Call AMAD_GetUpdateTimer"; return 1; } sub AMAD_Set($$@) { my ($hash, $name, $cmd, @val) = @_; my $apps = AttrVal("$name","setOpenApp","none"); my $list = ""; $list .= "screenMsg "; $list .= "ttsMsg "; $list .= "volume:slider,0,1,15 "; $list .= "deviceState:online,offline "; $list .= "mediaPlayer:play,stop,next,back " if (AttrVal("$name","fhemServerIP","none") ne "none"); $list .= "screenBrightness:slider,0,1,255 " if (AttrVal("$name","setScreenBrightness","0") eq "1"); $list .= "screen:on,off "; $list .= "screenOrientation:auto,landscape,portrait " if (AttrVal("$name","setScreenOrientation","0") eq "1"); $list .= "screenFullscreen:on,off " if (AttrVal("$name","setFullscreen","0") eq "1"); $list .= "openURL "; $list .= "openApp:$apps " if (AttrVal("$name","setOpenApp","none") ne "none"); $list .= "nextAlarmTime:time "; $list .= "statusRequest:noArg "; $list .= "system:reboot " if (AttrVal("$name","root","none") ne "none"); if (lc $cmd eq 'screenmsg' || lc $cmd eq 'ttsmsg' || lc $cmd eq 'volume' || lc $cmd eq 'mediaplayer' || lc $cmd eq 'devicestate' || lc $cmd eq 'screenbrightness' || lc $cmd eq 'screenorientation' || lc $cmd eq 'screenfullscreen' || lc $cmd eq 'screen' || lc $cmd eq 'openurl' || lc $cmd eq 'openapp' || lc $cmd eq 'nextalarmtime' || lc $cmd eq 'system' || lc $cmd eq 'statusrequest') { Log3 $name, 5, "AMAD ($name) - set $name $cmd ".join(" ", @val); return AMAD_SelectSetCmd ($hash, $cmd, @val) if (@val) || (lc $cmd eq 'statusrequest'); } return "Unknown argument $cmd, bearword as argument or wrong parameter(s), choose one of $list"; } sub AMAD_RetrieveAutomagicInfo($) { my ($hash) = @_; my $name = $hash->{NAME}; my $host = $hash->{HOST}; my $port = $hash->{PORT}; my $fhemip = AttrVal("$name","fhemServerIP","none"); my $url = "http://" . $host . ":" . $port . "/fhem-amad/deviceInfo/"; # Path muß so im Automagic als http request Trigger drin stehen HttpUtils_NonblockingGet( { url => $url, timeout => 5, hash => $hash, method => "GET", header => "fhemIP: $fhemip\r\nfhemDevice: $name", doTrigger => 1, callback => \&AMAD_RetrieveAutomagicInfoFinished, } ); Log3 $name, 4, "AMAD ($name) - NonblockingGet get URL"; Log3 $name, 4, "AMAD ($name) - AMAD_RetrieveAutomagicInfo: calling Host: $host"; } sub AMAD_RetrieveAutomagicInfoFinished($$$) { my ( $param, $err, $data ) = @_; my $hash = $param->{hash}; my $doTrigger = $param->{doTrigger}; my $name = $hash->{NAME}; my $host = $hash->{HOST}; Log3 $name, 4, "AMAD ($name) - AMAD_RetrieveAutomagicInfoFinished: processed request data"; ### Begin Error Handling if (defined($err)) { if ($err ne "") { $hash->{STATE} = $err if ($hash->{STATE} ne "initialized"); readingsBeginUpdate ($hash); readingsBulkUpdate ($hash,"lastStatusRequestState","statusRequest_error"); if ($err =~ /timed out/) { readingsBulkUpdate ($hash,"lastStatusRequestError","connect to your device is timed out. check network"); } elsif ($err =~ /Keine Route zum Zielrechner/) { readingsBulkUpdate ($hash,"lastStatusRequestError","no route to target. bad network configuration or network is down"); } else { readingsBulkUpdate ($hash,"lastStatusRequestError","$err"); } readingsEndUpdate ($hash,1); Log3 $name, 5, "AMAD ($name) - AMAD_RetrieveAutomagicInfoFinished: error while requesting AutomagicInfo: $err"; return; } } if($data eq "" and exists($param->{code})) { $hash->{STATE} = $param->{code} if ($hash->{STATE} ne "initialized"); readingsBeginUpdate ($hash); readingsBulkUpdate ($hash,"lastStatusRequestState","statusRequest_error"); if ($param->{code} ne 200) { readingsBulkUpdate ($hash,"lastStatusRequestError","http Error ".$param->{code}); } readingsBulkUpdate ($hash,"lastStatusRequestError","empty response, check automagic on your device"); readingsEndUpdate ($hash,1); Log3 $name, 5, "AMAD ($name) - AMAD_RetrieveAutomagicInfoFinished: received http code ".$param->{code}." without any data after requesting AMAD AutomagicInfo"; return; } if($data =~ /\Error/i and exists($param->{code})) { $hash->{STATE} = $param->{code} if ($hash->{STATE} ne "initialized"); readingsBeginUpdate($hash); readingsBulkUpdate ($hash,"lastStatusRequestState","statusRequest_error"); if ($param->{code} eq 404) { readingsBulkUpdate ($hash,"lastStatusRequestError","automagic information flow is inactive on your device!"); } else { readingsBulkUpdate ($hash,"lastStatusRequestError","http error ".$param->{code}); } readingsEndUpdate ($hash,1); Log3 $name, 5, "AMAD ($name) - AMAD_RetrieveAutomagicInfoFinished: received http code ".$param->{code}." receive Error after requesting AMAD AutomagicInfo"; return; } ### End Error Handling ### Begin Response Processing $hash->{STATE} = "active" if ($hash->{STATE} eq "initialized" || $hash->{STATE} ne "active"); my @valuestring = split('@@@@', $data); my %buffer; foreach (@valuestring) { my @values = split('@@', $_); $buffer{$values[0]} = $values[1]; } readingsBeginUpdate($hash); my $t; my $v; while (($t, $v) = each %buffer) { $v =~ s/null//g; readingsBulkUpdate($hash, $t, $v) if (defined($v)); } readingsBulkUpdate ($hash,"lastStatusRequestState","statusRequest_done"); readingsEndUpdate($hash, 1); ### End Response Processing $hash->{STATE} = "active" if ($hash->{STATE} eq "initialized"); return undef; } sub AMAD_HTTP_POST($$) { my ($hash, $url) = @_; my $name = $hash->{NAME}; my $state = $hash->{STATE}; if ($hash->{STATE} eq "initialized") { Log3 $name, 3, "AMAD ($name) - AMAD_HTTP_POST: set command only works if STATE active, please wait for next interval run"; return "set command only works if STATE not equal initialized, please wait for next interval run"; } $hash->{STATE} = "Send HTTP POST"; HttpUtils_NonblockingGet( { url => $url, timeout => 5, hash => $hash, method => "POST", doTrigger => 1, callback => \&AMAD_HTTP_POSTerrorHandling, } ); Log3 $name, 4, "AMAD ($name) - Send HTTP POST with URL $url"; $hash->{STATE} = $state; return undef; } sub AMAD_HTTP_POSTerrorHandling($$$) { my ( $param, $err, $data ) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; ### Begin Error Handling if (defined($err)) { if ($err ne "") { $hash->{STATE} = $err if ($hash->{STATE} ne "initialized"); readingsBeginUpdate ($hash); readingsBulkUpdate ($hash,"lastSetCommandState","cmd_error"); if ($err =~ /timed out/) { readingsBulkUpdate ($hash,"lastSetCommandError","connect to your device is timed out. check network"); } elsif ($err =~ /Keine Route zum Zielrechner/) { readingsBulkUpdate ($hash,"lastSetCommandError","no route to target. bad network configuration or network is down"); } else { readingsBulkUpdate ($hash,"lastSetCommandError","$err"); } readingsEndUpdate ($hash,1); Log3 $name, 5, "AMAD ($name) - AMAD_HTTP_POST: error while POST Command: $err"; return; } } if($data eq "" and exists($param->{code})) { $hash->{STATE} = $param->{code} if ($hash->{STATE} ne "initialized"); readingsBeginUpdate ($hash); if ($param->{code} ne 200) { readingsBulkUpdate ($hash,"lastSetCommandState","cmd_error"); readingsBulkUpdate ($hash,"lastSetCommandError","http Error ".$param->{code}); } readingsBulkUpdate ($hash,"lastSetCommandState","cmd_done"); readingsEndUpdate ($hash,1); Log3 $name, 5, "AMAD ($name) - AMAD_HTTP_POST: received http code ".$param->{code}; Log3 $name, 4, "AMAD ($name) - Starte Update GetUpdateLocal"; AMAD_GetUpdateLocal($hash); return; } if($data =~ /Error/i and exists($param->{code})) { $hash->{STATE} = $param->{code} if ($hash->{STATE} ne "initialized"); readingsBeginUpdate($hash); readingsBulkUpdate ($hash,"lastSetCommandState","cmd_error"); if ($param->{code} eq 404) { readingsBulkUpdate ($hash,"lastSetCommandError","automagic setcommand flow is inactive on your device!"); } else { readingsBulkUpdate ($hash,"lastSetCommandError","http error ".$param->{code}); } } readingsEndUpdate ($hash,1); ### End Error Handling return undef; } sub AMAD_SelectSetCmd($$@) { my ($hash, $cmd, @data) = @_; my $name = $hash->{NAME}; my $host = $hash->{HOST}; my $port = $hash->{PORT}; if (lc $cmd eq 'screenmsg') { my $msg = join(" ", @data); $msg =~ s/%/%25/g; $msg =~ s/\s/%20/g; my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/screenMsg?message=$msg"; Log3 $name, 4, "AMAD ($name) - Sub AMAD_SetScreenMsg"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'ttsmsg') { my $msg = join(" ", @data); $msg =~ s/%/%25/g; $msg =~ s/\s/%20/g; my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/ttsMsg?message=$msg"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'volume') { my $vol = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setVolume?volume=$vol"; readingsSingleUpdate ($hash,$cmd,$vol,1); return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'mediaplayer') { my $btn = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/mediaPlayer?button=$btn"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'devicestate') { my $v = join(" ", @data); readingsSingleUpdate ($hash,$cmd,$v,1); return undef; } elsif (lc $cmd eq 'screenbrightness') { my $bri = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setBrightness?brightness=$bri"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'screen') { my $mod = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setScreenOnOff?screen=$mod"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'screenorientation') { my $mod = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setScreenOrientation?orientation=$mod"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'screenfullscreen') { my $mod = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setScreenFullscreen?fullscreen=$mod"; readingsSingleUpdate ($hash,$cmd,$mod,1); return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'openurl') { my $openurl = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/openURL?url=$openurl"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'nextalarmtime') { my $alarmTime = join(" ", @data); my @alarm = split(":", $alarmTime); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setAlarm?hour=".$alarm[0]."&minute=".$alarm[1]; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'statusrequest') { AMAD_GetUpdateLocal($hash); return undef; } elsif (lc $cmd eq 'openapp') { my $app = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/openApp?app=$app"; return AMAD_HTTP_POST ($hash,$url); } elsif (lc $cmd eq 'system') { my $systemcmd = join(" ", @data); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/systemcommand?syscmd=$systemcmd"; return AMAD_HTTP_POST ($hash,$url); } return undef; } 1; =pod =begin html

AMAD

=end html =begin html_DE

AMAD

=end html_DE =cut