2017-12-26 21:17:50 +00:00
#################################################################
2017-12-23 16:16:19 +00:00
# $Id$
2017-12-26 21:17:50 +00:00
#################################################################
# physisches Modul - Verbindung zur Hardware
2017-12-23 16:16:19 +00:00
#
2018-02-08 21:17:55 +00:00
# note / ToDo´ s / Bugs:
2018-03-17 09:04:30 +00:00
# - Port Check ???
2018-04-13 13:48:07 +00:00
# - Sendeausgabe im LOG anpassen
#
#
2017-12-26 21:17:50 +00:00
#################################################################
2017-12-23 16:16:19 +00:00
package main ;
# Laden evtl. abhängiger Perl- bzw. FHEM-Module
use HttpUtils ; # um Daten via HTTP auszutauschen https://wiki.fhem.de/wiki/HttpUtils
use strict ;
use warnings ; # Warnings
2018-02-15 21:00:07 +00:00
use Net::Ping ;
2017-12-23 16:16:19 +00:00
2018-02-15 21:00:07 +00:00
my $ missingModul = "" ;
my $ xs1_ConnectionTry = 1 ; # disable Funktion sobald 10x keine Verbindung (Schutzabschaltung)
2018-03-17 09:04:30 +00:00
my $ xs1_id ;
2018-02-10 20:04:01 +00:00
2017-12-26 21:17:50 +00:00
eval "use Encode qw(encode encode_utf8 decode_utf8);1" or $ missingModul . = "Encode " ;
eval "use JSON;1" or $ missingModul . = "JSON " ;
2018-03-12 23:09:47 +00:00
eval "use Net::Ping;1" or $ missingModul . = "Net::Ping " ;
2017-12-26 21:17:50 +00:00
2018-02-05 20:02:07 +00:00
#$| = 1; #Puffern abschalten, Hilfreich für PEARL WARNINGS Search
2017-12-23 16:16:19 +00:00
sub xs1Bridge_Initialize ($) {
my ( $ hash ) = @ _ ;
$ hash - > { WriteFn } = "xs1Bridge_Write" ;
2018-02-05 20:02:07 +00:00
$ hash - > { Clients } = ":xs1Dev:" ;
$ hash - > { MatchList } = { "1:xs1Dev" = > '[x][s][1][D][e][v][#][A][k][t][o][r]#[0-6][0-9].*|[x][s][1][D][e][v][#][S][e][n][s][o][r]#[0-6][0-9].*' } ; ## https://regex101.com/ Testfunktion
2017-12-23 16:16:19 +00:00
$ hash - > { DefFn } = "xs1Bridge_Define" ;
$ hash - > { AttrFn } = "xs1Bridge_Attr" ;
2017-12-26 21:17:50 +00:00
$ hash - > { UndefFn } = "xs1Bridge_Undef" ;
2018-04-06 22:05:18 +00:00
$ hash - > { AttrList } = "debug:0,1,2 " .
"ignore:0,1 " .
"update_only_difference:0,1 " .
"view_Device_name:0,1 " .
"view_Device_function:0,1 " .
"xs1_blackl_aktor " .
"xs1_blackl_sensor " .
"xs1_control:0,1 " .
"xs1_interval:0,30,60,180,360 " ;
##$readingFnAttributes; ## die Standardattribute von FHEM
2017-12-23 16:16:19 +00:00
foreach my $ d ( sort keys % { $ modules { xs1Bridge } { defptr } } ) {
my $ hash = $ modules { xs1Bridge } { defptr } { $ d } ;
}
}
sub xs1Bridge_Define ($$) {
my ( $ hash , $ def ) = @ _ ;
my @ arg = split ( "[ \t][ \t]*" , $ def ) ;
my $ name = $ hash - > { NAME } ; ## Der Definitionsname, mit dem das Gerät angelegt wurde.
my $ typ = $ hash - > { TYPE } ; ## Der Modulname, mit welchem die Definition angelegt wurde.
my $ debug = AttrVal ( $ hash - > { NAME } , "debug" , 0 ) ;
2018-02-05 20:02:07 +00:00
my $ viewDeviceName = AttrVal ( $ hash - > { NAME } , "view_Device_name" , 0 ) ;
my $ viewDeviceFunction = AttrVal ( $ hash - > { NAME } , "view_Device_function" , 0 ) ;
my $ update_only_difference = AttrVal ( $ hash - > { NAME } , "update_only_difference" , 0 ) ;
2018-02-12 21:14:10 +00:00
2018-03-12 23:09:47 +00:00
# 0 1 2
return "Usage: define <NAME> $name <IP>" if ( @ arg != 3 ) ;
#return "Usage: define <NAME> $name <IP> <PORT>" if(@arg != 4);
2018-02-15 21:00:07 +00:00
return "Your IP is not valid. Please Check!" if not ( $ arg [ 2 ] =~ /[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}/s ) ;
2018-03-12 23:09:47 +00:00
#return "Your PORT is not valid. Please Check!" if not($arg[3] =~ /[0-9]{2,5}/s);
2017-12-26 21:17:50 +00:00
return "Cannot define xs1Bridge device. Perl modul ${missingModul}is missing." if ( $ missingModul ) ;
2018-02-12 21:14:10 +00:00
2018-03-01 19:50:59 +00:00
my $ xs1check = 0 ;
if ( ! defined $ modules { xs1Bridge } ) {
my $ p = Net::Ping - > new ( "tcp" , 2 ) ;
if ( ! ( $ p - > ping ( "$arg[2]" , 2 ) ) ) {
$ xs1check = 1 ;
}
$ p - > close ( ) ;
return "Your IP is not reachable. Please Check!" if ( $ xs1check == 1 ) ;
2018-02-15 21:00:07 +00:00
}
2018-02-15 21:04:57 +00:00
2017-12-23 16:16:19 +00:00
# Parameter Define
2018-02-15 21:00:07 +00:00
my $ xs1_ip = $ arg [ 2 ] ; ## Zusatzparameter 1 bei Define - ggf. nur in Sub
2017-12-23 16:16:19 +00:00
$ hash - > { xs1_ip } = $ xs1_ip ;
2018-04-01 17:51:09 +00:00
$ hash - > { STATE } = "Initialized" ; ## Der Status des Modules nach Initialisierung.
2018-02-15 21:00:07 +00:00
$ hash - > { TIME } = time ( ) ; ## Zeitstempel, derzeit vom anlegen des Moduls
2018-04-30 18:23:25 +00:00
$ hash - > { VERSION } = "1.26" ; ## Version
2018-02-15 21:00:07 +00:00
$ hash - > { BRIDGE } = 1 ;
# Attribut gesetzt
2018-03-17 09:04:30 +00:00
$ attr { $ name } { xs1_interval } = "60" if ( not defined ( $ attr { $ name } { xs1_interval } ) ) ;
2018-03-01 19:50:59 +00:00
$ attr { $ name } { room } = "xs1" if ( not defined ( $ attr { $ name } { room } ) ) ;
2018-04-13 13:48:07 +00:00
$ attr { $ name } { xs1_control } = "0" if ( not defined ( $ attr { $ name } { xs1_control } ) ) ;
2017-12-23 16:16:19 +00:00
2018-02-15 21:00:07 +00:00
$ modules { xs1Bridge } { defptr } { BRIDGE } = $ hash ;
2017-12-23 16:16:19 +00:00
2018-03-17 09:04:30 +00:00
InternalTimer ( gettimeofday ( ) + $ attr { $ name } { xs1_interval } , "xs1Bridge_GetUpDate" , $ hash ) ; ## set Timer
2017-12-23 16:16:19 +00:00
2018-03-17 09:04:30 +00:00
#Log3 $name, 3, "$typ: IODev defined with xs1_ip: $xs1_ip";
2018-02-10 20:04:01 +00:00
2018-04-13 13:48:07 +00:00
if ( ! defined ( $ defs { 'FileLog_xs1Bridge' } ) ) { ## Logfile existent check
2018-04-01 17:51:09 +00:00
Log3 $ name , 4 , "$typ: FileLog_xs1Bridge ist NICHT definiert" ;
2018-04-13 13:48:07 +00:00
fhem ( "define FileLog_xs1Bridge FileLog ./log/xs1Bridge-%Y-%m.log " . $ arg [ 0 ] ) ; ## Logfile define
fhem ( "attr FileLog_xs1Bridge room xs1" ) ; ## Logfile in xs1 room
2018-03-17 09:04:30 +00:00
} else {
2018-04-01 17:51:09 +00:00
Log3 $ name , 4 , "$typ: FileLog_xs1Bridge ist definiert" ;
2018-02-12 21:14:10 +00:00
}
2018-02-15 21:00:07 +00:00
return undef ;
2017-12-23 16:16:19 +00:00
}
sub xs1Bridge_Attr (@) {
my ( $ cmd , $ name , $ attrName , $ attrValue ) = @ _ ;
my $ hash = $ defs { $ name } ;
my $ typ = $ hash - > { TYPE } ;
my $ debug = AttrVal ( $ hash - > { NAME } , "debug" , 0 ) ;
2018-03-17 09:04:30 +00:00
my $ xs1_interval = 0 ;
2017-12-23 16:16:19 +00:00
2018-04-13 13:48:07 +00:00
my @ string_attrValue = split ( "," , $ attrValue ) if ( defined $ attrValue ) ; ## for Check Blacklist
my $ length = scalar @ string_attrValue ; ## for Check Blacklist
2018-04-06 22:05:18 +00:00
2017-12-23 16:16:19 +00:00
# $cmd - Vorgangsart - kann die Werte "del" (löschen) oder "set" (setzen) annehmen
# $name - Gerätename
# $attrName/$attrValue sind Attribut-Name und Attribut-Wert
2018-03-12 18:13:12 +00:00
#### Handling bei set .. attribute
if ( $ cmd eq "set" ) {
2018-04-13 13:48:07 +00:00
RemoveInternalTimer ( $ hash ) ; ## Timer löschen
2018-04-06 22:05:18 +00:00
Debug " $typ: Attr | Cmd:$cmd | RemoveInternalTimer" if ( $ debug == 2 ) ;
2018-04-13 13:48:07 +00:00
if ( $ attrName eq "xs1_interval" && $ attrValue == 0 ) { ## Handling xs1_interval == 0
2018-03-17 09:04:30 +00:00
RemoveInternalTimer ( $ hash ) ;
2017-12-23 16:16:19 +00:00
readingsSingleUpdate ( $ hash , "state" , "deactive" , 1 ) ;
2018-04-13 13:48:07 +00:00
} elsif ( $ attrName eq "xs1_interval" && $ attrValue >= 30 ) { ## Handling xs1_interval >= 30
2018-02-15 21:00:07 +00:00
$ xs1_ConnectionTry = 1 ;
2018-03-17 09:04:30 +00:00
my $ xs1_interval = $ attrValue ;
InternalTimer ( gettimeofday ( ) + $ xs1_interval , "xs1Bridge_GetUpDate" , $ hash ) ;
2017-12-23 16:16:19 +00:00
readingsSingleUpdate ( $ hash , "state" , "active" , 1 ) ;
2018-04-01 17:51:09 +00:00
### Ansicht xs1_Device_function ###
2018-02-05 20:02:07 +00:00
} elsif ( $ attrName eq "view_Device_function" ) {
2018-04-13 13:48:07 +00:00
if ( $ attrValue eq "1" ) { ## Handling view_Device_function 1
2018-04-30 18:23:25 +00:00
#Log3 $name, 3, "$typ: Attribut view_Device_function $cmd to $attrValue";
2018-02-05 20:02:07 +00:00
}
2018-04-13 13:48:07 +00:00
elsif ( $ attrValue eq "0" ) { ## Handling view_Device_function 0
2018-04-30 18:23:25 +00:00
#Log3 $name, 3, "$typ: Attribut view_Device_function $cmd to $attrValue";
2018-02-05 20:02:07 +00:00
}
2018-04-01 17:51:09 +00:00
### Ansicht xs1_Device_name ###
2018-02-05 20:02:07 +00:00
} elsif ( $ attrName eq "view_Device_name" ) {
2018-04-01 17:51:09 +00:00
if ( $ attrValue eq "1" ) { ## Handling view_Device_name 1
2018-04-30 18:23:25 +00:00
#Log3 $name, 3, "$typ: Attribut view_Device_name $cmd to $attrValue";
2018-02-05 20:02:07 +00:00
}
2018-04-01 17:51:09 +00:00
elsif ( $ attrValue eq "0" ) { ## Handling view_Device_name 0
2018-04-30 18:23:25 +00:00
#Log3 $name, 3, "$typ: Attribut view_Device_name $cmd to $attrValue";
2018-04-01 17:51:09 +00:00
for my $ i ( 0 .. 64 ) {
delete $ hash - > { READINGS } { "Aktor_" . sprintf ( "%02d" , $ i ) . "_name" } if ( $ hash - > { READINGS } ) ;
delete $ hash - > { READINGS } { "Sensor_" . sprintf ( "%02d" , $ i ) . "_name" } if ( $ hash - > { READINGS } ) ;
}
}
### Wertaenderung nur bei Difference ###
2018-02-05 20:02:07 +00:00
} elsif ( $ attrName eq "update_only_difference" ) {
2018-03-17 09:04:30 +00:00
if ( $ attrValue eq "1" ) { ## Handling update_only_difference 1
2018-04-30 18:23:25 +00:00
#Log3 $name, 3, "$typ: Attribut update_only_difference $cmd to $attrValue";
2018-02-05 20:02:07 +00:00
}
2018-03-17 09:04:30 +00:00
elsif ( $ attrValue eq "0" ) { ## Handling update_only_difference 0
2018-04-30 18:23:25 +00:00
#Log3 $name, 3, "$typ: Attribut update_only_difference $cmd to $attrValue";
2018-02-05 20:02:07 +00:00
for my $ i ( 0 .. 64 ) {
2018-04-01 17:51:09 +00:00
delete $ hash - > { READINGS } { "Aktor_" . sprintf ( "%02d" , $ i ) . "_name" } if ( $ hash - > { READINGS } ) ;
2018-02-05 20:02:07 +00:00
}
}
2018-04-01 17:51:09 +00:00
### xs1 - steuern ###
2018-03-01 19:50:59 +00:00
} elsif ( $ attrName eq "xs1_control" ) {
2018-03-17 09:04:30 +00:00
if ( $ attrValue eq "1" ) { ## Handling xs1_control 1
2018-03-01 19:50:59 +00:00
if ( ! $ modules { xs1Dev } ) { ## Check Modul vorhanden
$ attr { $ name } { xs1_control } = "0" ;
return "Module xs1Dev is non-existent or still under development. Please wait"
}
}
2018-04-01 17:51:09 +00:00
### Blacklist - Aktor / Sensor ###
2018-04-13 13:48:07 +00:00
} elsif ( $ attrName eq "xs1_blackl_aktor" ) { ## Handling xs1_blackl_aktor
2018-04-06 22:05:18 +00:00
for ( my $ x = 0 ; $ x < $ length ; $ x + + ) {
if ( $ string_attrValue [ $ x ] =~ /^[1-9]{1}\d*/ && $ string_attrValue [ $ x ] < 65 ) {
## RICHTIG ##
} else {
return "The comma separated value must only 1 to 64" ;
}
2018-04-05 18:29:17 +00:00
}
Log3 $ name , 4 , "$typ: Attribut xs1_blackl_aktor $attrValue" ;
2018-04-06 22:05:18 +00:00
2018-04-13 13:48:07 +00:00
} elsif ( $ attrName eq "xs1_blackl_sensor" ) { ## Handling xs1_blackl_sensor
2018-04-06 22:05:18 +00:00
for ( my $ x = 0 ; $ x < $ length ; $ x + + ) {
if ( $ string_attrValue [ $ x ] =~ /^[1-9]{1}\d*/ && $ string_attrValue [ $ x ] < 65 ) {
## RICHTIG ##
} else {
return "The comma separated value must only 1 to 64" ;
}
2018-04-05 18:29:17 +00:00
}
2018-04-01 17:51:09 +00:00
Log3 $ name , 4 , "$typ: Attribut xs1_blackl_sensor $attrValue" ;
2017-12-23 16:16:19 +00:00
}
}
2018-03-12 18:13:12 +00:00
#### Handling bei del ... attribute
if ( $ cmd eq "del" ) {
2018-04-13 13:48:07 +00:00
if ( $ attrName eq "xs1_interval" ) { ## Handling deleteattr xs1_interval
2018-03-17 09:04:30 +00:00
RemoveInternalTimer ( $ hash ) ;
readingsSingleUpdate ( $ hash , "state" , "deactive" , 1 ) ;
2018-04-06 22:05:18 +00:00
Debug " $typ: Attr | Cmd:$cmd | $attrName" if ( $ debug == 2 ) ;
2018-02-05 20:02:07 +00:00
}
2018-04-13 13:48:07 +00:00
elsif ( $ attrName eq "view_Device_function" ) { ## Handling deleteattr view_Device_function
2018-02-05 20:02:07 +00:00
Log3 $ name , 3 , "$typ: Attribut view_Device_function delete" ;
for my $ i ( 0 .. 64 ) {
for my $ i2 ( 1 .. 4 ) {
delete $ hash - > { READINGS } { "Aktor_" . sprintf ( "%02d" , $ i ) . "_function_" . $ i2 } if ( $ hash - > { READINGS } ) ;
}
}
}
2018-04-13 13:48:07 +00:00
elsif ( $ attrName eq "view_Device_name" ) { ## Handling deleteattr view_Device_name
2018-02-05 20:02:07 +00:00
Log3 $ name , 3 , "$typ: Attribut view_Device_name delete" ;
for my $ i ( 0 .. 64 ) {
delete $ hash - > { READINGS } { "Aktor_" . sprintf ( "%02d" , $ i ) . "_name" } if ( $ hash - > { READINGS } ) ;
delete $ hash - > { READINGS } { "Sensor_" . sprintf ( "%02d" , $ i ) . "_name" } if ( $ hash - > { READINGS } ) ;
}
}
elsif ( $ attrName eq "update_only_difference" ) {
Log3 $ name , 3 , "$typ: Attribut update_only_difference delete" ;
2017-12-23 16:16:19 +00:00
}
}
2018-04-01 17:51:09 +00:00
#### Handling bei state active
2017-12-23 16:16:19 +00:00
if ( $ hash - > { STATE } eq "active" ) {
RemoveInternalTimer ( $ hash ) ;
2018-03-17 09:04:30 +00:00
InternalTimer ( gettimeofday ( ) + $ xs1_interval , "xs1Bridge_GetUpDate" , $ hash ) ;
2018-04-06 22:05:18 +00:00
Debug " $typ: Attr | RemoveInternalTimer + InternalTimer" if ( $ debug == 2 ) ;
2018-03-12 18:13:12 +00:00
}
2017-12-23 16:16:19 +00:00
return undef ;
}
sub xs1Bridge_GetUpDate () {
my ( $ hash ) = @ _ ;
my $ name = $ hash - > { NAME } ;
my $ typ = $ hash - > { TYPE } ;
my $ state = $ hash - > { STATE } ;
2018-02-15 21:00:07 +00:00
my $ xs1_ip = $ hash - > { xs1_ip } ;
2018-02-10 20:04:01 +00:00
my $ xs1_uptimeStart = $ hash - > { helper } { xs1_uptimeStart } ;
my $ xs1_uptimeOld = $ hash - > { helper } { xs1_uptimeOld } ;
my $ xs1_uptimeNew = $ hash - > { helper } { xs1_uptimeNew } ;
2017-12-23 16:16:19 +00:00
my $ def ;
2017-12-30 12:39:56 +00:00
#http://x.x.x.x/control?callback=cname&cmd=...
2018-02-10 20:04:01 +00:00
#get_list_actuators - list all actuators i0
#get_list_sensors - list all sensors i1
2018-04-06 22:05:18 +00:00
#get_list_timers - list all timers i3
#get_config_info - list all device info´ s i2
2017-12-23 16:16:19 +00:00
#get_protocol_info - list protocol info´ s
my $ cmd = "/control?callback=cname&cmd=" ;
my @ cmdtyp = ( "get_list_actuators" , "get_list_sensors" , "get_config_info" , "get_list_timers" , "get_list_actuators" ) ;
my @ arrayname = ( "actuator" , "sensor" , "info" , "timer" , "function" ) ;
my @ readingsname = ( "Aktor" , "Sensor" , "" , "Timer" , "" ) ;
my $ debug = AttrVal ( $ hash - > { NAME } , "debug" , 0 ) ;
2018-03-17 09:04:30 +00:00
my $ xs1_interval = AttrVal ( $ name , "xs1_interval" , 60 ) ;
2018-02-05 20:02:07 +00:00
my $ viewDeviceName = AttrVal ( $ hash - > { NAME } , "view_Device_name" , 0 ) ;
my $ viewDeviceFunction = AttrVal ( $ hash - > { NAME } , "view_Device_function" , 0 ) ;
my $ update_only_difference = AttrVal ( $ hash - > { NAME } , "update_only_difference" , 0 ) ;
2018-03-01 19:50:59 +00:00
my $ xs1_control = AttrVal ( $ hash - > { NAME } , "xs1_control" , 0 ) ;
2018-03-17 09:04:30 +00:00
my $ xs1_blackl_aktor = AttrVal ( $ hash - > { NAME } , "xs1_blackl_aktor" , 0 ) ;
my $ xs1_blackl_sensor = AttrVal ( $ hash - > { NAME } , "xs1_blackl_sensor" , 0 ) ;
2018-03-01 19:50:59 +00:00
2018-03-17 09:04:30 +00:00
#### xs1Bridge xs1_interval >= 10 -> aktiviert zum auslesen
if ( $ xs1_interval >= 10 && $ xs1_ConnectionTry <= 5 ) {
2018-02-10 20:04:01 +00:00
RemoveInternalTimer ( $ hash ) ; ## Timer löschen
2018-03-17 09:04:30 +00:00
InternalTimer ( gettimeofday ( ) + $ xs1_interval , "xs1Bridge_GetUpDate" , $ hash ) ;
2018-04-06 22:05:18 +00:00
Debug " -------------- ERROR CHECK - START --------------" if ( $ debug == 2 || $ debug == 1 ) ;
Debug " $typ: GetUpDate | RemoveInternalTimer + InternalTimer" if ( $ debug == 2 ) ;
2017-12-23 16:16:19 +00:00
#Log3 $name, 3, "$typ: xs1Bridge_GetUpDate | RemoveInternalTimer + InternalTimer";
if ( $ state eq "Initialized" ) {
2018-02-06 19:25:16 +00:00
readingsSingleUpdate ( $ hash , "state" , "active" , 1 ) ;
2017-12-23 16:16:19 +00:00
}
2018-02-05 20:02:07 +00:00
my $ xs1Dev_check = "ERROR" ;
2017-12-30 12:39:56 +00:00
2018-02-05 20:02:07 +00:00
#if($modules{xs1Dev} && $modules{xs1Dev}{LOADED}) { ## Check Modul vorhanden + geladen
if ( $ modules { xs1Dev } ) { ## Check Modul vorhanden
$ xs1Dev_check = "ok" ;
2018-04-06 22:05:18 +00:00
Debug " $typ: GetUpDate | Modul xs1Dev_check = $xs1Dev_check" if ( $ debug == 2 ) ;
2017-12-30 12:39:56 +00:00
} else {
2018-04-06 22:05:18 +00:00
Debug " $typ: GetUpDate ERROR | Modul xs1Dev not existent! Please check it to be available!" if ( $ debug == 2 ) ;
2018-02-05 20:02:07 +00:00
#Log3 $name, 3, "$typ: GetUpDate | xs1Dev_check = $xs1Dev_check";
2017-12-30 12:39:56 +00:00
}
2018-03-12 18:13:12 +00:00
#### JSON Abfrage - Schleife
2018-02-05 20:02:07 +00:00
for my $ i ( 0 .. 3 ) {
2018-03-12 18:13:12 +00:00
#### HTTP Requests #### Start ####
2018-02-15 21:00:07 +00:00
my $ connection ;
my $ Http_err = "" ;
my $ Http_data = "" ;
my $ param = {
url = > "http://" . $ xs1_ip . $ cmd . $ cmdtyp [ $ i ] ,
timeout = > 3 ,
method = > "GET" , # Lesen von Inhalten
} ;
2018-04-06 22:05:18 +00:00
#HttpUtils_BlockingGet($param);
2018-02-15 21:00:07 +00:00
( $ Http_err , $ Http_data ) = HttpUtils_BlockingGet ( $ param ) ;
2018-03-12 18:13:12 +00:00
#### HTTP Requests #### END ####
2018-02-15 21:00:07 +00:00
my $ adress = "http://" . $ xs1_ip . $ cmd . $ cmdtyp [ $ i ] ;
2018-02-12 21:14:10 +00:00
my $ json ;
my $ json_utf8 ;
my $ decoded ;
2018-04-06 22:05:18 +00:00
Debug " $typ: GetUpDate | Adresse: $adress | xs1_ConnectionTry=$xs1_ConnectionTry" if ( $ debug == 1 && $ Http_err eq "" ) ;
Debug " $typ: GetUpDate | HTTP request: " . $ Http_err . "| xs1_ConnectionTry=$xs1_ConnectionTry" if ( $ debug == 1 && $ Http_err ne "" ) ;
2018-02-12 21:14:10 +00:00
2018-03-12 18:13:12 +00:00
#### HTTP Requests, ERROR
if ( $ Http_err ne "" ) {
2018-02-15 21:00:07 +00:00
# ERROR Message
# http://192.168.2.5/control?callback=cname&cmd=get_list_actuators: Can't connect(1) to http://192.168.2.5:80: IO::Socket::INET: connect: No route to host
# http://192.168.2.5/control?callback=cname&cmd=get_config_info: empty answer received
2018-03-01 19:50:59 +00:00
# http://192.168.2.5/control?callback=cname&cmd=get_config_info: Select timeout/error:
2018-02-15 21:00:07 +00:00
2018-03-01 19:50:59 +00:00
#($Http_err) = $Http_err =~ /[:]\s.*/g;
Log3 $ name , 3 , "$typ: GetUpDate | Try=$xs1_ConnectionTry loop=$i | Error: " . $ Http_err ;
2018-02-15 21:00:07 +00:00
$ xs1_ConnectionTry + + ;
last ; ## Abbruch Schleife
2018-03-12 18:13:12 +00:00
}
#### HTTP Requests, OK dann ARRAY Verarbeitung
elsif ( $ Http_data ne "" ) {
2018-02-15 21:00:07 +00:00
( $ json ) = $ Http_data =~ /[^(]*[}]/g ; ## cut cname( + ) am Ende von Ausgabe -> ARRAY Struktur als Antwort vom xs1
2018-02-08 21:17:55 +00:00
$ json_utf8 = eval { encode_utf8 ( $ json ) } ; ## UTF-8 character Bearbeitung, da xs1 TempSensoren ERROR
2018-02-15 21:00:07 +00:00
$ decoded = eval { decode_json ( $ json_utf8 ) } ;
$ xs1_ConnectionTry = 1 ;
2018-03-12 18:13:12 +00:00
#### xs1 Aktoren / Sensoren als Readings
if ( $ i <= 1 ) {
2018-02-15 21:00:07 +00:00
my $ xs1_data ;
my @ array ;
if ( defined $ decoded - > { $ arrayname [ $ i ] } ) {
@ array = @ { $ decoded - > { $ arrayname [ $ i ] } } ;
} else {
Log3 $ name , 3 , "$typ: GetUpDate | ARRAY-ERROR xs1 -> no Data in loop $i" ;
last ;
}
2018-03-12 18:13:12 +00:00
2018-03-05 19:20:16 +00:00
my $ i3 = 0 ; ## Counter für real Werte in xs1, da sonst Verschiebungen wenn User ID´ s verschiebt, NOTWENDIG!
2018-02-15 21:00:07 +00:00
foreach my $ f ( @ array ) {
2018-03-05 19:20:16 +00:00
$ i3 + + ;
2018-04-05 18:29:17 +00:00
$ xs1_id = $ i3 ;
2018-03-17 09:04:30 +00:00
#### Test ob Aktoren / Sensoren auf xs1_blackl
if ( $ f - > { "type" } ne "disabled" && is_in_array ( $ hash , $ xs1_id , $ i ) == 0 ) {
2018-02-15 21:00:07 +00:00
my $ xs1Dev = "xs1Dev" ;
2018-03-12 18:13:12 +00:00
#### Aktoren spezifisch
2018-02-15 21:00:07 +00:00
my $ xs1_function1 = "-" ;
my $ xs1_function2 = "-" ;
my $ xs1_function3 = "-" ;
my $ xs1_function4 = "-" ;
if ( $ i == 0 ) {
2018-03-12 18:13:12 +00:00
#### xs1 Aktoren nur update bei differenten Wert
2018-02-15 21:00:07 +00:00
if ( $ update_only_difference == 1 ) {
2018-03-05 19:20:16 +00:00
my $ oldState = ReadingsVal ( $ name , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) , "unknown" ) ; ## Readings Wert
2018-02-15 21:00:07 +00:00
my $ newState = sprintf ( "%.1f" , $ f - > { "value" } ) ; ## ARRAY Wert xs1 aktuell
2018-03-12 18:13:12 +00:00
2018-04-06 22:05:18 +00:00
Debug " $typ: " . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . " oldState=$oldState newState=$newState" if ( $ debug == 2 ) ;
2018-02-05 20:02:07 +00:00
2018-02-15 21:00:07 +00:00
if ( $ oldState ne $ newState ) {
2018-03-05 19:20:16 +00:00
readingsSingleUpdate ( $ hash , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) , $ newState , 0 ) ;
2018-02-15 21:00:07 +00:00
}
2018-02-05 20:02:07 +00:00
}
2018-03-12 18:13:12 +00:00
#### xs1 Aktoren / Funktion != disable
2018-03-05 19:20:16 +00:00
my @ array2 = @ { $ decoded - > { 'actuator' } - > [ $ i3 - 1 ] - > { $ arrayname [ 4 ] } } ;
2018-03-12 18:13:12 +00:00
my $ i2 = 0 ; ## Funktionscounter
2018-02-15 21:00:07 +00:00
foreach my $ f2 ( @ array2 ) {
2018-03-05 19:20:16 +00:00
$ i2 + + ;
2018-02-15 21:00:07 +00:00
2018-03-12 18:13:12 +00:00
#### xs1 Option - Ansicht Funktionsname
2018-02-15 21:00:07 +00:00
if ( $ viewDeviceFunction == 1 ) {
2018-03-05 19:20:16 +00:00
my $ oldState = ReadingsVal ( $ name , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . "_" . $ arrayname [ 4 ] . "_" . $ i2 , "unknown" ) ; ## Readings Wert
2018-02-15 21:00:07 +00:00
my $ newState = $ f2 - > { 'type' } ; ## ARRAY Wert xs1 aktuell
2018-03-05 19:20:16 +00:00
if ( $ oldState ne "unknown" && $ newState eq "disabled" ) { ## FunktionReading del bei disable
2018-04-06 22:05:18 +00:00
Debug " $typ: " . "Aktor_" . sprintf ( "%02d" , $ i3 ) . "_function_" . $ i2 . " are disabled" if ( $ debug == 2 ) ;
2018-03-05 19:20:16 +00:00
delete $ hash - > { READINGS } { "Aktor_" . sprintf ( "%02d" , $ i3 ) . "_function_" . $ i2 } if ( $ hash - > { READINGS } ) ;
}
2018-02-15 21:00:07 +00:00
if ( $ f2 - > { "type" } ne "disabled" ) { ## Funktion != function -> type disable
if ( $ oldState ne $ newState ) {
2018-03-05 19:20:16 +00:00
readingsSingleUpdate ( $ hash , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . "_" . $ arrayname [ 4 ] . "_" . $ i2 , $ f2 - > { "type" } , 1 ) ;
2018-02-15 21:00:07 +00:00
}
2018-02-05 20:02:07 +00:00
}
2018-03-05 19:20:16 +00:00
}
2018-02-15 21:00:07 +00:00
2018-03-12 18:13:12 +00:00
#### Funktion != function -> type disable
if ( $ f2 - > { "type" } ne "disabled" ) {
2018-03-05 19:20:16 +00:00
if ( $ i2 == 1 ) {
2018-02-15 21:00:07 +00:00
$ xs1_function1 = $ f2 - > { "type" } ;
2018-03-05 19:20:16 +00:00
} elsif ( $ i2 == 2 ) {
2018-02-15 21:00:07 +00:00
$ xs1_function2 = $ f2 - > { "type" } ;
2018-03-05 19:20:16 +00:00
} elsif ( $ i2 == 3 ) {
2018-02-15 21:00:07 +00:00
$ xs1_function3 = $ f2 - > { "type" } ;
2018-03-05 19:20:16 +00:00
} elsif ( $ i2 == 4 ) {
2018-02-15 21:00:07 +00:00
$ xs1_function4 = $ f2 - > { "type" } ;
2018-02-05 20:02:07 +00:00
}
}
}
2017-12-30 12:39:56 +00:00
}
2018-03-12 18:13:12 +00:00
#### Value der Aktoren | Sensoren
2018-02-15 21:00:07 +00:00
if ( $ i == 1 || $ i == 0 && $ update_only_difference == 0 ) { # Aktoren | Sensoren im intervall - Format 0.0 bzw. 37.0 wie aus xs1
2018-03-05 19:20:16 +00:00
readingsSingleUpdate ( $ hash , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) , sprintf ( "%.1f" , $ f - > { "value" } ) , 0 ) ;
$ xs1_data = $ xs1Dev . "#" . $ readingsname [ $ i ] . "#" . sprintf ( "%02d" , $ i3 ) . "#" . $ f - > { "type" } . "#" . sprintf ( "%.1f" , $ f - > { "value" } ) . "#" . "$xs1_function1" . "#" . "$xs1_function2" . "#" . "$xs1_function3" . "#" . "$xs1_function4" . "#" . $ f - > { "name" } ;
2018-02-15 21:00:07 +00:00
} elsif ( $ i == 0 && $ update_only_difference == 1 ) { # Aktoren | nur bei DIFF - Format 0.0 bzw. 37.0 wie aus xs1
2018-03-05 19:20:16 +00:00
$ xs1_data = $ xs1Dev . "#" . $ readingsname [ $ i ] . "#" . sprintf ( "%02d" , $ i3 ) . "#" . $ f - > { "type" } . "#" . sprintf ( "%.1f" , $ f - > { "value" } ) . "#" . "$xs1_function1" . "#" . "$xs1_function2" . "#" . "$xs1_function3" . "#" . "$xs1_function4" . "#" . $ f - > { "name" } ;
2018-02-15 21:00:07 +00:00
}
2018-03-12 18:13:12 +00:00
#### Ausgaben je Typ unterschiedlich !!!
2018-04-06 22:05:18 +00:00
Debug " $typ: " . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . " | " . $ f - > { "type" } . " | " . $ f - > { "name" } . " | " . $ f - > { "value" } . " | " . "F1 $xs1_function1 | F2 $xs1_function2 | F3 $xs1_function3 | F4 $xs1_function4" if ( $ debug == 2 && $ i == 0 ) ;
Debug " $typ: " . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . " | " . $ f - > { "type" } . " | " . $ f - > { "name" } . " | " . $ f - > { "value" } if ( $ debug == 2 && $ i != 0 ) ;
2018-02-05 20:02:07 +00:00
2018-03-12 18:13:12 +00:00
### Ansicht Namen der Aktoren | Sensoren als Readings
2018-02-15 21:00:07 +00:00
if ( $ viewDeviceName == 1 ) {
2018-03-12 18:13:12 +00:00
my $ oldState = ReadingsVal ( $ name , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . "_name" , "unknown" ) ; ## Readings Wert
my $ newState = $ f - > { "name" } ; ## ARRAY Wert xs1 aktuell
if ( $ oldState ne $ newState ) { ## Namen nur bei Änderung schreiben
#Log3 $name, 3, "$typ: GetUpDate | newState=$newState ne oldState=$oldState";
readingsSingleUpdate ( $ hash , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . "_name" , $ f - > { "name" } , 1 ) ;
}
2018-02-15 21:00:07 +00:00
}
2018-02-05 20:02:07 +00:00
2018-02-15 21:00:07 +00:00
### Dispatch an xs1Device Modul
2018-03-01 19:50:59 +00:00
if ( $ xs1Dev_check eq "ok" && $ xs1_control == 1 ) {
2018-04-06 22:05:18 +00:00
Debug " $typ: GetUpDate | Dispatch: $xs1_data" if ( $ debug == 2 ) ;
2018-02-15 21:00:07 +00:00
Dispatch ( $ hash , $ xs1_data , undef ) if ( $ xs1_data ) ;
}
2018-03-05 19:20:16 +00:00
} else {
2018-03-12 18:13:12 +00:00
#### ID bzw. Speicherplatz xs1 ist disabled | Reading are delete
2018-03-05 19:20:16 +00:00
delete $ hash - > { READINGS } { $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) } if ( $ hash - > { READINGS } ) ;
delete $ hash - > { READINGS } { $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . "_name" } if ( $ hash - > { READINGS } ) ;
2018-04-01 17:51:09 +00:00
### Erweiterung v1.20 ### Device | Logfile | SVG löschen wenn in xs1 disable - TEST
my $ delDevice = "xs1Dev_" . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) ;
if ( defined ( $ defs { "xs1Dev_" . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) } ) ) {
#Log3 $name, 3, "$typ: GetUpDate | for delete $delDevice";
fhem ( "delete " . $ delDevice ) ; ## delete Device
}
if ( defined ( $ defs { "SVG_xs1Dev_" . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) } ) ) {
#Log3 $name, 3, "$typ: GetUpDate | for delete FileLog_$delDevice";
fhem ( "delete SVG_" . $ delDevice ) ; ## delete FileLog_Device
}
if ( defined ( $ defs { "FileLog_xs1Dev_" . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) } ) ) {
#Log3 $name, 3, "$typ: GetUpDate | for delete FileLog_$delDevice";
fhem ( "delete FileLog_" . $ delDevice ) ; ## delete FileLog_Device
}
### Erweiterung v1.20 ### Device | Logfile | SVG löschen wenn in xs1 disable - TEST ### ENDE ###
2018-03-05 19:20:16 +00:00
if ( $ i == 0 ) {
for my $ count ( 1 .. 4 ) {
delete $ hash - > { READINGS } { $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ i3 ) . "_function_" . $ count } if ( $ hash - > { READINGS } ) ;
}
}
2017-12-30 12:39:56 +00:00
}
2017-12-26 21:17:50 +00:00
}
2018-03-12 18:13:12 +00:00
}
#### xs1 Info´ s nur bei uptime Änderung als Readings
elsif ( $ i == 2 ) {
2018-02-15 21:00:07 +00:00
my $ features ;
my $ features_i = 0 ;
my @ xs1_readings = ( "xs1_start" , "xs1_devicename" , "xs1_bootloader" , "xs1_hardware" , "xs1_features" , "xs1_firmware" , "xs1_mac" , "xs1_dhcp" ) ;
my @ xs1_decoded = ( FmtDateTime ( time ( ) - ( $ decoded - > { 'info' } { 'uptime' } ) ) , $ decoded - > { 'info' } { 'devicename' } , $ decoded - > { 'info' } { 'bootloader' } , $ decoded - > { 'info' } { 'hardware' } , $ features , $ decoded - > { 'info' } { 'firmware' } , $ decoded - > { 'info' } { 'mac' } , $ decoded - > { 'info' } { 'autoip' } ) ;
2017-12-30 12:39:56 +00:00
2018-02-15 21:00:07 +00:00
my $ oldState = ReadingsVal ( $ name , $ xs1_readings [ 0 ] , "2000-01-01 03:33:33" ) ; ## Readings Wert
my @ oldstate = split ( /[-,:,\s\/]/ , $ oldState ) ; ## Split $year, $month, $mday, $hour, $min, $sec
$ oldState = fhemTimeGm ( $ oldstate [ 5 ] , $ oldstate [ 4 ] , $ oldstate [ 3 ] , $ oldstate [ 2 ] , $ oldstate [ 1 ] - 1 , $ oldstate [ 0 ] - 1900 ) ; ## Verarbeitung $sec, $min, $hour, $mday, $month-1, $year-1900
2018-02-10 20:04:01 +00:00
2018-02-15 21:00:07 +00:00
my $ newState = FmtDateTime ( time ( ) - ( $ decoded - > { 'info' } { 'uptime' } ) ) ; ## ARRAY uptime Wert xs1 aktuell
my @ newState = split ( /[-,:,\s\/]/ , $ newState ) ; ## Split $year, $month, $mday, $hour, $min, $sec
$ newState = fhemTimeGm ( $ newState [ 5 ] , $ newState [ 4 ] , $ newState [ 3 ] , $ newState [ 2 ] , $ newState [ 1 ] - 1 , $ newState [ 0 ] - 1900 ) ; ## Verarbeitung $sec, $min, $hour, $mday, $month-1, $year-1900
2018-02-10 20:04:01 +00:00
2018-03-12 18:13:12 +00:00
#### Vergleich mit 5 Sekunden Tolleranz je Verarbeitungszeit Netzwerk | DLAN | CPU
2018-04-06 22:05:18 +00:00
if ( abs ( $ oldState - $ newState ) > 5 ) {
2018-02-15 21:00:07 +00:00
readingsBeginUpdate ( $ hash ) ;
for my $ i2 ( 0 .. 7 ) {
if ( $ i2 == 4 ) {
2018-02-10 20:04:01 +00:00
while ( defined $ decoded - > { 'info' } { 'features' } - > [ $ features_i ] ) {
2018-02-15 21:00:07 +00:00
$ features . = $ decoded - > { 'info' } { 'features' } - > [ $ features_i ] . " " ;
$ features_i + + ;
}
$ xs1_decoded [ 4 ] = $ features ; ## ARRAY Wert xs1_decoded wird definiert
}
if ( defined $ xs1_decoded [ $ i2 ] ) {
readingsBulkUpdate ( $ hash , $ xs1_readings [ $ i2 ] , $ xs1_decoded [ $ i2 ] ) ;
2018-04-06 22:05:18 +00:00
Debug " $typ: " . $ xs1_readings [ $ i2 ] . ": " . $ xs1_decoded [ $ i2 ] if ( $ debug == 2 ) ;
2018-02-15 21:00:07 +00:00
} else {
Log3 $ name , 3 , "$typ: GetUpDate | ARRAY-ERROR xs1 -> no Data in loop $i|$i2" ;
last ;
2018-02-10 20:04:01 +00:00
}
}
2018-02-15 21:00:07 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
2017-12-30 12:39:56 +00:00
}
2018-03-12 18:13:12 +00:00
}
#### xs1 Timers als Readings
elsif ( $ i == 3 ) {
2018-02-15 21:00:07 +00:00
my @ array = @ { $ decoded - > { $ arrayname [ $ i ] } } ;
foreach my $ f ( @ array ) {
my $ oldState = ReadingsVal ( $ name , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ f - > { "id" } ) , "unknown" ) ; ## Readings Wert
my $ newState = FmtDateTime ( $ f - > { "next" } ) ; ## ARRAY Wert xs1 aktuell
2017-12-30 12:39:56 +00:00
2018-02-15 21:00:07 +00:00
if ( $ f - > { "type" } ne "disabled" ) {
if ( $ oldState ne $ newState ) { ## Update Reading nur bei Wertänderung
readingsSingleUpdate ( $ hash , $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ f - > { "id" } ) , FmtDateTime ( $ f - > { "next" } ) , 1 ) ;
}
2018-04-06 22:05:18 +00:00
Debug " $typ: " . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ f - > { "id" } ) . " | " . $ f - > { "name" } . " | " . $ f - > { "type" } . " | " . $ f - > { "next" } if ( $ debug == 2 ) ;
2018-02-15 21:00:07 +00:00
} elsif ( $ oldState ne "unknown" ) { ## deaktive Timer mit Wert werden als Reading entfernt
Log3 $ name , 3 , "$typ: GetUpDate | " . $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ f - > { "id" } ) . " is deactive in xs1" ;
delete $ defs { $ name } { READINGS } { $ readingsname [ $ i ] . "_" . sprintf ( "%02d" , $ f - > { "id" } ) } ;
2017-12-30 12:39:56 +00:00
}
}
2017-12-23 16:16:19 +00:00
}
2018-02-05 20:02:07 +00:00
2018-04-06 22:05:18 +00:00
if ( $ i < 2 ) {
Debug " --------------- ERROR CHECK - SUB --------------- " if ( $ debug == 2 ) ;
2018-02-15 21:00:07 +00:00
}
### Schleifen Ende ###
2017-12-23 16:16:19 +00:00
}
}
2018-02-15 21:00:07 +00:00
2018-04-06 22:05:18 +00:00
Debug " ------------- ERROR CHECK - ALL END -------------\n " if ( $ debug == 2 || $ debug == 1 ) ;
2017-12-23 16:16:19 +00:00
}
2018-02-10 20:04:01 +00:00
2018-03-17 09:04:30 +00:00
if ( $ xs1_ConnectionTry == 6 ) { ## Abschaltung xs1 nach 5 Verbindungsversuchen
$ attr { $ name } { xs1_interval } = "0" ;
2018-02-10 20:04:01 +00:00
readingsSingleUpdate ( $ hash , "state" , "deactive" , 1 ) ;
RemoveInternalTimer ( $ hash ) ; ## Timer löschen
2018-03-17 09:04:30 +00:00
Log3 $ name , 3 , "$typ: GetUpDate | connection ERROR -> xs1 set to disable! Device not reachable after 5 attempts" ;
2018-02-10 20:04:01 +00:00
}
2017-12-23 16:16:19 +00:00
}
2018-02-15 21:00:07 +00:00
sub xs1Bridge_Write ($) # # Zustellen von Daten via IOWrite () vom logischen zum physischen Modul
2017-12-23 16:16:19 +00:00
{
2018-03-01 19:50:59 +00:00
my ( $ hash , $ Aktor_ID , $ xs1_typ , $ cmd , $ cmd2 ) = @ _ ;
2017-12-23 16:16:19 +00:00
my $ name = $ hash - > { NAME } ;
my $ typ = $ hash - > { TYPE } ;
2018-02-05 20:02:07 +00:00
my $ xs1_ip = $ hash - > { xs1_ip } ;
2018-04-06 22:05:18 +00:00
my $ debug = AttrVal ( $ hash - > { NAME } , "debug" , 0 ) ;
2017-12-23 16:16:19 +00:00
2018-04-01 17:51:09 +00:00
## Anfrage (Client -> XS1): http://192.168.1.242/control?callback=cname&cmd=set_state_actuator&number=1&value=100
2018-03-12 18:13:12 +00:00
## Aktor Typen aus xs1: (notwendig zur Verarbeitung)
## -------------------------------------------------
## blind - Jalousie | dimmer - Dimmer | door - Tür | disabled - deaktivert
2018-04-01 17:51:09 +00:00
## switch - Schalter | shutter - Rolladen | sound - Ton | sun-blind - Markise
## temperature - Temperatur | timerswitch - Zeitschalter | window - Fenster
2018-03-12 18:13:12 +00:00
## Sensor Typen (Auswahl) aus xs1: (nur Info)
## ------------------------------------------
2018-04-01 17:51:09 +00:00
## alarmmat - Alarmmatte | disabled - deaktivert
2018-03-12 18:13:12 +00:00
## gas_butan - Gasmelder Butan | gas_peak - Gas Spitzenwert
2018-04-01 17:51:09 +00:00
## mail - Briefmelder | motion - Bewegung
## other - Andere | presence - Anwesenheit
2018-03-12 18:13:12 +00:00
## pwr_consump - Energiezähler | pwr_peak - Energie Spitzenwert
## soilmoisture - Bodenfeuchte | soiltemp - Bodentemperatur
2018-04-01 17:51:09 +00:00
## leafwetness - Blattfeuchte | remotecontrol - Fernbedienung
2018-03-12 18:13:12 +00:00
## windowopen - Fenstermelder ...
2018-02-05 20:02:07 +00:00
$ Aktor_ID = substr ( $ Aktor_ID , 1 , 2 ) ;
2018-03-01 19:50:59 +00:00
my $ xs1cmd ;
2018-03-12 18:13:12 +00:00
#### xs1 Typ switch || shutter || timerswitch - Anpassung Sendebefehl
if ( $ xs1_typ eq "switch" || $ xs1_typ eq "shutter" || $ xs1_typ eq "timerswitch" ) {
2018-03-01 19:50:59 +00:00
$ xs1cmd = "http://$xs1_ip/control?callback=cname&cmd=set_state_actuator&number=$Aktor_ID&$cmd2" ;
} elsif ( $ xs1_typ eq "dimmer" ) {
2018-02-05 20:02:07 +00:00
if ( $ cmd eq "off" ) {
2018-02-08 21:17:55 +00:00
$ cmd = 0 ;
2018-02-05 20:02:07 +00:00
}
2018-04-13 13:48:07 +00:00
$ xs1cmd = "http://$xs1_ip/control?callback=cname&cmd=set_state_actuator&number=$Aktor_ID&$cmd2" if ( $ cmd2 =~ /[f][u][n][c][t][i][o][n][=]./ ) ;
my $ valuenew = substr ( $ cmd2 , 3 , length ( $ cmd2 ) - 3 ) if ( $ cmd2 !~ /[f][u][n][c][t][i][o][n][=]./ ) ;
#Log3 $name, 3, "$typ: Write | Check cmd=$cmd cmd2=$cmd2 valuenew=$valuenew";
$ xs1cmd = "http://$xs1_ip/control?callback=cname&cmd=set_state_actuator&number=$Aktor_ID&value=$valuenew" if ( $ cmd2 !~ /[f][u][n][c][t][i][o][n][=]./ ) ;
2018-03-05 19:20:16 +00:00
} else {
2018-04-01 17:51:09 +00:00
#### keine Verarbeitung zum senden ####
Log3 $ name , 3 , "$typ: Write | $xs1_typ not control xs1. Please inform me!" ;
last ;
2018-02-05 20:02:07 +00:00
}
2018-02-15 21:00:07 +00:00
### HTTP Requests #### Start ####
my $ connection ;
my $ Http_err = "" ;
my $ Http_data ;
2018-03-12 18:13:12 +00:00
my $ param = {
2018-04-01 17:51:09 +00:00
url = > "$xs1cmd" ,
timeout = > 3 ,
method = > "GET" , # Lesen von Inhalten
} ;
2018-02-15 21:00:07 +00:00
( $ Http_err , $ Http_data ) = HttpUtils_BlockingGet ( $ param ) ;
### HTTP Requests #### END ####
2018-02-05 20:02:07 +00:00
2018-02-15 21:00:07 +00:00
if ( $ Http_err ne "" ) {
( $ Http_err ) = $ Http_err =~ /[:]\s.*/g ;
Log3 $ name , 3 , "$typ: Write | no Control possible | Error" . $ Http_err ;
2018-02-05 20:02:07 +00:00
return undef ;
2018-02-15 21:00:07 +00:00
} elsif ( $ Http_data ne "" ) {
2018-04-06 22:05:18 +00:00
Debug " $typ: Write | Send to xs1 -> $xs1cmd" if ( $ debug == 1 ) ; ## Kontrolle Sendebefehl
2018-02-05 20:02:07 +00:00
}
2017-12-23 16:16:19 +00:00
}
2018-02-15 21:00:07 +00:00
sub xs1Bridge_Undef ($$)
{
2017-12-26 21:17:50 +00:00
my ( $ hash , $ name ) = @ _ ;
my $ typ = $ hash - > { TYPE } ;
2018-02-15 21:00:07 +00:00
2017-12-26 21:17:50 +00:00
RemoveInternalTimer ( $ hash ) ;
2018-02-15 21:00:07 +00:00
2018-02-05 20:02:07 +00:00
delete $ modules { xs1Bridge } { defptr } { BRIDGE } if ( defined ( $ modules { xs1Bridge } { defptr } { BRIDGE } ) ) ;
2018-03-17 09:04:30 +00:00
Log3 $ name , 3 , "$typ: deleting Device with Name $name" ;
2018-02-15 21:00:07 +00:00
foreach my $ d ( sort keys % defs ) {
if ( defined ( $ defs { $ d } ) && defined ( $ defs { $ d } { IODev } ) && $ defs { $ d } { IODev } == $ hash ) {
Log3 $ name , 3 , "$typ: deleting IODev for $d" ;
delete $ defs { $ d } { IODev } ;
2018-03-12 23:09:47 +00:00
}
}
2018-02-15 21:00:07 +00:00
return undef ;
2017-12-26 21:17:50 +00:00
}
2018-03-17 09:04:30 +00:00
##########################
# eigene Sub
sub is_in_array ($$$)
{
my ( $ hash , $ xs1_id , $ i ) = @ _ ;
my $ name = $ hash - > { NAME } ;
my $ typ = $ hash - > { TYPE } ;
my $ xs1_blackl = AttrVal ( $ hash - > { NAME } , "xs1_blackl_aktor" , 0 ) if ( $ i eq 0 ) ;
$ xs1_blackl = AttrVal ( $ hash - > { NAME } , "xs1_blackl_sensor" , 0 ) if ( $ i eq 1 ) ;
my @ attr_array = split ( /,/ , $ xs1_blackl ) ;
if ( grep ( /^$xs1_id$/ , @ attr_array ) ) {
#Log3 $name, 3, "$typ: is_in_array | id=$xs1_id auf xs1_blackl Aktoren" if ($i eq 0);
#Log3 $name, 3, "$typ: is_in_array | id=$xs1_id auf xs1_blackl Sensoren" if ($i eq 1);
return 1 ;
} else {
#Log3 $name, 3, "$typ: is_in_array | id=$xs1_id NICHT auf xs1_blackl Aktoren" if ($i eq 0);
#Log3 $name, 3, "$typ: is_in_array | id=$xs1_id NICHT auf xs1_blackl Sensoren" if ($i eq 1);
return 0 ;
}
}
##########################
2017-12-23 16:16:19 +00:00
# Eval-Rückgabewert für erfolgreiches
# Laden des Moduls
1 ;
# Beginn der Commandref
= pod
= item summary Connection of the device xs1 from EZControl
2018-02-05 20:02:07 +00:00
= item summary_DE Anbindung des Ger & auml ; tes xs1 der Firma EZControl
2017-12-23 16:16:19 +00:00
= begin html
< a name = "xs1Bridge" > </a>
<h3> xs1Bridge </h3>
<ul>
With this module you can read out the device xs1 from EZcontrol . There will be actors | Sensors | Timer | Information read from xs1 and written in readings . With each read only readings are created or updated , which are also defined and active in xs1 . Actor | Sensor or timer definitions which are deactivated in xs1 are NOT read .
<br> <br>
2018-02-05 20:02:07 +00:00
The module was developed based on the firmware version v4 - Beta of the xs1 . There may be errors due to different adjustments within the manufacturer ' s firmware . <br>
2018-04-01 17:51:09 +00:00
Testet firmware: v4 .0 .0 .5326 ( Beta ) @ me | v3 .0 .0 .4493 @ ForumUser <br>
<br> <ul>
<u> Currently implemented types of xs1 for processing: </u> <br>
<li> Aktor: dimmer , switch , shutter , timerswitch </li>
<li> Sensor: barometer , counter , counterdiff , light , motion , other , rain , rain_1h , rain_24h , rainintensity , remotecontrol , uv_index , waterdetector , winddirection , windgust , windspeed , windvariance </li>
</ul> <br> <br>
2017-12-23 16:16:19 +00:00
< a name = "xs1Bridge_define" > </a>
<b> Define </b> <br>
<ul>
2018-04-30 18:23:25 +00:00
xs1 without password: & nbsp ; & nbsp ; <code> define & lt ; NAME & gt ; xs1Bridge & lt ; IP & gt ; </code> <br>
xs1 with password: & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; <code> define & lt ; NAME & gt ; xs1Bridge & lt ; User & gt ; : & lt ; Passwort & gt ; @ & lt ; IP & gt ; </code>
2017-12-23 16:16:19 +00:00
<br> <br>
The module can not create without the IP of the xs1 . If the IP can not be reached during module definition , the Define process is aborted .
<ul>
2018-04-30 18:23:25 +00:00
<li> <code> & lt ; IP & gt ; </code> is IP address in the local network </li>
<li> <code> & lt ; User & gt ; </code> is the administrator user admin ( default ) </li>
<li> <code> & lt ; Password & gt ; </code> is the assigned administrator password in xs1 </li>
2017-12-23 16:16:19 +00:00
</ul> <br>
2018-04-30 18:23:25 +00:00
examples:
2017-12-23 16:16:19 +00:00
<ul>
2018-04-30 18:23:25 +00:00
define EZcontrol_xs1 xs1Bridge 192.168 .1 .45 <br>
define EZcontrol_xs1 xs1Bridge admin:secret @ 192 .168 .1 .45 <br>
2017-12-23 16:16:19 +00:00
</ul>
</ul> <br>
<b> Set </b>
<ul> N /A</ ul > <br>
<b> Get </b> <br>
<ul> N /A</ ul > <br>
< a name = "xs1_attr" > </a>
<b> Attributes </b>
<ul>
2018-04-13 13:48:07 +00:00
<li> debug ( 0 , 1 , 2 ) <br>
2017-12-23 16:16:19 +00:00
This brings the module into a very detailed debug output in the logfile . Program parts can be checked and errors checked . <br>
( Default , debug 0 )
</li> <br>
2018-02-05 20:02:07 +00:00
<li> update_only_difference ( 0 , 1 ) <br>
The actuators defined in xs1 are only updated when the value changes . <br>
( Default , update_only_difference 0 ) </li> <br>
<li> view_Device_name ( 0 , 1 ) <br>
The actor names defined in xs1 are read as Reading . <br>
( Default , view_Device_name 0 ) <br>
</li> <br>
<li> view_Device_function ( 0 , 1 ) <br>
The actuator functions defined in xs1 are read out as Reading . <br>
( Default , view_Device_function 0 ) <br>
2018-03-01 19:50:59 +00:00
</li> <br>
2018-03-17 09:04:30 +00:00
<li> xs1_blackl_aktor <br>
A comma - separated blacklist of actuators , which should not be created automatically as soon as xs1_control = 1 ( aktiv ) . <br>
( Example: 2 , 40 , 3 ) <br>
</li> <br>
<li> xs1_blackl_sensor <br>
A comma - separated blacklist of sensors , which should not be created automatically as soon as xs1_control = 1 ( aktiv ) . <br>
( Example: 3 , 37 , 55 ) <br>
</li> <br>
2018-03-01 19:50:59 +00:00
<li> xs1_control ( 0 , 1 ) <br>
Option to control the xs1 . After activating this , the xs1Dev module creates each actuator and sensor in FHEM . <br>
2018-03-17 09:04:30 +00:00
( Default , xs1_control 0 ) <br> <br>
<li> xs1_interval ( 0 , 30 , 60 , 180 , 360 ) <br>
This is the interval in seconds at which readings are read from xs1 <br>
<i> For actuators , only different states are updated in the set interval . </i> <br>
<i> Sensors are always updated in intervals , regardless of the status . </i> <br>
( Default , xs1_interval 60 )
</li> <br>
2017-12-30 12:39:56 +00:00
</li> <br> <br>
</ul>
<b> explanation: </b>
<ul>
<li> various Readings: </li>
<ul>
2018-02-05 20:02:07 +00:00
<li> Aktor_ ( 01 - 64 ) </li> defined actuator in the device <br>
<li> Aktor_ ( 01 - 64 ) _name </li> defined actor name in the device <br>
<li> Aktor_ ( 01 - 64 ) _function ( 1 - 4 ) </li> defined actuator function in the device <br>
<li> Sensor_ ( 01 - 64 ) </li> defined sensor in the device <br>
<li> Sensor_ ( 01 - 64 ) _name </li> defined sensor name in the device <br>
<li> Timer_ ( 01 - 128 ) </li> defined timer in the device <br>
<li> xs1_bootloader </li> version of bootloader <br>
2018-02-10 20:04:01 +00:00
<li> xs1_dhcp </li> DHCP on / off <br>
2018-02-05 20:02:07 +00:00
<li> xs1_features </li> purchased feature when buying ( A = send | B = receive | C = Skripte / Makros | D = Media Access ) <br>
<li> xs1_firmware </li> firmware number <br>
<li> xs1_start </li> device start <br>
2017-12-30 12:39:56 +00:00
</ul> <br>
2018-03-01 19:50:59 +00:00
<li> The message "<code>... Can't connect ...</code>" or "<code>ERROR: empty answer received</code>" in the system logfile says that there was no query for a short time . <br>
( This can happen more often with DLAN . ) <br> <br> </li>
2018-02-15 21:00:07 +00:00
<li> If the device has not been connected after 5 connection attempts , the module will switch on < disable > ! </li> <br>
2018-02-10 20:04:01 +00:00
<li> Create logfile automatically after define | scheme: <code> define FileLog_xs1Bridge FileLog . /log/xs 1 Bridge - % Y - % m . log & lt ; name & gt ; </code> <br>
2018-03-05 19:20:16 +00:00
The following values are recorded in logfile: Timer | xs1 - status information </li>
2017-12-23 16:16:19 +00:00
</ul>
</ul>
= end html
= begin html_DE
< a name = "xs1Bridge" > </a>
<h3> xs1Bridge </h3>
<ul>
2018-03-01 19:50:59 +00:00
Mit diesem Modul k & ouml ; nnen Sie das Gerät xs1 der Firma < a href = "http://www.ezcontrol.de/" > EZcontrol </a> auslesen . Das Modul ruft die Daten des xs1 via der Kommunikationsschnittstelle ab . Mit einem HTTP GET Requests erh & auml ; lt man die Antworten in Textform welche im Datenformat JSON ( JavaScript Object Notation ) ausgegeben werden .
2017-12-23 16:16:19 +00:00
Es werden Aktoren | Sensoren | Timer | Informationen vom xs1 ausgelesen und in Readings geschrieben . Bei jedem Auslesen werden nur Readings angelegt bzw . aktualisiert , welche auch im xs1 definiert und aktiv sind . Aktor | Sensor bzw . Timer Definitionen welche deaktiviert sind im xs1 , werden NICHT ausgelesen .
<br> <br>
2018-02-05 20:02:07 +00:00
Das Modul wurde entwickelt basierend auf dem Firmwarestand v4 - Beta des xs1 . Es kann aufgrund von unterschiedlichen Anpassungen innerhalb der Firmware des Herstellers zu Fehlern kommen . <br>
2018-04-01 17:51:09 +00:00
Getestete Firmware: v4 .0 .0 .5326 ( Beta ) @ me | v3 .0 .0 .4493 @ ForumUser <br>
2017-12-23 16:16:19 +00:00
2018-04-01 17:51:09 +00:00
<br> <ul>
<u> Derzeit implementierte Typen des xs1 zur Verarbeitung: </u> <br>
<li> Aktor: dimmer , switch , shutter , timerswitch </li>
<li> Sensor: barometer , counter , counterdiff , light , motion , other , rain , rain_1h , rain_24h , rainintensity , remotecontrol , uv_index , waterdetector , winddirection , windgust , windspeed , windvariance </li>
</ul> <br> <br>
2017-12-23 16:16:19 +00:00
< a name = "xs1Bridge_define" > </a>
<b> Define </b> <br>
<ul>
2018-04-30 18:23:25 +00:00
xs1 ohne Passwortabfrage: & nbsp ; & nbsp ; <code> define & lt ; NAME & gt ; xs1Bridge & lt ; IP & gt ; </code> <br>
xs1 mit Passwortabfrage: & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; <code> define & lt ; NAME & gt ; xs1Bridge & lt ; User & gt ; : & lt ; Passwort & gt ; @ & lt ; IP & gt ; </code>
2017-12-23 16:16:19 +00:00
<br> <br>
2018-03-01 19:50:59 +00:00
Ein anlegen des Modules ohne Angabe der IP vom xs1 ist nicht m & ouml ; glich . Sollte die IP bei der Moduldefinierung nicht erreichbar sein , so bricht der Define Vorgang ab .
2017-12-23 16:16:19 +00:00
<ul>
2018-04-30 18:23:25 +00:00
<li> <code> & lt ; IP & gt ; </code> ist IP - Adresse im lokalen Netzwerk </li>
<li> <code> & lt ; User & gt ; </code> ist der Administrator Benutzer admin ( standard ) </li>
<li> <code> & lt ; Passwort & gt ; </code> ist das vergebene Administrator Passwort im xs1 . </li>
2017-12-23 16:16:19 +00:00
</ul> <br>
2018-04-30 18:23:25 +00:00
Beispiele:
2017-12-23 16:16:19 +00:00
<ul>
2018-04-30 18:23:25 +00:00
define EZcontrol_xs1 xs1Bridge 192.168 .1 .45 <br>
define EZcontrol_xs1 xs1Bridge admin:geheim @ 192 .168 .1 .45 <br>
2017-12-23 16:16:19 +00:00
</ul>
</ul> <br>
<b> Set </b>
<ul> N /A</ ul > <br>
<b> Get </b> <br>
<ul> N /A</ ul > <br>
< a name = "xs1_attr" > </a>
<b> Attribute </b>
<ul>
2018-04-13 13:48:07 +00:00
<li> debug ( 0 , 1 , 2 ) <br>
2017-12-23 16:16:19 +00:00
Dies bringt das Modul in eine sehr ausf & uuml ; hrliche Debug - Ausgabe im Logfile . Somit lassen sich Programmteile kontrollieren und Fehler & uuml ; berpr & uuml ; fen . <br>
( Default , debug 0 )
</li> <br>
2018-02-05 20:02:07 +00:00
<li> update_only_difference ( 0 , 1 ) <br>
Die Aktoren welche im xs1 definiert wurden , werden nur bei Wert & auml ; nderung aktualisiert . <br>
( Default , update_only_difference 0 ) </li> <br>
<li> view_Device_name ( 0 , 1 ) <br>
Die Aktor Namen welche im xs1 definiert wurden , werden als Reading ausgelesen . <br>
( Default , view_Device_name 0 ) <br>
</li> <br>
<li> view_Device_function ( 0 , 1 ) <br>
Die Aktor Funktionen welche im xs1 definiert wurden , werden als Reading ausgelesen . <br>
( Default , view_Device_function 0 ) <br>
2018-03-01 19:50:59 +00:00
</li> <br>
2018-03-17 09:04:30 +00:00
<li> xs1_blackl_aktor <br>
Eine kommagetrennte Blacklist der Aktoren , welche nicht automatisch angelegt werden sollen sobald xs1_control = 1 ( aktiv ) . <br>
( Beispiel: 2 , 40 , 3 ) <br>
</li> <br>
<li> xs1_blackl_sensor <br>
Eine kommagetrennte Blacklist der Sensoren , welche nicht automatisch angelegt werden sollen sobald xs1_control = 1 ( aktiv ) . <br>
( Beispiel: 3 , 37 , 55 ) <br>
</li> <br>
2018-03-01 19:50:59 +00:00
<li> xs1_control ( 0 , 1 ) <br>
Die Freigabe zur Steuerung des xs1 . Nach Aktivierung dieser , wird durch das xs1Dev Modul jeder Aktor und Sensor in FHEM angelegt . <br>
( Default , xs1_control 0 ) <br>
2018-03-17 09:04:30 +00:00
</li> <br>
<li> xs1_interval ( 0 , 30 , 60 , 180 , 360 ) <br>
Das ist der Intervall in Sekunden , in dem die Readings neu gelesen werden vom xs1 . <br>
<i> Bei Aktoren werden nur unterschiedliche Zust & auml ; nde aktualisiert im eingestellten Intervall . </i> <br>
<i> Sensoren werden unabhängig vom Zustand immer im Intervall aktualisiert . </i> <br>
( Default , xs1_interval 60 )
2017-12-30 12:39:56 +00:00
</li> <br> <br>
</ul>
<b> Erl & auml ; uterung: </b>
<ul>
<li> Auszug Readings: </li>
<ul>
2018-02-05 20:02:07 +00:00
<li> Aktor_ ( 01 - 64 ) </li> definierter Aktor mit jeweiligem Zustand im Ger & auml ; t <br>
<li> Aktor_ ( 01 - 64 ) _name </li> definierter Aktorname im Ger & auml ; t <br>
<li> Aktor_ ( 01 - 64 ) _function ( 1 - 4 ) </li> definierte Aktorfunktion im Ger & auml ; t <br>
<li> Sensor_ ( 01 - 64 ) </li> definierter Sensor im Ger & auml ; t <br>
<li> Sensor_ ( 01 - 64 ) </li> definierter Sensorname im Ger & auml ; t <br>
<li> Timer_ ( 01 - 128 ) </li> definierter Timer im Ger & auml ; t <br>
<li> xs1_bootloader </li> Firmwareversion des Bootloaders <br>
2018-02-10 20:04:01 +00:00
<li> xs1_dhcp </li> DHCP an / aus <br>
2018-02-05 20:02:07 +00:00
<li> xs1_features </li> erworbene Feature beim Kauf ( A = SENDEN | B = EMPFANGEN | C = Skripte / Makros | D = Speicherkartenzugriff ) <br>
<li> xs1_firmware </li> Firmwareversion <br>
2018-02-10 20:04:01 +00:00
<li> xs1_start </li> Ger & auml ; testart <br>
2017-12-30 12:39:56 +00:00
</ul> <br>
2018-03-01 19:50:59 +00:00
<li> Die Meldung "<code>Error: Can't connect ...</code>" oder "<code>ERROR: empty answer received</code>" im System - Logfile , besagt das kurzzeitig keine Abfrage erfolgen konnte . <br>
( Das kann h & auml ; ufiger bei DLAN vorkommen . ) <br> <br> </li>
2018-02-15 21:00:07 +00:00
<li> Sollte das Ger & auml ; t nach 5 Verbindungsversuchen ebenfalls keine Verbindung erhalten haben , so schaltet das Modul auf < disable > ! </li> <br>
2018-02-10 20:04:01 +00:00
<li> Logfile Erstellung erfolgt automatisch nach dem definieren . | Schema: <code> define FileLog_xs1Bridge FileLog . /log/xs 1 Bridge - % Y - % m . log & lt ; Name & gt ; </code> <br>
2018-03-12 18:13:12 +00:00
Folgende Werte werden im Logfile erfasst: Timer | xs1 - Statusinformationen </li> <br>
<li> Sollte das Ger & auml ; t nach 5 Verbindungsversuchen ebenfalls keine Verbindung erhalten haben , so schaltet das Modul auf < disable > ! </li> <br>
2017-12-23 16:16:19 +00:00
</ul>
</ul>
= end html_DE
= cut