2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

88_xs1Bridge.pm: code changeover + safety connection check

git-svn-id: https://svn.fhem.de/fhem/trunk@16188 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
HomeAuto_User 2018-02-15 21:00:07 +00:00
parent 1ac6fa6bd0
commit 6b4edc5c8d
2 changed files with 238 additions and 253 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- bugfix: 88_xs1Bridge: code changeover + safety connection check
- bugfix: 73_PRESENCE: new collectord .deb package fixing perl warnings
- bugfix: 88_HMCCU: fixed CUxD bug and minor bugs
- feature: 93_DbRep: V7.10.0, new "changeValue" command, minor fixes

View File

@ -16,18 +16,14 @@ package main;
use HttpUtils; # um Daten via HTTP auszutauschen https://wiki.fhem.de/wiki/HttpUtils
use strict;
use warnings; # Warnings
use POSIX;
use LWP::Simple;
use Time::Local;
use Net::Ping;
my $missingModul = "";
my $xs1_security = 0; # disable Funktion sobald 10x keine Verbindung (Schutzabschaltung)
my $xs1_ConnectionTry = 1; # disable Funktion sobald 10x keine Verbindung (Schutzabschaltung)
eval "use Encode qw(encode encode_utf8 decode_utf8);1" or $missingModul .= "Encode ";
eval "use JSON;1" or $missingModul .= "JSON ";
use Net::Ping; # Ping Test Verbindung
#$| = 1; #Puffern abschalten, Hilfreich für PEARL WARNINGS Search
sub xs1Bridge_Initialize($) {
@ -39,7 +35,6 @@ sub xs1Bridge_Initialize($) {
$hash->{DefFn} = "xs1Bridge_Define";
$hash->{AttrFn} = "xs1Bridge_Attr";
$hash->{NotifyFn} = "xs1Bridge_Notify";
$hash->{UndefFn} = "xs1Bridge_Undef";
$hash->{AttrList} = "debug:0,1 ".
"disable:0,1 ".
@ -66,16 +61,22 @@ sub xs1Bridge_Define($$) {
my $update_only_difference = AttrVal($hash->{NAME},"update_only_difference",0);
return "Usage: define <name> $name <ip>" if(@arg != 3);
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);
return "Cannot define xs1Bridge device. Perl modul ${missingModul}is missing." if ( $missingModul );
my $p = Net::Ping->new("tcp", 2);
if(!($p->ping("$arg[2]", 2))) {
return "Your IP is not reachable. Please Check!";
}
$p->close();
# Parameter Define
my $xs1_ip = $arg[2]; ## Zusatzparameter 1 bei Define - ggf. nur in Sub
$hash->{xs1_ip} = $xs1_ip;
if (&xs1Bridge_Ping == 1) { ## IP - Check
$hash->{STATE} = "Initialized"; ## Der Status des Modules nach Initialisierung.
$hash->{TIME} = time(); ## Zeitstempel, derzeit vom anlegen des Moduls
$hash->{VERSION} = "1.12"; ## Version
$hash->{VERSION} = "1.14"; ## Version
$hash->{BRIDGE} = 1;
# Attribut gesetzt
@ -93,14 +94,9 @@ sub xs1Bridge_Define($$) {
fhem("define FileLog_xs1Bridge FileLog ./log/xs1Bridge-%Y-%m.log ".$arg[0]); ## Logfile define
fhem("attr FileLog_xs1Bridge room xs1"); ## Logfile in xs1 room
}
return undef;
}
else
{
return "ERROR - Host IP $xs1_ip is not reachable. Please check!" if(!defined($defs{$name}));
return undef; "$typ: ERROR - Host IP $xs1_ip is not reachable. Please check!" if(defined($defs{$name}));
}
}
sub xs1Bridge_Attr(@) {
my ($cmd,$name,$attrName,$attrValue) = @_;
@ -120,7 +116,7 @@ sub xs1Bridge_Attr(@) {
RemoveInternalTimer($hash); ## Timer löschen
Debug " $typ: Attr | Cmd:$cmd | RemoveInternalTimer" if($debug);
if ($attrName eq "interval") { ## Abfrage Attribute
if (($attrValue !~ /^\d*$/) || ($attrValue < 10)) ## Bildschirmausgabe - Hinweis Wert zu klein
if (($attrValue !~ /^\d*$/) || ($attrValue < 10))
{
return "$typ: Interval is too small. Please define new Interval | (at least: 10 seconds)";
}
@ -131,7 +127,7 @@ sub xs1Bridge_Attr(@) {
readingsSingleUpdate($hash, "state", "deactive", 1);
}
elsif ($attrValue eq "0") { ## Handling bei attribute disable 0
$xs1_security = 0;
$xs1_ConnectionTry = 1;
readingsSingleUpdate($hash, "state", "active", 1);
}
}elsif ($attrName eq "view_Device_function") {
@ -203,36 +199,13 @@ sub xs1Bridge_Attr(@) {
return undef;
}
sub xs1Bridge_Delete($$) {
my ( $hash, $name ) = @_;
RemoveInternalTimer($hash);
return undef;
}
sub xs1Bridge_Ping() { ## Check IP before Define
my ($hash) = @_;
my $name = $hash->{NAME};
my $typ = $hash->{TYPE};
my $xs1_ip = $hash->{xs1_ip};
my $timeout = "3";
my $connection;
my $p = Net::Ping->new;
my $isAlive = $p->ping($xs1_ip , $timeout);
$p->close;
if ($isAlive) {
$connection = 1;
} else {
$connection = 0;
}
return ($connection);
}
sub xs1Bridge_GetUpDate() {
my ($hash) = @_;
my $name = $hash->{NAME};
my $typ = $hash->{TYPE};
my $state = $hash->{STATE};
my $xs1_ip = $hash->{xs1_ip};
my $xs1_uptimeStart = $hash->{helper}{xs1_uptimeStart};
my $xs1_uptimeOld = $hash->{helper}{xs1_uptimeOld};
my $xs1_uptimeNew = $hash->{helper}{xs1_uptimeNew};
@ -257,10 +230,10 @@ sub xs1Bridge_GetUpDate() {
my $viewDeviceFunction = AttrVal($hash->{NAME},"view_Device_function",0);
my $update_only_difference = AttrVal($hash->{NAME},"update_only_difference",0);
if (AttrVal($hash->{NAME},"disable",0) == 0 && $xs1_security <= 10) {
if (AttrVal($hash->{NAME},"disable",0) == 0 && $xs1_ConnectionTry <= 5) {
RemoveInternalTimer($hash); ## Timer löschen
InternalTimer(gettimeofday()+$interval, "xs1Bridge_GetUpDate", $hash);
Debug "\n ------------- ERROR CHECK - START -------------" if($debug);
Debug " -------------- ERROR CHECK - START --------------" if($debug);
Debug " $typ: GetUpDate | RemoveInternalTimer + InternalTimer" if($debug);
#Log3 $name, 3, "$typ: xs1Bridge_GetUpDate | RemoveInternalTimer + InternalTimer";
@ -281,36 +254,48 @@ sub xs1Bridge_GetUpDate() {
### JSON Abfrage - Schleife
for my $i (0..3) {
my $adress = "http://".$hash->{xs1_ip}.$cmd.$cmdtyp[$i];
Debug " $typ: GetUpDate | Adresse: $adress" if($debug);
### HTTP Requests #### Start ####
my $connection;
my $Http_err = "";
my $Http_data = "";
my $param = {
url => "http://".$xs1_ip.$cmd.$cmdtyp[$i],
timeout => 3,
method => "GET", # Lesen von Inhalten
};
HttpUtils_BlockingGet($param);
($Http_err, $Http_data) = HttpUtils_BlockingGet($param);
### HTTP Requests #### END ####
my $adress = "http://".$xs1_ip.$cmd.$cmdtyp[$i];
my $json;
my $json_utf8;
my $decoded;
my $ua = LWP::UserAgent->new; ## CHECK JSON Adresse -> JSON-query, sonst FHEM shutdown
my $resp = $ua->request(HTTP::Request->new(GET => $adress));
Debug " $typ: GetUpDate | Adresse HTTP request Code: ".$resp->code if($debug);
Debug " $typ: GetUpDate | Adresse: $adress | xs1_ConnectionTry=$xs1_ConnectionTry" if($debug && $Http_err eq "");
Debug " $typ: GetUpDate | HTTP request: ".$Http_err."| xs1_ConnectionTry=$xs1_ConnectionTry" if($debug && $Http_err ne "");
## Get $adress Antwort, OK dann ARRAY Verarbeitung, n.iO ABBRUCH
if ($resp->code == "200") { ## http://search.cpan.org/~oalders/HTTP-Message-6.13/lib/HTTP/Status.pm
($json) = get( $adress ) =~ /[^(]*[}]/g; ## cut cname( + ) am Ende von Ausgabe -> ARRAY Struktur als Antwort vom xs1
if ($Http_err ne "") { ## HTTP Requests, ERROR
# 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
($Http_err) = $Http_err =~ /[:]\s.*/g;
Log3 $name, 3, "$typ: GetUpDate | Try=$xs1_ConnectionTry loop=$i | Error".$Http_err;
$xs1_ConnectionTry++;
last; ## Abbruch Schleife
} elsif ($Http_data ne "") { ## HTTP Requests, OK dann ARRAY Verarbeitung
($json) = $Http_data =~ /[^(]*[}]/g; ## cut cname( + ) am Ende von Ausgabe -> ARRAY Struktur als Antwort vom xs1
$json_utf8 = eval {encode_utf8( $json )}; ## UTF-8 character Bearbeitung, da xs1 TempSensoren ERROR
$decoded = eval {decode_json( $json_utf8 )}; ## auswertbares ARAAY
} else {
Log3 $name, 3, "$typ: GetUpDate | cmdtyp=".$cmdtyp[$i]." - HTTP GET error code ".$resp->code." -> no Data";
$xs1_security++;
last; ## ERROR JSON-query -> Abbruch schleife
}
$decoded = eval {decode_json( $json_utf8 )};
$xs1_ConnectionTry = 1;
if ($i <= 1 ) { ### xs1 Aktoren / Sensoren
if ($resp->code != "200") { ## http://search.cpan.org/~oalders/HTTP-Message-6.13/lib/HTTP/Status.pm
Log3 $name, 3, "$typ: GetUpDate | cmdtyp=".$cmdtyp[$i]." - HTTP GET error code ".$resp->code." -> no Data";
last; ## ERROR JSON-query -> Abbruch schleife
}
my $data;
my $xs1_data;
my @array;
if (defined $decoded->{$arrayname[$i]}) {
@array = @{ $decoded->{$arrayname[$i]} };
} else {
@ -378,9 +363,9 @@ sub xs1Bridge_GetUpDate() {
### Value der Aktoren | Sensoren
if ($i == 1 || $i == 0 && $update_only_difference == 0) { # Aktoren | Sensoren im intervall - Format 0.0 bzw. 37.0 wie aus xs1
readingsSingleUpdate($hash, $readingsname[$i]."_".sprintf("%02d", $f->{"id"}) , sprintf("%.1f" , $f->{"value"}), 1);
$data = $xs1Dev."#".$readingsname[$i]."#".sprintf("%02d", $f->{"id"})."#".$f->{"type"}."#".sprintf("%.1f" , $f->{"value"})."#"."$xs1_function1"."#"."$xs1_function2"."#"."$xs1_function3"."#"."$xs1_function4"."#".$f->{"name"};
$xs1_data = $xs1Dev."#".$readingsname[$i]."#".sprintf("%02d", $f->{"id"})."#".$f->{"type"}."#".sprintf("%.1f" , $f->{"value"})."#"."$xs1_function1"."#"."$xs1_function2"."#"."$xs1_function3"."#"."$xs1_function4"."#".$f->{"name"};
} elsif ($i == 0 && $update_only_difference == 1){ # Aktoren | nur bei DIFF - Format 0.0 bzw. 37.0 wie aus xs1
$data = $xs1Dev."#".$readingsname[$i]."#".sprintf("%02d", $f->{"id"})."#".$f->{"type"}."#".sprintf("%.1f" , $f->{"value"})."#"."$xs1_function1"."#"."$xs1_function2"."#"."$xs1_function3"."#"."$xs1_function4"."#".$f->{"name"};
$xs1_data = $xs1Dev."#".$readingsname[$i]."#".sprintf("%02d", $f->{"id"})."#".$f->{"type"}."#".sprintf("%.1f" , $f->{"value"})."#"."$xs1_function1"."#"."$xs1_function2"."#"."$xs1_function3"."#"."$xs1_function4"."#".$f->{"name"};
}
### Ausgaben je Typ unterschiedlich !!!
@ -394,17 +379,12 @@ sub xs1Bridge_GetUpDate() {
### Dispatch an xs1Device Modul
if ($xs1Dev_check eq "ok") {
Debug " $typ: GetUpDate | Dispatch -> $data" if($debug);
Dispatch($hash,$data,undef) if($data);
Debug " $typ: GetUpDate | Dispatch: $xs1_data" if($debug);
Dispatch($hash,$xs1_data,undef) if($xs1_data);
}
}
}
} elsif ($i == 2) { ### xs1 Info´s nur bei uptime Änderung
if ($resp->code != "200") { ## http://search.cpan.org/~oalders/HTTP-Message-6.13/lib/HTTP/Status.pm
Log3 $name, 3, "$typ: GetUpDate | cmdtyp=".$cmdtyp[$i]." - HTTP GET error code ".$resp->code." -> no Data";
last; ## ERROR JSON-query -> Abbruch schleife
}
my $features;
my $features_i=0;
@ -419,7 +399,7 @@ sub xs1Bridge_GetUpDate() {
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
if (abs($oldState - $newState) > 5) { ## Vergleich mit 5 Sekunden Tolleranz je Verabeitungszeit Netzwerk | DLAN | CPU
if (abs($oldState - $newState) > 5 || $debug == 1) { ## Vergleich mit 5 Sekunden Tolleranz je Verarbeitungszeit Netzwerk | DLAN | CPU
readingsBeginUpdate($hash);
for my $i2 (0..7) {
if ($i2 == 4) {
@ -430,7 +410,6 @@ sub xs1Bridge_GetUpDate() {
$xs1_decoded[4] = $features; ## ARRAY Wert xs1_decoded wird definiert
}
if (defined $xs1_decoded[$i2]) {
readingsBulkUpdate($hash, $xs1_readings[$i2] , $xs1_decoded[$i2]);
Debug " $typ: ".$xs1_readings[$i2].": ".$xs1_decoded[$i2] if($debug);
} else {
@ -441,11 +420,6 @@ sub xs1Bridge_GetUpDate() {
readingsEndUpdate($hash, 1);
}
} elsif ($i == 3) { ### xs1 Timers
if ($resp->code != "200") { ## http://search.cpan.org/~oalders/HTTP-Message-6.13/lib/HTTP/Status.pm
Log3 $name, 3, "$typ: GetUpDate | cmdtyp=".$cmdtyp[$i]." - HTTP GET error code ".$resp->code." -> no Data";
last; ## ERROR JSON-query -> Abbruch schleife
}
my @array = @{ $decoded->{$arrayname[$i]} };
foreach my $f ( @array ) {
my $oldState = ReadingsVal($name, $readingsname[$i]."_".sprintf("%02d", $f->{"id"}), "unknown"); ## Readings Wert
@ -464,15 +438,16 @@ sub xs1Bridge_GetUpDate() {
}
if ($i < 3) {
Debug "\n ------------- ERROR CHECK - SUB -------------" if($debug);
Debug " --------------- ERROR CHECK - SUB --------------- " if($debug);
}
### Schleifen Ende ###
}
Debug "\n ------------- ERROR CHECK - ALL END -------------\n " if($debug);
}
if ($xs1_security == 10) { ## Abschaltung xs1 nach 10 Verbindungsversuchen
Debug " ------------- ERROR CHECK - ALL END -------------\n " if($debug);
}
if ($xs1_ConnectionTry == 6) { ## Abschaltung xs1 nach 10 Verbindungsversuchen
$attr{$name}{disable} = "1";
readingsSingleUpdate($hash, "state", "deactive", 1);
RemoveInternalTimer($hash); ## Timer löschen
@ -487,7 +462,7 @@ sub xs1Bridge_Write($) ## Zustellen von Daten via IOWrite() vom logischen zum
my $typ = $hash->{TYPE};
my $xs1_ip = $hash->{xs1_ip};
## Anfrage (Client -> XS1): http://192.168.1.242/control?callback=cname&cmd=set_state_actuator&number=1&value=50
## Anfrage (Client -> XS1): http://192.168.1.242/control?callback=cname&cmd=set_state_actuator&number=1&value=100
$Aktor_ID = substr($Aktor_ID, 1,2);
@ -499,39 +474,48 @@ sub xs1Bridge_Write($) ## Zustellen von Daten via IOWrite() vom logischen zum
}
}
my $json;
my $json_utf8;
my $decoded;
my $xs1cmd = "http://$xs1_ip/control?callback=cname&cmd=set_state_actuator&number=$Aktor_ID&value=$cmd";
my $ua = LWP::UserAgent->new; ## CHECK JSON Adresse -> JSON-query, sonst FHEM shutdown
my $resp = $ua->request(HTTP::Request->new(GET => $xs1cmd));
### HTTP Requests #### Start ####
my $connection;
my $Http_err = "";
my $Http_data;
my $param = {
url => "$xs1cmd",
timeout => 3,
method => "GET", # Lesen von Inhalten
};
if ($resp->code != "200") { ## http://search.cpan.org/~oalders/HTTP-Message-6.13/lib/HTTP/Status.pm
Log3 $name, 3, "$typ: Write | cmd=".$xs1cmd." - HTTP GET error code ".$resp->code." -> no Control possible";
HttpUtils_BlockingGet($param);
($Http_err, $Http_data) = HttpUtils_BlockingGet($param);
### HTTP Requests #### END ####
if ($Http_err ne "") {
($Http_err) = $Http_err =~ /[:]\s.*/g;
Log3 $name, 3, "$typ: Write | no Control possible | Error".$Http_err;
return undef;
} else {
} elsif ($Http_data ne "") {
Log3 $name, 3, "$typ: Write | Send to xs1 -> $xs1cmd";
($json) = get( $xs1cmd ) =~ /[^(]*[}]/g; ## cut cname( + ) am Ende von Ausgabe -> ARRAY Struktur als Antwort vom xs1
#$json_utf8 = eval {encode_utf8( $json )}; ## UTF-8 character Bearbeitung, da xs1 TempSensoren ERROR
#$decoded = eval {decode_json( $json_utf8 )}; ## auswertbares ARAAY
}
}
sub xs1Bridge_Notify($$)
{
}
sub xs1Bridge_Undef($$)
{
my ( $hash, $name) = @_;
my $typ = $hash->{TYPE};
RemoveInternalTimer($hash);
Log3 $name, 3, "$typ: Device with Name: $name delete";
delete $modules{xs1Bridge}{defptr}{BRIDGE} if( defined($modules{xs1Bridge}{defptr}{BRIDGE}) );
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};
}
}
Log3 $name, 3, "$typ: deleting Device with Name $name";
return undef;
}
@ -554,7 +538,7 @@ sub xs1Bridge_Undef($$)
<br><br>
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>
Testet firmware: v4.0.0.5326 (Beta) <br><br>
Testet firmware: v4.0.0.5326 (Beta) @me | v3.0.0.4493 @ForumUser<br><br>
<a name="xs1Bridge_define"></a>
<b>Define</b><br>
@ -620,8 +604,8 @@ sub xs1Bridge_Undef($$)
<li>xs1_firmware</li> firmware number<br>
<li>xs1_start</li> device start<br>
</ul><br>
<li>The message "<code>HTTP GET error code 500 -> no Data </code>" in the log file says that there was no query for a short time.</li>
<li>If the device has not been connected after 10 connection attempts, the module will switch on < disable > !</li><br>
<li>The message "<code>... Can't connect ...</code>" in the system logfile says that there was no query for a short time.</li>
<li>If the device has not been connected after 5 connection attempts, the module will switch on < disable > !</li><br>
<li>Create logfile automatically after define | scheme: <code>define FileLog_xs1Bridge FileLog ./log/xs1Bridge-%Y-%m.log &lt;name&gt;</code><br>
The following values are recorded in logfile: Aktor_(01-64) or Sensor_(01-64) values | Timer | xs1-status information</li>
</ul>
@ -637,7 +621,7 @@ sub xs1Bridge_Undef($$)
<br><br>
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>
Getestete Firmware: v4.0.0.5326 (Beta) <br><br>
Getestete Firmware: v4.0.0.5326 (Beta) @me | v3.0.0.4493 @ForumUser<br><br>
<a name="xs1Bridge_define"></a>
<b>Define</b><br>
@ -703,8 +687,8 @@ sub xs1Bridge_Undef($$)
<li>xs1_firmware</li> Firmwareversion<br>
<li>xs1_start</li> Ger&auml;testart<br>
</ul><br>
<li>Die Meldung "<code>HTTP GET error code 500 -> no Data </code>" im Logfile besagt, das kurzzeitig keine Abfrage erfolgen konnte.</li>
<li>Sollte das Ger&auml;t nach 10 Verbindungsversuchen ebenfalls keine Verbindung erhalten haben, so schaltet das Modul auf < disable > !</li><br>
<li>Die Meldung "<code>... Can't connect ...</code>" im System-Logfile besagt, das kurzzeitig keine Abfrage erfolgen konnte.</li>
<li>Sollte das Ger&auml;t nach 5 Verbindungsversuchen ebenfalls keine Verbindung erhalten haben, so schaltet das Modul auf < disable > !</li><br>
<li>Logfile Erstellung erfolgt automatisch nach dem definieren. | Schema: <code>define FileLog_xs1Bridge FileLog ./log/xs1Bridge-%Y-%m.log &lt;Name&gt;</code><br>
Folgende Werte werden im Logfile erfasst: Aktor_(01-64) bzw. Sensor_(01-64) Werte | Timer | xs1-Statusinformationen</li>
</ul>