############################################################################### # # 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. # # # $Id$ # ############################################################################### package main; use strict; use warnings; use Time::HiRes qw(gettimeofday); use HttpUtils; use TcpServerUtils; my $version = "0.7.9"; sub AMAD_Initialize($) { my ($hash) = @_; $hash->{SetFn} = "AMAD_Set"; $hash->{DefFn} = "AMAD_Define"; $hash->{UndefFn} = "AMAD_Undef"; $hash->{AttrFn} = "AMAD_Attr"; $hash->{ReadFn} = "AMAD_CommBridge_Read"; $hash->{AttrList} = "setOpenApp ". "checkActiveTask ". "setFullscreen:0,1 ". "setScreenOrientation:0,1 ". "setScreenBrightness:0,1 ". "setBluetoothDevice ". "root:0,1 ". "interval ". "port ". "disable:1 "; $hash->{AttrList} .= $readingFnAttributes; foreach my $d(sort keys %{$modules{AMAD}{defptr}}) { my $hash = $modules{AMAD}{defptr}{$d}; $hash->{VERSION} = $version; } } sub AMAD_Define($$) { my ( $hash, $def ) = @_; my @a = split( "[ \t][ \t]*", $def ); return "too few parameters: define AMAD " if( @a != 3 && $a[0] ne "AMADCommBridge" ); my $name = $a[0]; my $host = $a[2]; my $port = 8090; my $interval = 180; $hash->{HOST} = $host if( $host ); $hash->{PORT} = $port; $hash->{INTERVAL} = $interval if( $hash->{HOST} ); $hash->{VERSION} = $version; $hash->{helper}{infoErrorCounter} = 0 if( $hash->{HOST} ); $hash->{helper}{setCmdErrorCounter} = 0 if( $hash->{HOST} ); if( ! $hash->{HOST} ) { return "there is already a AMAD Bridge" if( $modules{AMAD}{defptr}{BRIDGE} ); $hash->{BRIDGE} = 1; $modules{AMAD}{defptr}{BRIDGE} = $hash; $attr{$name}{room} = "AMAD"; Log3 $name, 3, "AMAD ($name) - defined Bridge with Socketport $hash->{PORT}"; AMAD_CommBridge_Open( $hash ); } else { if( ! $modules{AMAD}{defptr}{BRIDGE} && $init_done ) { CommandDefine( undef, "AMADCommBridge AMAD" ); } Log3 $name, 3, "AMAD ($name) - defined with host $hash->{HOST} on port $hash->{PORT} and interval $hash->{INTERVAL} (sec)"; $attr{$name}{room} = "AMAD"; readingsSingleUpdate ( $hash, "state", "initialized", 1 ) if( $hash->{HOST} ); readingsSingleUpdate ( $hash, "deviceState", "online", 1 ) if( $hash->{HOST} ); InternalTimer( gettimeofday()+$hash->{INTERVAL}, "AMAD_GetUpdateTimer", $hash, 0 ) if( $hash->{HOST} ); $modules{AMAD}{defptr}{$hash->{HOST}} = $hash; return undef; } } sub AMAD_Undef($$) { my ( $hash, $arg ) = @_; if( $hash->{BRIDGE} ) { delete $modules{AMAD}{defptr}{BRIDGE}; my $ret = TcpServer_Close( $hash ); return $ret; } else { delete $modules{AMAD}{defptr}{$hash->{HOST}}; RemoveInternalTimer( $hash ); foreach my $d(sort keys %{$modules{AMAD}{defptr}}) { my $hash = $modules{AMAD}{defptr}{$d}; my $host = $hash->{HOST}; return if( $host ); CommandDelete( undef, "AMADCommBridge" ); } } } 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( ReadingsVal( $hash->{NAME}, "state", 0 ) eq "disabled" ); readingsSingleUpdate ( $hash, "state", "active", 1 ); Log3 $name, 3, "AMAD ($name) - enabled"; } else { readingsSingleUpdate ( $hash, "state", "disabled", 1 ); RemoveInternalTimer( $hash ); Log3 $name, 3, "AMAD ($name) - disabled"; } } elsif( $cmd eq "del" ) { RemoveInternalTimer( $hash ); InternalTimer( gettimeofday()+2, "AMAD_GetUpdateTimer", $hash, 0 ) if( ReadingsVal( $hash->{NAME}, "state", 0 ) eq "disabled" ); readingsSingleUpdate ( $hash, "state", "active", 1 ); 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 ) if( ReadingsVal( $name, "deviceState", "online" ) eq "online" && ReadingsVal( $hash->{NAME}, "state", 0 ) ne "initialized" && AttrVal( $name, "disable", 0 ) ne "1" ); ### deviceState muß von Hand online/offline gesetzt werden z.B. ueber RESIDENZ Modul return 1; } sub AMAD_GetUpdateTimer($) { my ( $hash ) = @_; my $name = $hash->{NAME}; AMAD_RetrieveAutomagicInfo( $hash ) if( ReadingsVal( $name, "deviceState", "online" ) eq "online" && AttrVal( $name, "disable", 0 ) ne "1" ); ### deviceState muss von Hand online/offline gesetzt werden z.B. ueber RESIDENZ Modul InternalTimer( gettimeofday()+$hash->{INTERVAL}, "AMAD_GetUpdateTimer", $hash, 1 ); Log3 $name, 4, "AMAD ($name) - Call AMAD_GetUpdateTimer"; return 1; } sub AMAD_RetrieveAutomagicInfo($) { my ($hash) = @_; my $name = $hash->{NAME}; my $host = $hash->{HOST}; my $port = $hash->{PORT}; my $fhemip = ReadingsVal( "AMADCommBridge", "fhemServerIP", "none" ); my $activetask = AttrVal( $name, "checkActiveTask", "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 => 10, hash => $hash, method => "GET", header => "fhemIP: $fhemip\r\nfhemDevice: $name\r\nactiveTask: $activetask", 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( $hash->{helper}{infoErrorCounter} > 2 ) { readingsBeginUpdate( $hash ); readingsBulkUpdate( $hash, "lastStatusRequestState", "statusRequest_error" ); if( ReadingsVal( $name, "flow_Informations", "active" ) eq "inactive" && ReadingsVal( $name, "flow_SetCommands", "active" ) eq "inactive" ) { readingsBulkUpdate( $hash, "lastStatusRequestError", "AMAD flows on your device inactive, please check your device" ); Log3 $name, 5, "AMAD ($name) - CHECK THE LAST ERROR READINGS FOR MORE INFO, DEVICE IS SET OFFLINE"; readingsBulkUpdate( $hash, "deviceState", "offline" ); readingsBulkUpdate ( $hash, "state", "AMAD Flows inactive, device set offline"); } elsif( $hash->{helper}{infoErrorCounter} > 9 && $hash->{helper}{setCmdErrorCounter} > 4 ) { readingsBulkUpdate( $hash, "lastStatusRequestError", "unknown error, please contact the developer" ); Log3 $name, 4, "AMAD ($name) - UNKNOWN ERROR, PLEASE CONTACT THE DEVELOPER, DEVICE DISABLED"; $attr{$name}{disable} = 1; readingsBulkUpdate ( $hash, "state", "Unknown Error, device disabled"); $hash->{helper}{infoErrorCounter} = 0; $hash->{helper}{setCmdErrorCounter} = 0; return; } elsif( ReadingsVal( $name, "flow_Informations", "active" ) eq "inactive" ) { readingsBulkUpdate( $hash, "lastStatusRequestError", "informations flow on your device is inactive, will try to reactivate" ); Log3 $name, 4, "AMAD ($name) - Informations Flow on your Device is inactive, will try to reactivate"; } elsif($hash->{helper}{infoErrorCounter} > 4 && ReadingsVal( $name, "flow_Informations", "active" ) eq "active" ){ readingsBulkUpdate( $hash, "lastStatusRequestError", "check automagicApp on your device" ); Log3 $name, 4, "AMAD ($name) - Please check the AutomagicAPP on your Device"; } elsif( $hash->{helper}{infoErrorCounter} > 9 ) { readingsBulkUpdate( $hash, "lastStatusRequestError", "to many errors, check your network or device configuration" ); Log3 $name, 4, "AMAD ($name) - To many Errors please check your Network or Device Configuration, DEVICE IS SET OFFLINE"; readingsBulkUpdate( $hash, "deviceState", "offline" ); readingsBulkUpdate ( $hash, "state", "To many Errors, device set offline"); $hash->{helper}{infoErrorCounter} = 0; } readingsEndUpdate( $hash, 1 ); } if( defined( $err ) ) { if( $err ne "" ) { readingsBeginUpdate( $hash ); readingsBulkUpdate ( $hash, "state", "$err") if( ReadingsVal( $name, "state", 1 ) ne "initialized" ); $hash->{helper}{infoErrorCounter} = ( $hash->{helper}{infoErrorCounter} + 1 ); 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/ ) && $hash->{helper}{infoErrorCounter} > 1 ) { readingsBulkUpdate( $hash,"lastStatusRequestError", "no route to target. bad network configuration or network is down "); } else { readingsBulkUpdate($hash, "lastStatusRequestError", $err ); } readingsEndUpdate( $hash, 1 ); Log3 $name, 4, "AMAD ($name) - AMAD_RetrieveAutomagicInfoFinished: error while requesting AutomagicInfo: $err"; return; } } if( $data eq "" and exists( $param->{code} ) ) { readingsBeginUpdate( $hash ); readingsBulkUpdate ( $hash, "state", $param->{code} ) if( ReadingsVal( $name, "state", 1 ) ne "initialized" ); $hash->{helper}{infoErrorCounter} = ( $hash->{helper}{infoErrorCounter} + 1 ); readingsBulkUpdate( $hash, "lastStatusRequestState", "statusRequest_error" ); if( $param->{code} ne 200 ) { readingsBulkUpdate( $hash," lastStatusRequestError", "http Error ".$param->{code} ); } readingsBulkUpdate( $hash, "lastStatusRequestError", "empty response, check automagicApp on your device" ); readingsEndUpdate( $hash, 1 ); Log3 $name, 4, "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} ) ) { readingsBeginUpdate( $hash ); readingsBulkUpdate( $hash, "state", $param->{code} ) if( ReadingsVal( $name, "state" ,0) ne "initialized" ); $hash->{helper}{infoErrorCounter} = ( $hash->{helper}{infoErrorCounter} + 1 ); readingsBulkUpdate( $hash, "lastStatusRequestState", "statusRequest_error" ); if( $param->{code} eq 404 && ReadingsVal( $name, "flow_Informations", "inactive" ) eq "inactive" ) { readingsBulkUpdate( $hash, "lastStatusRequestError", "check the informations flow on your device" ); } elsif( $param->{code} eq 404 && ReadingsVal( $name, "flow_Informations", "active" ) eq "active" ) { readingsBulkUpdate( $hash, "lastStatusRequestError", "check the automagicApp on your device" ); } else { readingsBulkUpdate( $hash, "lastStatusRequestError", "http error ".$param->{code} ); } readingsEndUpdate( $hash, 1 ); Log3 $name, 4, "AMAD ($name) - AMAD_RetrieveAutomagicInfoFinished: received http code ".$param->{code}." receive Error after requesting AMAD AutomagicInfo"; return; } ### End Error Handling $hash->{helper}{infoErrorCounter} = 0; ### Begin Response Processing readingsSingleUpdate( $hash, "state", "active", 1) if( ReadingsVal( $name, "state", 0 ) ne "initialized" or ReadingsVal( $name, "state", 0 ) 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" ); $hash->{helper}{infoErrorCounter} = 0; ### End Response Processing readingsBulkUpdate( $hash, "state", "active" ) if( ReadingsVal( $name, "state", 0 ) eq "initialized" ); readingsEndUpdate( $hash, 1 ); return undef; } sub AMAD_Set($$@) { my ( $hash, $name, $cmd, @val ) = @_; if( $name ne "AMADCommBridge" ) { my $apps = AttrVal( $name, "setOpenApp", "none" ); my $btdev = AttrVal( $name, "setBluetoothDevice", "none" ); my $activetask = AttrVal( $name, "setActiveTask", "none" ); my $list = ""; $list .= "screenMsg "; $list .= "ttsMsg "; $list .= "volume:slider,0,1,15 "; $list .= "deviceState:online,offline "; $list .= "mediaPlayer:play,stop,next,back " if( ReadingsVal( "AMADCommBridge", "fhemServerIP", "none" ) ne "none"); $list .= "screenBrightness:slider,0,1,255 " if( AttrVal( $name, "setScreenBrightness", "1" ) eq "1" ); $list .= "screen:on,off "; $list .= "screenOrientation:auto,landscape,portrait " if( AttrVal( $name, "setScreenOrientation", "1" ) eq "1" ); $list .= "screenFullscreen:on,off " if( AttrVal( $name, "setFullscreen", "1" ) 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", "1" ) eq "1" ); $list .= "bluetooth:on,off "; $list .= "notifySndFile "; $list .= "clearNotificationBar:All,Automagic "; $list .= "changetoBTDevice:$btdev " if( AttrVal( $name, "setBluetoothDevice", "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 'bluetooth' || lc $cmd eq 'system' || lc $cmd eq 'notifysndfile' || lc $cmd eq 'changetobtdevice' || lc $cmd eq 'clearnotificationbar' || lc $cmd eq 'statusrequest' ) { Log3 $name, 5, "AMAD ($name) - set $name $cmd ".join(" ", @val); return "set command only works if state not equal initialized, please wait for next interval run" if( ReadingsVal( $hash->{NAME}, "state", 0 ) eq "initialized"); return "Cannot set command, FHEM Device is disabled" if( AttrVal( $name, "disable", "0" ) eq "1" ); return AMAD_SelectSetCmd( $hash, $cmd, @val ) if( @val ) && ( ReadingsVal( $name, "deviceState", "online" ) eq "offline" ) && ( lc $cmd eq 'devicestate' ); return "Cannot set command, FHEM Device is offline" if( ReadingsVal( $name, "deviceState", "online" ) eq "offline" ); 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"; } elsif( $name eq "AMADCommBridge" ) { my $list = ""; ## set Befehle für die AMAD_CommBridge $list .= "expertMode:0,1 " if( $modules{AMAD}{defptr}{BRIDGE} ); $list .= "fhemServerIP " if( $modules{AMAD}{defptr}{BRIDGE} ); if( lc $cmd eq 'expertmode' || lc $cmd eq 'fhemserverip' ) { readingsSingleUpdate( $hash, $cmd, $val[0], 0 ); return; } return "Unknown argument $cmd, bearword as argument or wrong parameter(s), choose one of $list"; } } 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 ); } elsif( lc $cmd eq 'bluetooth' ) { my $mod = join( " ", @data ); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setbluetooth?bluetooth=$mod"; return AMAD_HTTP_POST( $hash,$url ); } elsif( lc $cmd eq 'notifysndfile' ) { my $notify = join( " ", @data ); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/playnotifysnd?notifyfile=$notify"; return AMAD_HTTP_POST( $hash,$url ); } elsif( lc $cmd eq 'changetobtdevice' ) { my $swToBtDevice = join( " ", @data ); my @swToBtMac = split( /\|/, $swToBtDevice ); my $btDevices = AttrVal( $name, "setBluetoothDevice", "none" ) if( AttrVal( $name, "setBluetoothDevice", "none" ) ne "none" ); my @btDevice = split( ',', $btDevices ); my @btDeviceOne = split( /\|/, $btDevice[0] ); my @btDeviceTwo = split( /\|/, $btDevice[1] ); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/setbtdevice?swToBtDeviceMac=".$swToBtMac[1]."&btDeviceOne=".$btDeviceOne[1]."&btDeviceTwo=".$btDeviceTwo[1]; return AMAD_HTTP_POST( $hash,$url ); } elsif( lc $cmd eq 'clearnotificationbar' ) { my $appname = join( " ", @data ); my $url = "http://" . $host . ":" . $port . "/fhem-amad/setCommands/clearnotificationbar?app=$appname"; return AMAD_HTTP_POST( $hash,$url ); } return undef; } sub AMAD_HTTP_POST($$) { my ( $hash, $url ) = @_; my $name = $hash->{NAME}; my $state = ReadingsVal( $name, "state", 0 ); readingsSingleUpdate( $hash, "state", "Send HTTP POST", 1 ); HttpUtils_NonblockingGet( { url => $url, timeout => 60, hash => $hash, method => "POST", doTrigger => 1, callback => \&AMAD_HTTP_POSTerrorHandling, } ); Log3 $name, 4, "AMAD ($name) - Send HTTP POST with URL $url"; readingsSingleUpdate( $hash, "state", $state, 1 ); return undef; } sub AMAD_HTTP_POSTerrorHandling($$$) { my ( $param, $err, $data ) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; ### Begin Error Handling if( $hash->{helper}{setCmdErrorCounter} > 2 ) { readingsBeginUpdate( $hash ); readingsBulkUpdate( $hash, "lastSetCommandState", "statusRequest_error" ); if( ReadingsVal( $name, "flow_Informations", "active" ) eq "inactive" && ReadingsVal( $name, "flow_SetCommands", "active" ) eq "inactive" ) { readingsBulkUpdate( $hash, "lastSetCommandError", "AMAD flows on your device inactive, please check your device" ); Log3 $name, 5, "AMAD ($name) - CHECK THE LAST ERROR READINGS FOR MORE INFO, DEVICE IS SET OFFLINE"; readingsBulkUpdate( $hash, "deviceState", "offline" ); readingsBulkUpdate( $hash, "state", "AMAD Flows inactive, device set offline" ); } elsif( $hash->{helper}{infoErrorCounter} > 9 && $hash->{helper}{setCmdErrorCounter} > 4 ) { readingsBulkUpdate($hash, "lastSetCommandError", "unknown error, please contact the developer" ); Log3 $name, 4, "AMAD ($name) - UNKNOWN ERROR, PLEASE CONTACT THE DEVELOPER, DEVICE DISABLED"; $attr{$name}{disable} = 1; readingsBulkUpdate( $hash, "state", "Unknown Error, device disabled" ); $hash->{helper}{infoErrorCounter} = 0; $hash->{helper}{setCmdErrorCounter} = 0; return; } elsif( ReadingsVal( $name, "flow_SetCommands", "active" ) eq "inactive" ) { readingsBulkUpdate( $hash, "lastSetCommandError", "setCommands flow on your device is inactive, will try to reactivate" ); Log3 $name, 4, "AMAD ($name) - Flow SetCommands on your Device is inactive, will try to reactivate"; } elsif( $hash->{helper}{setCmdErrorCounter} > 4 && ReadingsVal( $name, "flow_SetCommands", "active" ) eq "active" ){ readingsBulkUpdate( $hash, "lastSetCommandError", "check automagicApp on your device" ); Log3 $name, 4, "AMAD ($name) - Please check the AutomagicAPP on your Device"; } elsif( $hash->{helper}{setCmdErrorCounter} > 9 ) { readingsBulkUpdate( $hash, "lastSetCommandError", "to many errors, check your network or device configuration" ); Log3 $name, 4, "AMAD ($name) - To many Errors please check your Network or Device Configuration, DEVICE IS SET OFFLINE"; readingsBulkUpdate( $hash, "deviceState", "offline" ); readingsBulkUpdate( $hash, "state", "To many Errors, device set offline" ); $hash->{helper}{setCmdErrorCounter} = 0; } readingsEndUpdate( $hash, 1 ); } if( defined( $err ) ) { if( $err ne "" ) { readingsBeginUpdate( $hash ); readingsBulkUpdate( $hash, "state", $err ) if( ReadingsVal( $name, "state", 0 ) ne "initialized" ); $hash->{helper}{setCmdErrorCounter} = ($hash->{helper}{setCmdErrorCounter} + 1); 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} ) && $param->{code} ne 200 ) { readingsBeginUpdate( $hash ); readingsBulkUpdate( $hash, "state", $param->{code} ) if( ReadingsVal( $hash, "state", 0 ) ne "initialized" ); $hash->{helper}{setCmdErrorCounter} = ( $hash->{helper}{setCmdErrorCounter} + 1 ); readingsBulkUpdate($hash, "lastSetCommandState", "cmd_error" ); readingsBulkUpdate($hash, "lastSetCommandError", "http Error ".$param->{code} ); readingsEndUpdate( $hash, 1 ); Log3 $name, 5, "AMAD ($name) - AMAD_HTTP_POST: received http code ".$param->{code}; return; } if( ( $data =~ /Error/i ) and exists( $param->{code} ) ) { readingsBeginUpdate( $hash ); readingsBulkUpdate( $hash, "state", $param->{code} ) if( ReadingsVal( $name, "state", 0 ) ne "initialized" ); $hash->{helper}{setCmdErrorCounter} = ( $hash->{helper}{setCmdErrorCounter} + 1 ); readingsBulkUpdate( $hash, "lastSetCommandState", "cmd_error" ); if( $param->{code} eq 404 ) { readingsBulkUpdate( $hash, "lastSetCommandError", "setCommands flow is inactive on your device!" ); } else { readingsBulkUpdate( $hash, "lastSetCommandError", "http error ".$param->{code} ); } return; } ### End Error Handling readingsSingleUpdate( $hash, "lastSetCommandState", "cmd_done", 1 ); $hash->{helper}{setCmdErrorCounter} = 0; return undef; } sub AMAD_CommBridge_Open($) { my ( $hash ) = @_; my $name = $hash->{NAME}; # Oeffnen des TCP Sockets my $ret = TcpServer_Open( $hash, "8090", "global" ); if( $ret && !$init_done ) { Log3 $name, 3, "$ret. Exiting."; exit(1); } readingsSingleUpdate ( $hash, "state", "opened", 1 ); Log3 $name, 5, "Socket wird geöffnet."; return $ret; } sub AMAD_CommBridge_Read($) { my ( $hash ) = @_; my $name = $hash->{NAME}; my $brihash = $modules{AMAD}{defptr}{BRIDGE}; if( $hash->{SERVERSOCKET} ) { # Accept and create a child TcpServer_Accept( $hash, "AMAD" ); return; } # Read 1024 byte of data my $buf; my $ret = sysread($hash->{CD}, $buf, 1024); # When there is an error in connection return if( !defined($ret ) || $ret <= 0 ) { CommandDelete( undef, $hash->{NAME} ); return; } my $response = "header lines: \r\n AMADCommBridge receive Data complete\r\n FHEM will process\r\n now\r\n"; my $c = $hash->{CD}; print $c "HTTP/1.1 200 OK\r\n", "Content-Type: text/plain\r\n", "Content-Length: ".length($response)."\r\n\r\n", $response; ## hier den close Client einbauen auf hash vom Accept $chash siehe oben ## close($hash->{CD}) ### ## Consume Content ### my @data = split( '\R\R', $buf ); if ( $data[0] =~ /FHEMCMD: setreading\b/ ) { my $tv = $data[1]; @data = split( '\R', $data[0] ); $data[2] =~ s/FHEMDEVICE: //; my $chash = $defs{$data[2]}; ### Begin Response Processing my @valuestring = split( '@@@@', $tv ); my %buffer; foreach( @valuestring ) { my @values = split( '@@' , $_ ); $buffer{$values[0]} = $values[1]; } my $t; my $v; while( ( $t, $v ) = each %buffer ) { $v =~ s/null//g; readingsBeginUpdate( $chash ); readingsBulkUpdate( $chash, $t, $v ) if( defined( $v ) ); } readingsBulkUpdate( $chash, "lastStatusRequestState", "statusRequest_done" ); readingsEndUpdate( $chash, 1 ); ### End Response Processing return; } elsif ( $data[0] =~ /FHEMCMD: set\b/ ) { my $fhemCmd = $data[1]; fhem ("$fhemCmd") if( ReadingsVal( "AMADCommBridge", "expertMode", 0 ) eq "1" ); readingsSingleUpdate( $brihash, "receiveFhemCommand", $fhemCmd, 1 ); return; } elsif ( $data[0] =~ /FHEMCMD: statusrequest\b/ ) { @data = split( '\R', $data[0] ); $data[2] =~ s/FHEMDEVICE: //; my $chash = $defs{$data[2]}; return AMAD_GetUpdateLocal( $chash ); } } 1; =pod =begin html

AMAD

=end html =begin html_DE

AMAD

=end html_DE =cut