mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 22:19:38 +00:00
24_TPLinkHS110: Added patch for viegener for more reliable communication with newer models or firmwares
git-svn-id: https://svn.fhem.de/fhem/trunk@19532 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
ead21543e1
commit
1e63f6700d
@ -1,7 +1,7 @@
|
|||||||
################################################################
|
################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Release 2018-11-01 SetExtension
|
# Release 2019-05-31 SendCommand2
|
||||||
#
|
#
|
||||||
# Copyright notice
|
# Copyright notice
|
||||||
#
|
#
|
||||||
@ -25,7 +25,7 @@
|
|||||||
# In older distribution try "cpan IO::Socket::Timeout"
|
# In older distribution try "cpan IO::Socket::Timeout"
|
||||||
#
|
#
|
||||||
# Origin:
|
# Origin:
|
||||||
# https://github.com/kettenbach-it/FHEM-TPLink-HS110
|
# https://gitlab.com/volkerkettenbach/FHEM-TPLink-Kasa
|
||||||
#
|
#
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
@ -41,8 +41,7 @@ use Data::Dumper;
|
|||||||
|
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Initialize($)
|
sub TPLinkHS110_Initialize($) {
|
||||||
{
|
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
$hash->{DefFn} = "TPLinkHS110_Define";
|
$hash->{DefFn} = "TPLinkHS110_Define";
|
||||||
@ -51,7 +50,7 @@ sub TPLinkHS110_Initialize($)
|
|||||||
$hash->{UndefFn} = "TPLinkHS110_Undefine";
|
$hash->{UndefFn} = "TPLinkHS110_Undefine";
|
||||||
$hash->{DeleteFn} = "TPLinkHS110_Delete";
|
$hash->{DeleteFn} = "TPLinkHS110_Delete";
|
||||||
$hash->{AttrFn} = "TPLinkHS110_Attr";
|
$hash->{AttrFn} = "TPLinkHS110_Attr";
|
||||||
$hash->{AttrList} = "interval ".
|
$hash->{AttrList} = "interval " .
|
||||||
"disable:0,1 " .
|
"disable:0,1 " .
|
||||||
"nightmode:on,off " .
|
"nightmode:on,off " .
|
||||||
"timeout " .
|
"timeout " .
|
||||||
@ -59,64 +58,135 @@ sub TPLinkHS110_Initialize($)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Define($$)
|
sub TPLinkHS110_Define($$) {
|
||||||
{
|
|
||||||
my ($hash, $def) = @_;
|
my ($hash, $def) = @_;
|
||||||
my $name= $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
my @a = split( "[ \t][ \t]*", $def );
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
return "Wrong syntax: use define <name> TPLinkHS110 <hostname/ip> " if (int(@a) != 3);
|
return "Wrong syntax: use define <name> TPLinkHS110 <hostname/ip> " if (int(@a) != 3);
|
||||||
|
|
||||||
$hash->{INTERVAL}=300;
|
$hash->{INTERVAL} = 300;
|
||||||
$hash->{TIMEOUT}=1;
|
$hash->{TIMEOUT} = 1;
|
||||||
$hash->{HOST}=$a[2];
|
$hash->{HOST} = $a[2];
|
||||||
$attr{$name}{"disable"} = 0;
|
$attr{$name}{"disable"} = 0;
|
||||||
# initial request after 2 secs, there timer is set to interval for further update
|
# initial request after 2 secs, there timer is set to interval for further update
|
||||||
InternalTimer(gettimeofday()+2, "TPLinkHS110_Get", $hash, 0);
|
InternalTimer(gettimeofday() + 2, "TPLinkHS110_Get", $hash, 0);
|
||||||
|
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name defined.";
|
Log3 $hash, 3, "TPLinkHS110: $name defined.";
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Get($$)
|
# sends given command and returns ($errmsg/undef,undef/$decrypteddata)
|
||||||
{
|
sub TPLinkHS110_SendCommand($$) {
|
||||||
my ($hash) = @_;
|
my ($hash, $command) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my($success,$json,$realtimejson);
|
|
||||||
return "Device disabled in config" if ($attr{$name}{"disable"} eq "1");
|
|
||||||
RemoveInternalTimer($hash);
|
|
||||||
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "TPLinkHS110_Get", $hash, 1);
|
|
||||||
$hash->{NEXTUPDATE}=localtime(gettimeofday()+$hash->{INTERVAL});
|
|
||||||
|
|
||||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
|
||||||
$mon++;
|
|
||||||
$year += 1900;
|
|
||||||
|
|
||||||
my $remote_host = $hash->{HOST};
|
my $remote_host = $hash->{HOST};
|
||||||
my $remote_port = 9999;
|
my $remote_port = 9999;
|
||||||
my $command = '{"system":{"get_sysinfo":{}}}';
|
|
||||||
my $c = encrypt($command);
|
my $c = encrypt($command);
|
||||||
my $socket = IO::Socket::INET->new(PeerAddr => $remote_host,
|
my $socket = IO::Socket::INET->new(PeerAddr => $remote_host,
|
||||||
PeerPort => $remote_port,
|
PeerPort => $remote_port,
|
||||||
Proto => 'tcp',
|
Proto => 'tcp',
|
||||||
Type => SOCK_STREAM,
|
Type => SOCK_STREAM,
|
||||||
Timeout => $hash->{TIMEOUT} )
|
Timeout => $hash->{TIMEOUT})
|
||||||
or return "Couldn't connect to $remote_host:$remote_port: $@\n";
|
or return("Couldn't connect to $remote_host:$remote_port: $@\n", undef);
|
||||||
$socket->write($c);
|
$socket->write($c);
|
||||||
IO::Socket::Timeout->enable_timeouts_on($socket);
|
IO::Socket::Timeout->enable_timeouts_on($socket);
|
||||||
$socket->read_timeout(.5);
|
$socket->read_timeout(2.5);
|
||||||
|
|
||||||
|
my $dlen;
|
||||||
|
my $res;
|
||||||
|
my $errmsg;
|
||||||
my $data;
|
my $data;
|
||||||
$data = <$socket>;
|
|
||||||
|
$res = sysread($socket, $dlen, 4);
|
||||||
|
$dlen = "" if (!defined($res));
|
||||||
|
|
||||||
|
if ($res != 4) {
|
||||||
|
$errmsg = "Could not read 4 length bytes";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $datalen = 0;
|
||||||
|
|
||||||
|
if (!defined($errmsg)) {
|
||||||
|
for (my $i = 0; $i < 4; $i++) {
|
||||||
|
$datalen *= 256;
|
||||||
|
$datalen += ord(substr($dlen, $i, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Log3 $hash, 4, "TPLinkHS110: $name Get length - " . $datalen; # JV
|
||||||
|
|
||||||
|
|
||||||
|
my $datapart;
|
||||||
|
$data = "";
|
||||||
|
my $partlen = 0;
|
||||||
|
my $remainlen = $datalen;
|
||||||
|
my $ctr = 0;
|
||||||
|
|
||||||
|
while (($remainlen > 0) && (!defined($errmsg))) {
|
||||||
|
$res = sysread($socket, $datapart, $remainlen);
|
||||||
|
if (!defined($res) || $res < 0) {
|
||||||
|
$errmsg = "Data reading failed - received errcode: " . $res;
|
||||||
|
}
|
||||||
|
elsif ($res == 0) {
|
||||||
|
$ctr++;
|
||||||
|
$errmsg = "Could not read correct length - expected: " . $datalen . " received: " . $partlen if ($ctr > 2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ctr = 0;
|
||||||
|
$data .= $datapart;
|
||||||
|
$remainlen -= $res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log3 $hash, 4, "TPLinkHS110: $name Get read data length - " . length($data); # JV
|
||||||
|
}
|
||||||
|
|
||||||
$socket->close();
|
$socket->close();
|
||||||
|
|
||||||
readingsBeginUpdate($hash);
|
if (!defined($errmsg)) {
|
||||||
$data = decrypt(substr($data,4));
|
$data = decrypt($data);
|
||||||
|
return(undef, $data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return($errmsg, undef);
|
||||||
|
}
|
||||||
|
|
||||||
($success,$json) = TPLinkHS110__evaljson($name,$data);
|
}
|
||||||
if(!$success) {
|
|
||||||
|
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub TPLinkHS110_Get($$) {
|
||||||
|
my ($hash) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my ($success, $json, $realtimejson);
|
||||||
|
return "Device disabled in config" if ($attr{$name}{"disable"} eq "1");
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
InternalTimer(gettimeofday() + $hash->{INTERVAL}, "TPLinkHS110_Get", $hash, 1);
|
||||||
|
$hash->{NEXTUPDATE} = localtime(gettimeofday() + $hash->{INTERVAL});
|
||||||
|
|
||||||
|
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
|
||||||
|
$mon++;
|
||||||
|
$year += 1900;
|
||||||
|
|
||||||
|
my $errmsg;
|
||||||
|
my $data;
|
||||||
|
|
||||||
|
my $command = '{"system":{"get_sysinfo":{}}}';
|
||||||
|
($errmsg, $data) = TPLinkHS110_SendCommand($hash, $command);
|
||||||
|
if (defined($errmsg)) {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name Get failed - " . $errmsg; # JV
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
($success, $json) = TPLinkHS110__evaljson($name, $data);
|
||||||
|
if (!$success) {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name Get failed"; # JV
|
||||||
readingsEndUpdate($hash, 1);
|
readingsEndUpdate($hash, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -145,32 +215,30 @@ sub TPLinkHS110_Get($$)
|
|||||||
readingsBulkUpdate($hash, "state", "on");
|
readingsBulkUpdate($hash, "state", "on");
|
||||||
}
|
}
|
||||||
# If the device is a HS110, get realtime data:
|
# If the device is a HS110, get realtime data:
|
||||||
|
# if ( 1 == 0 ) {
|
||||||
if ($json->{'system'}->{'get_sysinfo'}->{'model'} eq "HS110(EU)" or $json->{'system'}->{'get_sysinfo'}->{'model'} eq "HS110(UK)") {
|
if ($json->{'system'}->{'get_sysinfo'}->{'model'} eq "HS110(EU)" or $json->{'system'}->{'get_sysinfo'}->{'model'} eq "HS110(UK)") {
|
||||||
my $realtimejcommand='{"emeter":{"get_realtime":{}}}';
|
my $realtimejcommand = '{"emeter":{"get_realtime":{}}}';
|
||||||
my $rc = encrypt($realtimejcommand);
|
|
||||||
my $socket = IO::Socket::INET->new(PeerAddr => $remote_host,
|
|
||||||
PeerPort => $remote_port,
|
|
||||||
Proto => 'tcp',
|
|
||||||
Type => SOCK_STREAM,
|
|
||||||
Timeout => $hash->{TIMEOUT} )
|
|
||||||
or return "Couldn't connect to $remote_host:$remote_port: $@\n";
|
|
||||||
$socket->write($rc);
|
|
||||||
IO::Socket::Timeout->enable_timeouts_on($socket);
|
|
||||||
$socket->read_timeout(.5);
|
|
||||||
my $rdata;
|
my $rdata;
|
||||||
$rdata = <$socket>;
|
($errmsg, $rdata) = TPLinkHS110_SendCommand($hash, $realtimejcommand);
|
||||||
$rdata = decrypt(substr($rdata,4));
|
if (defined($errmsg)) {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name Get realtime data failed - " . $errmsg; # JV
|
||||||
if (length($rdata)==0) {
|
readingsEndUpdate($hash, 1);
|
||||||
Log3 $hash, 1, "TPLinkHS110: $name: Received zero bytes of realtime data. Cannot process realtime data";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
($success,$realtimejson) = TPLinkHS110__evaljson($name,$rdata);
|
if (length($rdata) == 0) {
|
||||||
if(!$success) {
|
Log3 $hash, 1, "TPLinkHS110: $name: Received zero bytes of realtime data. Cannot process realtime data";
|
||||||
readingsEndUpdate($hash, 1);
|
readingsEndUpdate($hash, 1);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
($success, $realtimejson) = TPLinkHS110__evaljson($name, $rdata);
|
||||||
|
if (!$success) {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name: Received zero bytes of realtime data. Cannot process realtime data";
|
||||||
|
readingsEndUpdate($hash, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
Log3 $hash, 2, "TPLinkHS110: $name Realtime data updated";
|
Log3 $hash, 2, "TPLinkHS110: $name Realtime data updated";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +256,8 @@ sub TPLinkHS110_Get($$)
|
|||||||
$key2 = $hwMap{$hw_ver}{'emeter'}{'get_realtime'}{$key2}{'name'};
|
$key2 = $hwMap{$hw_ver}{'emeter'}{'get_realtime'}{$key2}{'name'};
|
||||||
readingsBulkUpdate($hash, $key2, $emeterValue);
|
readingsBulkUpdate($hash, $key2, $emeterValue);
|
||||||
$emeterReadings{$key2} = $emeterValue;
|
$emeterReadings{$key2} = $emeterValue;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return "Check supported hw_ver of device: $hw_ver\n";
|
return "Check supported hw_ver of device: $hw_ver\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,50 +266,45 @@ sub TPLinkHS110_Get($$)
|
|||||||
|
|
||||||
|
|
||||||
# Get Daily Stats
|
# Get Daily Stats
|
||||||
my $command = '{"emeter":{"get_daystat":{"month":'.$mon.',"year":'.$year.'}}}';
|
$command = '{"emeter":{"get_daystat":{"month":' . $mon . ',"year":' . $year . '}}}';
|
||||||
my $c = encrypt($command);
|
($errmsg, $data) = TPLinkHS110_SendCommand($hash, $command);
|
||||||
$socket = IO::Socket::INET->new(PeerAddr => $remote_host,
|
if (defined($errmsg)) {
|
||||||
PeerPort => $remote_port,
|
Log3 $hash, 1, "TPLinkHS110: $name Get daily stats failed - " . $errmsg; # JV
|
||||||
Proto => 'tcp',
|
readingsEndUpdate($hash, 1);
|
||||||
Type => SOCK_STREAM,
|
return;
|
||||||
Timeout => $hash->{TIMEOUT} )
|
}
|
||||||
or return "Couldn't connect to $remote_host:$remote_port: $@\n";
|
|
||||||
$socket->write($c);
|
|
||||||
IO::Socket::Timeout->enable_timeouts_on($socket);
|
|
||||||
$socket->read_timeout(.5);
|
|
||||||
my $data;
|
|
||||||
$data = <$socket>;
|
|
||||||
$socket->close();
|
|
||||||
$data = decrypt(substr($data,4));
|
|
||||||
|
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name Updating daystat. Data: " . $data;
|
Log3 $hash, 3, "TPLinkHS110: $name Updating daystat. Data: " . $data;
|
||||||
|
|
||||||
($success,$json) = TPLinkHS110__evaljson($name,$data);
|
($success, $json) = TPLinkHS110__evaljson($name, $data);
|
||||||
if($success && $json) {
|
if ($success && $json) {
|
||||||
my $total=0;
|
|
||||||
|
my $total = 0;
|
||||||
foreach my $key (sort keys @{$json->{'emeter'}->{'get_daystat'}->{'day_list'}}) {
|
foreach my $key (sort keys @{$json->{'emeter'}->{'get_daystat'}->{'day_list'}}) {
|
||||||
foreach my $key2 ($json->{'emeter'}->{'get_daystat'}->{'day_list'}[$key]) {
|
foreach my $key2 ($json->{'emeter'}->{'get_daystat'}->{'day_list'}[$key]) {
|
||||||
if ($hw_ver eq "1.0") {
|
if ($hw_ver eq "1.0") {
|
||||||
$total = $total+ $key2->{'energy'};
|
$total = $total + $key2->{'energy'};
|
||||||
if ($key2->{'day'} == $mday) {
|
if ($key2->{'day'} == $mday) {
|
||||||
readingsBulkUpdate($hash, "daily_total", sprintf("%.3f", $key2->{'energy'}));
|
readingsBulkUpdate($hash, "daily_total", sprintf("%.3f", $key2->{'energy'}));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
$total = $total+ $key2->{'energy_wh'};
|
else {
|
||||||
|
$total = $total + $key2->{'energy_wh'};
|
||||||
if ($key2->{'day'} == $mday) {
|
if ($key2->{'day'} == $mday) {
|
||||||
readingsBulkUpdate($hash, "daily_total", sprintf("%.3f", $key2->{'energy_wh'}*0.001));
|
readingsBulkUpdate($hash, "daily_total", sprintf("%.3f", $key2->{'energy_wh'} * 0.001));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
my $count=1;
|
my $count = 1;
|
||||||
$count = @{$json->{'emeter'}->{'get_daystat'}->{'day_list'}};
|
$count = @{$json->{'emeter'}->{'get_daystat'}->{'day_list'}};
|
||||||
if ($hw_ver eq "1.0") {readingsBulkUpdate($hash, "monthly_total", $total);}
|
if ($hw_ver eq "1.0") {readingsBulkUpdate($hash, "monthly_total", $total);}
|
||||||
if ($hw_ver eq "2.0") {readingsBulkUpdate($hash, "monthly_total", $total*0.001);}
|
if ($hw_ver eq "2.0") {readingsBulkUpdate($hash, "monthly_total", $total * 0.001);}
|
||||||
if ($count) { readingsBulkUpdate($hash, "daily_average", $total/$count)};
|
if ($count) {readingsBulkUpdate($hash, "daily_average", $total / $count)};
|
||||||
Log3 $hash, 2, "TPLinkHS110: $name Daystat updated";
|
Log3 $hash, 2, "TPLinkHS110: $name Daystat updated";
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Log3 $hash, 1, "TPLinkHS110: $name Error updating daystat. Success: " . $success . ", json: " . $json;
|
Log3 $hash, 1, "TPLinkHS110: $name Error updating daystat. Success: " . $success . ", json: " . $json;
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name Updating readings";
|
Log3 $hash, 3, "TPLinkHS110: $name Updating readings";
|
||||||
readingsEndUpdate($hash, 1);
|
readingsEndUpdate($hash, 1);
|
||||||
@ -255,22 +319,19 @@ sub TPLinkHS110_Get($$)
|
|||||||
|
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Set($$)
|
sub TPLinkHS110_Set($$) {
|
||||||
{
|
my ($hash, $name, $cmd, @args) = @_;
|
||||||
my ( $hash, $name, $cmd, @args ) = @_;
|
|
||||||
my $cmdList = "on off";
|
my $cmdList = "on off";
|
||||||
my($success,$json,$realtimejson);
|
my ($success, $json, $realtimejson);
|
||||||
return "\"set $name\" needs at least one argument" unless(defined($cmd));
|
return "\"set $name\" needs at least one argument" unless (defined($cmd));
|
||||||
return if ($attr{$name}{"disable"} eq "1");
|
return if ($attr{$name}{"disable"} eq "1");
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name Set <". $cmd ."> called" if ($cmd !~ /\?/);
|
Log3 $hash, 3, "TPLinkHS110: $name Set <" . $cmd . "> called" if ($cmd !~ /\?/);
|
||||||
|
|
||||||
my $command="";
|
my $command = "";
|
||||||
if($cmd eq "on")
|
if ($cmd eq "on") {
|
||||||
{
|
|
||||||
$command = '{"system":{"set_relay_state":{"state":1}}}';
|
$command = '{"system":{"set_relay_state":{"state":1}}}';
|
||||||
}
|
}
|
||||||
elsif($cmd eq "off")
|
elsif ($cmd eq "off") {
|
||||||
{
|
|
||||||
$command = '{"system":{"set_relay_state":{"state":0}}}';
|
$command = '{"system":{"set_relay_state":{"state":0}}}';
|
||||||
}
|
}
|
||||||
else # wenn der übergebene Befehl nicht durch X_Set() verarbeitet werden kann, Weitergabe an SetExtensions
|
else # wenn der übergebene Befehl nicht durch X_Set() verarbeitet werden kann, Weitergabe an SetExtensions
|
||||||
@ -278,35 +339,31 @@ sub TPLinkHS110_Set($$)
|
|||||||
return SetExtensions($hash, $cmdList, $name, $cmd, @args);
|
return SetExtensions($hash, $cmdList, $name, $cmd, @args);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $remote_host = $hash->{HOST};
|
my $errmsg;
|
||||||
my $remote_port = 9999;
|
|
||||||
my $c = encrypt($command);
|
|
||||||
my $socket = IO::Socket::INET->new(PeerAddr => $remote_host,
|
|
||||||
PeerPort => $remote_port,
|
|
||||||
Proto => 'tcp',
|
|
||||||
Type => SOCK_STREAM,
|
|
||||||
Timeout => $hash->{TIMEOUT})
|
|
||||||
or return "Couldn't connect to $remote_host:$remote_port: $@\n";
|
|
||||||
$socket->write($c);
|
|
||||||
IO::Socket::Timeout->enable_timeouts_on($socket);
|
|
||||||
$socket->read_timeout(.5);
|
|
||||||
my $data;
|
my $data;
|
||||||
$data = <$socket>;
|
|
||||||
$socket->close();
|
($errmsg, $data) = TPLinkHS110_SendCommand($hash, $command);
|
||||||
|
if (defined($errmsg)) {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name Set failed - " . $errmsg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
readingsBeginUpdate($hash);
|
readingsBeginUpdate($hash);
|
||||||
$data = decrypt(substr($data,4));
|
|
||||||
|
|
||||||
($success,$json) = TPLinkHS110__evaljson($name,$data);
|
($success, $json) = TPLinkHS110__evaljson($name, $data);
|
||||||
if(!$success) {
|
if (!$success) {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name Set failed - parsing";
|
||||||
readingsEndUpdate($hash, 1);
|
readingsEndUpdate($hash, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($json->{'system'}->{'set_relay_state'}->{'err_code'} eq "0") {
|
if ($json->{'system'}->{'set_relay_state'}->{'err_code'} eq "0") {
|
||||||
TPLinkHS110_Get($hash,"");
|
Log3 $hash, 3, "TPLinkHS110: $name Set OK - get status data";
|
||||||
|
TPLinkHS110_Get($hash, "");
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
Log3 $hash, 1, "TPLinkHS110: $name Set failed with error code";
|
||||||
return "Command failed!";
|
return "Command failed!";
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
@ -314,10 +371,9 @@ sub TPLinkHS110_Set($$)
|
|||||||
|
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Undefine($$)
|
sub TPLinkHS110_Undefine($$) {
|
||||||
{
|
|
||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
my $name= $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name undefined.";
|
Log3 $hash, 3, "TPLinkHS110: $name undefined.";
|
||||||
return;
|
return;
|
||||||
@ -327,7 +383,7 @@ sub TPLinkHS110_Undefine($$)
|
|||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Delete {
|
sub TPLinkHS110_Delete {
|
||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
my $name= $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name deleted.";
|
Log3 $hash, 3, "TPLinkHS110: $name deleted.";
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -335,13 +391,14 @@ sub TPLinkHS110_Delete {
|
|||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub TPLinkHS110_Attr {
|
sub TPLinkHS110_Attr {
|
||||||
my ($cmd,$name,$aName,$aVal) = @_;
|
my ($cmd, $name, $aName, $aVal) = @_;
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
if ($aName eq "interval") {
|
if ($aName eq "interval") {
|
||||||
if ($cmd eq "set") {
|
if ($cmd eq "set") {
|
||||||
$hash->{INTERVAL} = $aVal;
|
$hash->{INTERVAL} = $aVal;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
$hash->{INTERVAL} = 300;
|
$hash->{INTERVAL} = 300;
|
||||||
}
|
}
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name INTERVAL set to " . $hash->{INTERVAL};
|
Log3 $hash, 3, "TPLinkHS110: $name INTERVAL set to " . $hash->{INTERVAL};
|
||||||
@ -350,7 +407,8 @@ sub TPLinkHS110_Attr {
|
|||||||
if ($aName eq "timeout") {
|
if ($aName eq "timeout") {
|
||||||
if ($cmd eq "set") {
|
if ($cmd eq "set") {
|
||||||
$hash->{TIMEOUT} = $aVal;
|
$hash->{TIMEOUT} = $aVal;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
$hash->{TIMEOUT} = 1;
|
$hash->{TIMEOUT} = 1;
|
||||||
}
|
}
|
||||||
Log3 $hash, 3, "TPLinkHS110: $name TIMEOUT set to " . $hash->{TIMEOUT};
|
Log3 $hash, 3, "TPLinkHS110: $name TIMEOUT set to " . $hash->{TIMEOUT};
|
||||||
@ -384,7 +442,7 @@ sub TPLinkHS110_Attr {
|
|||||||
my $data;
|
my $data;
|
||||||
$data = <$socket>;
|
$data = <$socket>;
|
||||||
$socket->close();
|
$socket->close();
|
||||||
$data = decrypt(substr($data,4));
|
$data = decrypt(substr($data, 4));
|
||||||
my $json;
|
my $json;
|
||||||
eval {
|
eval {
|
||||||
$json = decode_json($data);
|
$json = decode_json($data);
|
||||||
@ -401,8 +459,8 @@ sub TPLinkHS110_Attr {
|
|||||||
# Based on https://www.softscheck.com/en/reverse-engineering-tp-link-hs110/
|
# Based on https://www.softscheck.com/en/reverse-engineering-tp-link-hs110/
|
||||||
sub encrypt {
|
sub encrypt {
|
||||||
my $key = 171;
|
my $key = 171;
|
||||||
my @string=split(//, $_[0]);
|
my @string = split(//, $_[0]);
|
||||||
my $result = "\0\0\0".chr(@string);
|
my $result = "\0\0\0" . chr(@string);
|
||||||
foreach (@string) {
|
foreach (@string) {
|
||||||
my $a = $key ^ ord($_);
|
my $a = $key ^ ord($_);
|
||||||
$key = $a;
|
$key = $a;
|
||||||
@ -410,10 +468,11 @@ sub encrypt {
|
|||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub decrypt {
|
sub decrypt {
|
||||||
my $key = 171;
|
my $key = 171;
|
||||||
my $result = "";
|
my $result = "";
|
||||||
my @string=split(//, $_[0]);
|
my @string = split(//, $_[0]);
|
||||||
foreach (@string) {
|
foreach (@string) {
|
||||||
my $a = $key ^ ord($_);
|
my $a = $key ^ ord($_);
|
||||||
$key = ord($_);
|
$key = ord($_);
|
||||||
@ -462,28 +521,29 @@ sub hwMapping {
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Test ob JSON-String empfangen wurde
|
# Test ob JSON-String empfangen wurde
|
||||||
sub TPLinkHS110__evaljson($$) {
|
sub TPLinkHS110__evaljson($$) {
|
||||||
my ($name,$data)= @_;
|
my ($name, $data) = @_;
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
my $json;
|
my $json;
|
||||||
my $success = 1;
|
my $success = 1;
|
||||||
my $jerr = "ok";
|
my $jerr = "ok";
|
||||||
|
|
||||||
Log3 $name, 5, "$name - Data returned: ". Dumper $data;
|
Log3 $name, 5, "$name - Data returned: " . Dumper $data;
|
||||||
eval {$json = decode_json($data);} or do
|
eval {$json = decode_json($data);} or do
|
||||||
{
|
{
|
||||||
$success = 0;
|
$success = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
if($@) {
|
if ($@) {
|
||||||
$jerr = $@;
|
$jerr = $@;
|
||||||
};
|
};
|
||||||
|
|
||||||
readingsBulkUpdate($hash, "decode_json", $jerr);
|
readingsBulkUpdate($hash, "decode_json", $jerr);
|
||||||
|
|
||||||
if($success) {
|
if ($success) {
|
||||||
return($success,$json);
|
return($success, $json);
|
||||||
} else {
|
}
|
||||||
return($success,undef);
|
else {
|
||||||
|
return($success, undef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user