Bugfix and code cleaning

fix: unkown command at device set.
fix : updateallreadings now using sub functions
change: device readings now with real names
This commit is contained in:
2017-05-01 13:09:07 +02:00
parent c0e41a0a52
commit 49c6a159ea
3 changed files with 78 additions and 98 deletions

View File

@@ -50,7 +50,7 @@ sub XiaomiSmartHome_Notify($$);
sub XiaomiSmartHome_updateSingleReading($$); sub XiaomiSmartHome_updateSingleReading($$);
sub XiaomiSmartHome_updateAllReadings($); sub XiaomiSmartHome_updateAllReadings($);
my $iv="\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58\x56\x2e"; my $iv="\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58\x56\x2e";
my $version = "0.18"; my $version = "0.20";
my %XiaomiSmartHome_gets = ( my %XiaomiSmartHome_gets = (
"getDevices" => ["get_id_list", '^.+get_id_list_ack' ], "getDevices" => ["get_id_list", '^.+get_id_list_ack' ],
@@ -117,12 +117,13 @@ sub XiaomiSmartHome_Read($) {
{ {
Log3 $name, 5, "$name: Read> " . $buf; Log3 $name, 5, "$name: Read> " . $buf;
readingsBeginUpdate( $hash ); readingsBeginUpdate( $hash );
if ($decoded->{'cmd'} eq 'read_ack' || $decoded->{'cmd'} eq 'report' && $decoded->{'model'} eq 'gateway' || $decoded->{'cmd'} eq 'heartbeat' && $decoded->{'model'} eq 'gateway' || $decoded->{'cmd'} eq 'write_ack'){ if ($decoded->{'cmd'} eq 'report' && $decoded->{'model'} eq 'gateway' || $decoded->{'cmd'} eq 'heartbeat' && $decoded->{'model'} eq 'gateway' || $decoded->{'cmd'} eq 'write_ack'){
readingsBeginUpdate( $hash );
if ($decoded->{'model'} && $decoded->{'model'} eq 'gateway' ){ if ($decoded->{'model'} && $decoded->{'model'} eq 'gateway' ){
if ($decoded->{'cmd'} eq 'report'){ if ($decoded->{'cmd'} eq 'report'){
my $data = decode_json($decoded->{data}); my $data = decode_json($decoded->{data});
if (defined $data->{rgb}){ if (defined $data->{rgb}){
Log3 $name, 4, "$name: Read>" . " SID: " . $decoded->{'sid'} . " Type: Gateway" . " RGB: " . $data->{rgb} ; Log3 $name, 3, "$name: Read>" . " SID: " . $decoded->{'sid'} . " Type: Gateway" . " RGB: " . $data->{rgb} ;
readingsBulkUpdate($hash, "RGB", $data->{rgb} , 1 ); readingsBulkUpdate($hash, "RGB", $data->{rgb} , 1 );
} }
} }
@@ -147,12 +148,23 @@ sub XiaomiSmartHome_Read($) {
readingsBulkUpdate($hash, 'heartbeat', "Write_OK", 1 ); readingsBulkUpdate($hash, 'heartbeat', "Write_OK", 1 );
} }
} }
readingsEndUpdate( $hash, 1 );
return;
} }
else { if ($decoded->{'cmd'} eq 'get_id_list_ack'){
Log3 $name, 4, "$name: Read> dispatch " . $buf; my @sensors = @{decode_json($decoded->{data})};
Dispatch($hash, $buf, undef); foreach my $sensor (@sensors)
} {
readingsEndUpdate( $hash, 1 ); Log3 $name, 4, "$name: Read> PushRead:" . $sensor;
XiaomiSmartHome_Write($hash, 'read', $sensor );
}
return;
}
Log3 $name, 4, "$name: Read> dispatch " . $buf;
Dispatch($hash, $buf, undef);
} }
} }
##################################### #####################################
@@ -199,10 +211,8 @@ sub XiaomiSmartHome_getGatewaySID($){
{ {
if ($decoded->{'sid'} ne '') if ($decoded->{'sid'} ne '')
{ {
Log3 $name, 3, "$name: Find SID for Gateway: $decoded->{'sid'}"; Log3 $name, 4, "$name: Find SID for Gateway: $decoded->{'sid'}";
return $decoded->{'sid'}; return $decoded->{'sid'};
# XiaomiSmartHome_connect($hash) if( $init_done);
} }
} }
else { else {
@@ -277,9 +287,8 @@ sub XiaomiSmartHome_Write($@)
XiaomiSmartHome_disconnect($hash); XiaomiSmartHome_disconnect($hash);
$p->close(); $p->close();
return undef; return undef;
} }
}
}
my $GATEWAY = inet_ntoa(inet_aton($hash->{GATEWAY})); my $GATEWAY = inet_ntoa(inet_aton($hash->{GATEWAY}));
$hash->{GATEWAY_IP} = $GATEWAY; $hash->{GATEWAY_IP} = $GATEWAY;
my $msg; my $msg;
@@ -287,31 +296,33 @@ sub XiaomiSmartHome_Write($@)
{ {
$msg = '{"cmd":"' .$cmd . '","sid":"' . $val . '"}'; $msg = '{"cmd":"' .$cmd . '","sid":"' . $val . '"}';
} }
else { if ($cmd eq 'get_id_list')
if ( $hash->{READINGS}{password}{VAL} !~ /^[a-zA-Z0-9]{16}$/ ) {
{ Log3 $name, 5, "$name: Write> Get all Sensors";
Log3 $name, 1, "$name: Write> Password not SET!"; $msg = '{"cmd" : "get_id_list"}';
readingsSingleUpdate($hash, "password", "giveaPassword!", 1); }
return "for $cmd, wrong password, it must be hex and 16 characters"; if ( $hash->{READINGS}{password}{VAL} !~ /^[a-zA-Z0-9]{16}$/ )
} {
else { Log3 $name, 1, "$name: Write> Password not SET!";
if ($cmd eq 'rgb') readingsSingleUpdate($hash, "password", "giveaPassword!", 1);
{ return "for $cmd, wrong password, it must be hex and 16 characters";
$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{SID} . '","short_id":0,"key":"8","data":"{\"rgb\":' . $val . ',\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }'; }
} else {
if ($cmd eq 'pct') if ($cmd eq 'rgb')
{ {
$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{SID} . '","short_id":0,"key":"8","data":"{\"rgb\":' . $val . ',\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }'; $msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{SID} . '","short_id":0,"key":"8","data":"{\"rgb\":' . $val . ',\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
} }
if ($cmd eq 'power') if ($cmd eq 'pct')
{ {
$msg = '{"cmd":"write","model":"plug","sid":"' . $iohash->{SID} . '","data":"{\"status\":\"' . $val . '\",\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }'; $msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{SID} . '","short_id":0,"key":"8","data":"{\"rgb\":' . $val . ',\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
} }
if ($cmd eq 'power')
{
$msg = '{"cmd":"write","model":"plug","sid":"' . $iohash->{SID} . '","data":"{\"status\":\"' . $val . '\",\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
}
} }
}
return Log3 $name, 4, "$name: Write> - socket not connected" unless($hash->{CD}); return Log3 $name, 4, "$name: Write> - socket not connected" unless($hash->{CD});
Log3 $name, 4, "$name: Write> $msg " . $GATEWAY;
Log3 $name, 3, "$name: Write> $msg " . $GATEWAY;
my $sock = $hash->{CD}; my $sock = $hash->{CD};
my $MAXLEN = 1024; my $MAXLEN = 1024;
$sock->mcast_send($msg,$GATEWAY .':9898') or die "send: $!"; $sock->mcast_send($msg,$GATEWAY .':9898') or die "send: $!";
@@ -593,7 +604,7 @@ sub XiaomiSmartHome_updateAllReadings($)
{ {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
Log3 $name, 5, "name> updateAllReadings> Starting UpdateALLReadings"; Log3 $name, 5, "$name> updateAllReadings> Starting UpdateALLReadings";
my $GATEWAY; my $GATEWAY;
my $p = Net::Ping->new(); my $p = Net::Ping->new();
if ( ! $p->ping($hash->{GATEWAY})){ if ( ! $p->ping($hash->{GATEWAY})){
@@ -626,37 +637,8 @@ sub XiaomiSmartHome_updateAllReadings($)
XiaomiSmartHome_connect($hash); XiaomiSmartHome_connect($hash);
return undef; return undef;
} }
my $sock = $hash->{CD};
my $MAXLEN = 1024; XiaomiSmartHome_Write($hash, 'get_id_list');
my $msg = '{"cmd" : "get_id_list"}';
$sock->mcast_send($msg, $GATEWAY .':9898') or die "send: $!";
eval {
$sock->recv($msg, $MAXLEN) or die "recv: $!";
Log3 $name, 5, "$name: updateAllReadings>" . $msg;
my $json = $hash->{helper}{JSON}->incr_parse($msg);
my $decoded = decode_json($msg);
if ($json){
Log3 $name, 5, "$name: updateAllReadings> Read:" . $msg;
if ($decoded->{'cmd'} eq 'get_id_list_ack'){
my @sensors = @{decode_json($decoded->{data})};
foreach my $sensor (@sensors)
{
$msg = '{"cmd":"read","sid":"' . $sensor . '" }';
Log3 $name, 4, "$name: updateAllReadings> PushRead:" . $sensor;
my $msg = '{"cmd":"read","sid":"' . $sensor . '" }';
$sock->mcast_send($msg, $GATEWAY .':9898') or die "send: $!";
eval {
$sock->recv($msg, $MAXLEN) or die "recv: $!";
Log3 $name, 5, "$name: updateAllReadings> " . $msg;
Dispatch($hash, $msg, undef);
}
}
}
}
}
#return undef;
} }
##################################### #####################################

View File

@@ -25,7 +25,7 @@ package main;
use strict; use strict;
use warnings; use warnings;
my $version = "0.19"; my $version = "0.20";
sub XiaomiSmartHome_Device_updateSReading($); sub XiaomiSmartHome_Device_updateSReading($);
@@ -52,8 +52,6 @@ sub XiaomiSmartHome_Device_mot($$)
my ($hash, $mot) = @_; my ($hash, $mot) = @_;
InternalTimer(gettimeofday()+$mot, "XiaomiSmartHome_Device_on_timeout",$hash, 0); InternalTimer(gettimeofday()+$mot, "XiaomiSmartHome_Device_on_timeout",$hash, 0);
# on-for-timer is now a on.
} }
##################################### #####################################
@@ -74,26 +72,27 @@ sub XiaomiSmartHome_Device_Set($@)
if($args[0] eq "on") if($args[0] eq "on")
{ {
IOWrite($hash,"power","on",$hash); IOWrite($hash,"power","on",$hash);
return;
} }
elsif($args[0] eq "off") elsif($args[0] eq "off")
{ {
IOWrite($hash,"power","off",$hash); IOWrite($hash,"power","off",$hash);
return;
} }
} }
if($cmd eq "open") # if($cmd eq "open")
{ # {
readingsSingleUpdate($hash, "state", "open", 1 ); # readingsSingleUpdate($hash, "state", "open", 1 );
return; # return;
} # }
if($cmd eq "motionOffTimer") if($cmd eq "motionOffTimer")
{ {
readingsSingleUpdate($hash, "motionOffTimer", "$args[0]", 1 );; readingsSingleUpdate($hash, "motionOffTimer", "$args[0]", 1 );;
return; return;
} }
else
{ return "Unknown argument $cmd, choose one of $setlist";
return "Unknown argument $cmd, choose one of $setlist";
}
} }
@@ -117,7 +116,7 @@ sub XiaomiSmartHome_Device_Read($$$){
my $data = decode_json($decoded->{data}); my $data = decode_json($decoded->{data});
readingsBeginUpdate( $hash ); readingsBeginUpdate( $hash );
if (defined $data->{status}){ if (defined $data->{status}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Status: " . $data->{status}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Status: " . $data->{status};
readingsBulkUpdate($hash, "state", "$data->{status}", 1 ); readingsBulkUpdate($hash, "state", "$data->{status}", 1 );
if ($data->{status} eq 'motion' && $hash->{MODEL} eq 'motion'){ if ($data->{status} eq 'motion' && $hash->{MODEL} eq 'motion'){
readingsBulkUpdate($hash, "no_motion", "0", 1 ); readingsBulkUpdate($hash, "no_motion", "0", 1 );
@@ -127,33 +126,33 @@ sub XiaomiSmartHome_Device_Read($$$){
} }
} }
if (defined $data->{no_motion}){ if (defined $data->{no_motion}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_motion: " . $data->{no_motion}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_motion: " . $data->{no_motion};
readingsBulkUpdate($hash, "no_motion", "$data->{no_motion}", 1 ); readingsBulkUpdate($hash, "no_motion", "$data->{no_motion}", 1 );
} }
if (defined $data->{no_close}){ if (defined $data->{no_close}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_close: " . $data->{no_close}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_close: " . $data->{no_close};
readingsBulkUpdate($hash, "no_close", "$data->{no_close}", 1 ); readingsBulkUpdate($hash, "no_close", "$data->{no_close}", 1 );
} }
if (defined $data->{voltage}){ if (defined $data->{voltage}){
my $bat = ($data->{voltage}/1000); my $bat = ($data->{voltage}/1000);
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Voltage: " . $data->{voltage}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Voltage: " . $data->{voltage};
readingsBulkUpdate($hash, "battery", $bat, 1 ); readingsBulkUpdate($hash, "battery", $bat, 1 );
} }
if (defined $data->{temperature}){ if (defined $data->{temperature}){
my $temp = $data->{temperature}; my $temp = $data->{temperature};
$temp =~ s/(^[-+]?\d+?(?=(?>(?:\d{2})+)(?!\d))|\G\d{2}(?=\d))/$1./g; $temp =~ s/(^[-+]?\d+?(?=(?>(?:\d{2})+)(?!\d))|\G\d{2}(?=\d))/$1./g;
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Temperature: " . $temp; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Temperature: " . $temp;
readingsBulkUpdate($hash, "temperature", "$temp", 1 ); readingsBulkUpdate($hash, "temperature", "$temp", 1 );
} }
if (defined $data->{humidity}){ if (defined $data->{humidity}){
my $hum = $data->{humidity}; my $hum = $data->{humidity};
$hum =~ s/(^[-+]?\d+?(?=(?>(?:\d{2})+)(?!\d))|\G\d{2}(?=\d))/$1./g; $hum =~ s/(^[-+]?\d+?(?=(?>(?:\d{2})+)(?!\d))|\G\d{2}(?=\d))/$1./g;
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Humidity: " . $hum; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Humidity: " . $hum;
readingsBulkUpdate($hash, "humidity", "$hum", 1 ); readingsBulkUpdate($hash, "humidity", "$hum", 1 );
} }
#86sw2 start #86sw2 start
if (defined $data->{channel_0}){ if (defined $data->{channel_0}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Channel_0: " . $data->{channel_0}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Channel_0: " . $data->{channel_0};
readingsBulkUpdate($hash, "channel_0", "$data->{channel_0}", 1 ); readingsBulkUpdate($hash, "channel_0", "$data->{channel_0}", 1 );
} }
if (defined $data->{channel_1}){ if (defined $data->{channel_1}){
@@ -163,25 +162,25 @@ sub XiaomiSmartHome_Device_Read($$$){
#86sw2 end #86sw2 end
#plug start #plug start
if (defined $data->{load_voltage}){ if (defined $data->{load_voltage}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Voltage: " . $data->{load_voltage}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Voltage: " . $data->{load_voltage};
readingsBulkUpdate($hash, "LOAD_Voltage", "$data->{load_voltage}", 1 ); readingsBulkUpdate($hash, "LOAD_Voltage", "$data->{load_voltage}", 1 );
} }
if (defined $data->{load_power}){ if (defined $data->{load_power}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Power: " . $data->{load_power}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Power: " . $data->{load_power};
readingsBulkUpdate($hash, "LOAD_Power", "$data->{load_power}", 1 ); readingsBulkUpdate($hash, "LOAD_Power", "$data->{load_power}", 1 );
} }
if (defined $data->{power_consumed}){ if (defined $data->{power_consumed}){
Log3 $name, 3, "$name:" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " POWER_Consumed: " . $data->{power_consumed}; Log3 $name, 3, "$name:" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " POWER_Consumed: " . $data->{power_consumed};
readingsBulkUpdate($hash, "POWER_Consumed", "$data->{power_consumed}", 1 ); readingsBulkUpdate($hash, "POWER_Consumed", "$data->{power_consumed}", 1 );
} }
if (defined $data->{inuse}){ if (defined $data->{inuse}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " InUse: " . $data->{inuse}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " InUse: " . $data->{inuse};
readingsBulkUpdate($hash, "inuse", "$data->{inuse}", 1 ); readingsBulkUpdate($hash, "inuse", "$data->{inuse}", 1 );
} }
#plug end #plug end
#cube start #cube start
if (defined $data->{rotate}){ if (defined $data->{rotate}){
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Rotate: " . $data->{rotate}; Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Rotate: " . $data->{rotate};
readingsBulkUpdate($hash, "rotate", "$data->{rotate}", 1 ); readingsBulkUpdate($hash, "rotate", "$data->{rotate}", 1 );
readingsBulkUpdate($hash, "state", "rotate", 1 ); readingsBulkUpdate($hash, "state", "rotate", 1 );
} }
@@ -244,7 +243,6 @@ sub XiaomiSmartHome_Device_update($){
sub XiaomiSmartHome_Device_Define($$) { sub XiaomiSmartHome_Device_Define($$) {
my ($hash, $def) = @_; my ($hash, $def) = @_;
my ($name, $modul, $sid, $type, $iodev) = split("[ \t]+", $def); my ($name, $modul, $sid, $type, $iodev) = split("[ \t]+", $def);
#Log3 "test", 3, "Define status = " . $status;
$hash->{TYPE} = $modul; $hash->{TYPE} = $modul;
$hash->{MODEL} = $type; $hash->{MODEL} = $type;
$hash->{SID} = $sid; $hash->{SID} = $sid;
@@ -256,7 +254,7 @@ sub XiaomiSmartHome_Device_Define($$) {
if(defined($hash->{IODev}->{NAME})) { if(defined($hash->{IODev}->{NAME})) {
my $IOname = $hash->{IODev}->{NAME}; my $IOname = $hash->{IODev}->{NAME};
Log3 $name, 3, $IOname . ": DEV_Define> " .$name. ": " . $type . " I/O device is " . $hash->{IODev}->{NAME}; Log3 $name, 4, $IOname . ": DEV_Define> " .$name. ": " . $type . " I/O device is " . $hash->{IODev}->{NAME};
} else { } else {
Log3 $name, 1, "$name DEV_Define> $type - no I/O device"; Log3 $name, 1, "$name DEV_Define> $type - no I/O device";
} }
@@ -266,7 +264,7 @@ sub XiaomiSmartHome_Device_Define($$) {
return "XiaomiSmartHome device $hash->{SID} on XiaomiSmartHome $iodev already defined as $d->{NAME}." if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name ); return "XiaomiSmartHome device $hash->{SID} on XiaomiSmartHome $iodev already defined as $d->{NAME}." if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
Log3 $name, 3, $iodev . ": DEV_Define> " . $name . ": defined as ". $hash->{MODEL}; Log3 $name, 4, $iodev . ": DEV_Define> " . $name . ": defined as ". $hash->{MODEL};
$attr{$name}{room} = "MiSmartHome" if( !defined( $attr{$name}{room} ) ); $attr{$name}{room} = "MiSmartHome" if( !defined( $attr{$name}{room} ) );
if( $type eq 'motion') { if( $type eq 'motion') {
$attr{$name}{devStateIcon} = 'motion:motion_detector@red off:motion_detector@green no_motion:motion_detector@green' if( !defined( $attr{$name}{devStateIcon} ) ); $attr{$name}{devStateIcon} = 'motion:motion_detector@red off:motion_detector@green no_motion:motion_detector@green' if( !defined( $attr{$name}{devStateIcon} ) );

View File

@@ -1,2 +1,2 @@
UPD 2017-04-28_20:38:35 22335 FHEM/71_XiaomiSmartHome.pm UPD 2017-05-01_12:08:08 22360 FHEM/71_XiaomiSmartHome.pm
UPD 2017-04-28_23:29:58 11418 FHEM/71_XiaomiSmartHome_Device.pm UPD 2017-05-01_11:32:24 11699 FHEM/71_XiaomiSmartHome_Device.pm