Merge pull request #17 from T0RST3N/devel

close #16
close #15
close #14
close #13

-change: the sensors now align themselves with their real gateway (iodev)
-change: the ne aqara cube is supportet but the firmware has an bug
-change batteryreadings changed to FHEM standard
This commit is contained in:
2018-07-02 08:51:50 +02:00
committed by GitHub
3 changed files with 149 additions and 114 deletions

View File

@@ -42,7 +42,6 @@ eval "use Net::Ping";
return "\nERROR: Please install Net::Ping" if($@);
use Color;
use SetExtensions;
@@ -52,7 +51,7 @@ sub XiaomiSmartHome_Notify($$);
sub XiaomiSmartHome_updateSingleReading($$);
my $iv="\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58\x56\x2e";
my $version = "1.20";
my $version = "1.30";
my %XiaomiSmartHome_gets = (
"getDevices" => ["get_id_list", '^.+get_id_list_ack' ],
@@ -93,7 +92,7 @@ sub XiaomiSmartHome_Initialize($) {
"2:XiaomiSmartHome_Device" => ".*motion.*",
"3:XiaomiSmartHome_Device" => "^.+sensor_ht",
"4:XiaomiSmartHome_Device" => ".*switch.*",
"5:XiaomiSmartHome_Device" => "^.+cube",
"5:XiaomiSmartHome_Device" => ".*cube.*",
"6:XiaomiSmartHome_Device" => "^.+plug",
"7:XiaomiSmartHome_Device" => "^.+86sw1",
"8:XiaomiSmartHome_Device" => "^.+86sw2",
@@ -143,12 +142,37 @@ sub XiaomiSmartHome_Read($) {
}
if ($json)
{
Log3 $name, 5, "$name: Read> " . $buf;
Log3 $name, 5, "$name: Read> [PLAIN] " . $buf;
my $rsid = $decoded->{'sid'};
if ($decoded->{'cmd'} eq 'read_ack' || $decoded->{'cmd'} eq 'report' && $decoded->{'model'} ne 'gateway'|| $decoded->{'cmd'} eq 'heartbeat' && $decoded->{'model'} ne 'gateway' || $decoded->{'cmd'} eq 'write_ack' && $decoded->{'model'} ne 'gateway') {
Log3 $name, 5, "$name: Read> Dispatch " . $buf;
if (!$modules{XiaomiSmartHome_Device}{defptr}{$rsid}{IODev}->{NAME}){
Log3 $name, 5, "$name: Read> XiaomiSmartHome_Device unknown trying autocreate" ;
my $def=$modules{XiaomiSmartHome}{defptr};
while(my ($key, $value) =each(%$def)){
XiaomiSmartHome_Write($value, 'get_id_list');
Log3 $value->{NAME}, 5, "$value->{NAME}: Push to get all Sensors for Gateway $value->{NAME} " . $key;
if ($value->{helper}{sensors} =~ m/$rsid/ ) {
Log3 $value->{NAME}, 5, "$value->{NAME}: $rsid is sensor from $value->{NAME}";
Dispatch($value, $buf, undef);
return;
}
}
}
if ($modules{XiaomiSmartHome_Device}{defptr}{$rsid}{IODev}->{NAME} eq $hash->{NAME}) {
Log3 $name, 5, "$name: Read> XiaomiSmartHome_Device known! " . "SID: " . $rsid . " " . $modules{XiaomiSmartHome_Device}{defptr}{$rsid}{IODev}->{NAME} . " " . $hash->{NAME};
}
elsif ($modules{XiaomiSmartHome_Device}{defptr}{$rsid}{IODev}->{NAME} ne $hash->{NAME}) {
Log3 $name, 5, "$name: Read> Wrong Modul HASH Trying to find the right one " . $modules{XiaomiSmartHome_Device}{defptr}{$rsid}{IODev}->{NAME} . " <> " . $hash->{NAME} ;
$hash = $modules{XiaomiSmartHome_Device}{defptr}{$rsid}->{IODev};
Log3 $name, 5, "$name: Read> Using this GW " . $hash->{NAME};
}
Log3 $name, 5, "$name: Read> Dispatching " . $buf . " " . $hash->{NAME};
Dispatch($hash, $buf, undef);
}
}
elsif (!$modules{XiaomiSmartHome}{defptr}{$rsid}){
Log3 $name, 1, "$name: Read> GW not defined " . $buf;
return;
}
elsif ( $modules{XiaomiSmartHome}{defptr}{$rsid}->{SID} ne $hash->{SID} ){
$self = $modules{XiaomiSmartHome}{defptr}{$rsid};
Log3 $name, 5, "$name: Read> Change HASH Ref to $self->{NAME}";
@@ -208,7 +232,7 @@ sub XiaomiSmartHome_Reading ($@) {
#$hash->{SID} = $decoded->{'sid'};
}
else {
Log3 $name, 4, "$name: Reading> IP-Heartbeat Data didnt match! $data->{ip} " . $hash->{GATEWAY_IP} ;
Log3 $name, 5, "$name: Reading> IP-Heartbeat Data didnt match! $data->{ip} " . $hash->{GATEWAY_IP} ;
}
}
}
@@ -244,11 +268,14 @@ sub XiaomiSmartHome_Reading ($@) {
Log3 $name, 1, "$name: Reading> Error while request: $@";
return;
}
my $all_sensors = "";
foreach my $sensor (@sensors)
{
Log3 $name, 4, "$name: Reading> PushRead:" . $sensor;
XiaomiSmartHome_Write($hash, 'read', $sensor );
$all_sensors = $all_sensors . $sensor . ",";
}
$hash->{helper}{sensors} = $all_sensors;
return;
}
}
@@ -295,14 +322,14 @@ sub XiaomiSmartHome_getGatewaySID($){
}
if ($json) {
if ($decoded->{'ip'} eq $ip){
Log3 $name, 4, "$name: getGatewaySID> Find SID for Gateway: $decoded->{sid}";
Log3 $name, 3, "$name: getGatewaySID> Find SID for Gateway: $decoded->{sid}";
$sidsock->close();
$hash->{SID} = $decoded->{sid};
$modules{XiaomiSmartHome}{defptr}{$decoded->{sid}} = $hash;
return $decoded->{sid};
}
else {
Log3 $name, 4, "$name: getGatewaySID> whois Data didnt match! $decoded->{sid} $decoded->{'ip'} ". $ip ;
Log3 $name, 5, "$name: getGatewaySID> whois Data didnt match! $decoded->{sid} $decoded->{'ip'} ". $ip ;
}
}
};
@@ -335,7 +362,7 @@ sub XiaomiSmartHome_Define($$) {
if ( ! $p->ping($param[2])){
$hash->{STATE} = "Disconnected";
XiaomiSmartHome_disconnect($hash);
Log3 $name, 5, "$name: Define> Ping ERROR Gateway disconnecting";
Log3 $name, 1, "$name: Define> Ping ERROR Gateway disconnecting";
$p->close();
}
my $GATEWAY_IP = $param[2];
@@ -363,7 +390,7 @@ sub XiaomiSmartHome_Define($$) {
}
}
$hash->{GATEWAY_IP} = $GATEWAY_IP;
$modules{XiaomiSmartHome}{defptr}{$GATEWAY_IP} = $hash;
#$modules{XiaomiSmartHome}{defptr}{$GATEWAY_IP} = $hash;
#$hash->{SID} = XiaomiSmartHome_getGatewaySID($hash);
Log3 $name, 5, "$name: Define> $definition";
@@ -496,7 +523,7 @@ sub XiaomiSmartHome_Write($@)
my $sock = $hash->{CD};
my $MAXLEN = 1024;
$sock->mcast_send($msg,$GATEWAY .':9898') or die "send: $!";
Log3 $name, 5, "$name: Write> End " . $GATEWAY;
Log3 $name, 4, "$name: Write> End " . $GATEWAY;
return undef;
}
#####################################
@@ -527,12 +554,14 @@ sub XiaomiSmartHome_Get($@)
if ($opt eq "UpdateAll")
{
XiaomiSmartHome_updateAllReadings($hash);
Log3 $name, 5, "$name: Get> UpdateALLReadings Started";
Log3 $name, 3, "$name: Get> UpdateALLReadings Started";
return "UpdateALLReadings Started";
}
elsif($opt eq "UpdateSingle")
{
XiaomiSmartHome_updateSingleReading($hash,$args);
Log3 $name, 5, "$name: Get> UpdateSingel Started";
Log3 $name, 3, "$name: Get> UpdateSingel Started";
return "UpdateSingel " . $args . " Started";
}
else
{
@@ -699,8 +728,6 @@ sub XiaomiSmartHome_connect($)
my $name = $hash->{NAME};
my $GATEWAY_IP;
Log3 $name, 5, "$name: connect> ConnectStart";
Log3 $name, 4, "$name: connecting";
my $p = Net::Ping->new();
if ( ! $p->ping($hash->{GATEWAY})){
Log3 $name, 1, "$name: connect> Ping to $hash->{helper}{host} failed";
@@ -713,7 +740,7 @@ sub XiaomiSmartHome_connect($)
eval {
$GATEWAY_IP = inet_ntoa(inet_aton($hash->{GATEWAY})) ;
$hash->{GATEWAY_IP} = $GATEWAY_IP;
Log3 $name, 4, "$name: Connect> Set GATEWAYs IP: " . $GATEWAY_IP;
Log3 $name, 5, "$name: Connect> Set GATEWAYs IP: " . $GATEWAY_IP;
};
if ($@) {
Log3 $name, 1, "$name: Connect> Error $@\n";
@@ -724,12 +751,12 @@ sub XiaomiSmartHome_connect($)
}
XiaomiSmartHome_getGatewaySID($hash);
my $timeout = $hash->{TIMEOUT} ? $hash->{TIMEOUT} : 3;
my $sock = IO::Socket::Multicast->new( Proto => 'udp', LocalPort =>'9898', ReuseAddr => 1, Timeout => $timeout) or die "Creating socket: $!\n";
my $sock = IO::Socket::Multicast->new( Proto => 'udp', LocalPort =>'9898', ReusePort => 1, ReuseAddr => 1, Timeout => $timeout) or die "Creating socket: $!\n";
$sock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0)) or die "setsockopt: $!";
if ($sock)
{
Log3 $name, 4, "$name: connect> Connected";
$sock->mcast_add('224.0.0.50', $hash->{fhemIP} ) || die "Couldn't set group: $!\n"; #$hash->{fhemIP}
Log3 $name, 3, "$name: connect> Connected";
$sock->mcast_add('224.0.0.50', $hash->{FHEMIP} ) || die "Couldn't set group: $!\n"; #$hash->{FHEMIP}
$sock->mcast_ttl(32);
$sock->mcast_loopback(1);
$hash->{helper}{ConnectionState} = "Connected";
@@ -800,7 +827,7 @@ sub XiaomiSmartHome_updateAllReadings($)
my $GATEWAY;
my $p = Net::Ping->new();
if ( ! $p->ping($hash->{GATEWAY})){
Log3 $name, 4, "$name: updateAllReadings> Ping to $hash->{helper}{host} failed";
Log3 $name, 1, "$name: updateAllReadings> Ping to $hash->{helper}{host} failed";
$hash->{STATE} = "Disconnected";
XiaomiSmartHome_disconnect($hash);
$p->close();
@@ -1047,6 +1074,3 @@ sub XiaomiSmartHome_updateAllReadings($)
=cut

View File

@@ -27,7 +27,7 @@ use warnings;
my $version = "1.20";
my $version = "1.30";
sub XiaomiSmartHome_Device_updateSReading($);
@@ -38,19 +38,18 @@ sub XiaomiSmartHome_Device_Initialize($)
{
my ($hash) = @_;
$hash->{Match} = ".*magnet.*|.*motion.*|sensor_ht|.*switch.*|plug|cube|86sw1|86sw2|ctrl_neutral1|ctrl_neutral2|rgbw_light|curtain|ctrl_ln1|ctrl_ln2|86plug|natgas|smoke|weather.v1|sensor_wleak.aq1";
$hash->{Match} = ".*magnet.*|.*motion.*|sensor_ht|.*switch.*|plug|.*cube.*|86sw1|86sw2|ctrl_neutral1|ctrl_neutral2|rgbw_light|curtain|ctrl_ln1|ctrl_ln2|86plug|natgas|smoke|weather.v1|sensor_wleak.aq1";
$hash->{DefFn} = "XiaomiSmartHome_Device_Define";
$hash->{SetFn} = "XiaomiSmartHome_Device_Set";
$hash->{UndefFn} = "XiaomiSmartHome_Device_Undef";
$hash->{ParseFn} = "XiaomiSmartHome_Device_Parse";
$hash->{AttrList} = "IODev follow-on-for-timer:1,0 follow-on-timer ".
$hash->{AttrList} = "follow-on-for-timer:1,0 follow-on-timer ".
"do_not_notify:1,0 ignore:1,0 dummy:1,0 showtime:1,0 valueFn:textField-long ".
"rnd_tmp:1,2,3 ".
"rnd_hum:1,2,3 ".
"rnd_bat:1,2,3 ".
"rnd_tmp:0,1,2,3 ".
"rnd_hum:0,1,2,3 ".
"rnd_bat:0,1,2,3 ".
"rnd_pres:0,1,2,3 ".
$readingFnAttributes ;
}
#####################################
@@ -202,6 +201,7 @@ sub XiaomiSmartHome_Device_Read($$$){
my $XMIround_tmp = AttrVal( $hash->{NAME}, "rnd_tmp", "2" );
my $XMIround_hum = AttrVal( $hash->{NAME}, "rnd_hum", "2" );
my $XMIround_bat = AttrVal( $hash->{NAME}, "rnd_bat", "1" );
my $XMIround_pres = AttrVal( $hash->{NAME}, "rnd_pres", "2" );
my $decoded = eval{decode_json($msg)};
if ($@) {
@@ -241,13 +241,13 @@ sub XiaomiSmartHome_Device_Read($$$){
my $bat = ($data->{voltage}/1000);
Log3 $name, 4, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Voltage: " . $data->{voltage};
if ($bat < 2.2) {
readingsBulkUpdate($hash, "battery", "low", 1 );
readingsBulkUpdate($hash, "batteryState", "low", 1 );
}
else {
readingsBulkUpdate($hash, "battery", "ok", 1 )
readingsBulkUpdate($hash, "batteryState", "ok", 1 )
}
$bat = XiaomiSmartHome_round($bat, $XMIround_bat, $name );
readingsBulkUpdate($hash, "battery_level", $bat, 1 );
readingsBulkUpdate($hash, "batteryVoltage", $bat, 1 );
}
if (defined $data->{temperature}){
if ($data->{temperature} ne "10000"){
@@ -271,7 +271,8 @@ sub XiaomiSmartHome_Device_Read($$$){
if ($data->{pressure} ne "0"){
my $pres = $data->{pressure};
$pres =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1./g;
Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Pressure: " . $pres;
$pres = XiaomiSmartHome_round($pres, $XMIround_pres, $name );
Log3 $name, 3, "$name: DEV_Read>" . " Name: " . $hash->{NAME} . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Pressure: " . $pres . " Round: " . $XMIround_pres;
readingsBulkUpdate($hash, "pressure", "$pres", 1 );
}
}
@@ -383,15 +384,17 @@ sub XiaomiSmartHome_Device_Parse($$) {
}
my $sid = $decoded->{'sid'};
my $model = $decoded->{'model'};
if (my $hash = $modules{XiaomiSmartHome_Device}{defptr}{$sid})
if ($modules{XiaomiSmartHome_Device}{defptr}{$sid}{IODev}->{NAME})
{
Log3 $name, 4, "$name: DEV_Parse> IS DEFINED " . $model . " : " .$sid;
my $hash = $modules{XiaomiSmartHome_Device}{defptr}{$sid}->{IODev};
Log3 $name, 5, "$name: DEV_Parse> IS DEFINED " . $model . " : " . $sid . " " . $modules{XiaomiSmartHome_Device}{defptr}{$sid}->{IODev};
$hash = $modules{XiaomiSmartHome_Device}{defptr}{$sid};
XiaomiSmartHome_Device_Read($hash, $msg, $name);
}
else
{
Log3 $name, 4, "$name: DEV_Parse> UNDEFINED " . $model . " : " .$sid;
Log3 $name, 1, "$name: DEV_Parse> UNDEFINED " . $model . " : " .$sid;
return "UNDEFINED XMI_$sid XiaomiSmartHome_Device $sid $model $name";
}
}
@@ -418,7 +421,10 @@ sub XiaomiSmartHome_Device_update($){
# Update delete old reading voltage & batterystate
CommandDeleteReading( undef, "$name voltage" ) if(defined(ReadingsVal($name,"voltage",undef)));
CommandDeleteReading( undef, "$name batterystate" ) if(defined(ReadingsVal($name,"batterystate",undef)));
CommandDeleteReading( undef, "$name round" ) if(defined(ReadingsVal($name,"round",undef)));
CommandDeleteReading( undef, "$name round" ) if(defined(ReadingsVal($name,"round",undef)));
CommandDeleteReading( undef, "$name battery_level" ) if(defined(ReadingsVal($name,"battery_level",undef)));
CommandDeleteReading( undef, "$name battery" ) if(defined(ReadingsVal($name,"battery",undef)));
CommandDeleteReading( undef, "$name batteryLevel" ) if(defined(ReadingsVal($name,"batteryLevel",undef)));
}
#####################################
@@ -444,14 +450,16 @@ sub XiaomiSmartHome_Device_Define($$) {
}
$iodev = $hash->{IODev}->{NAME};
my $d = $modules{XiaomiSmartHome_Device}{defptr}{$name};
my $d = $modules{XiaomiSmartHome_Device}{defptr}{$sid};
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->{SID}." if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{SID} ne $sid );
Log3 $name, 4, $iodev . ": DEV_Define> " . $name . ": defined as ". $hash->{MODEL};
$attr{$name}{room} = $room if( !defined( $attr{$name}{room} ) );
if( $type =~ /motion/) {
readingsSingleUpdate($hash, "state", "motion", 1 ) 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} ) );
}
elsif ( $type =~ /magnet/) {
$attr{$name}{devStateIcon} = 'open:fts_door_open@red close:fts_door@green' if( !defined( $attr{$name}{devStateIcon} ) );
@@ -486,9 +494,11 @@ sub XiaomiSmartHome_Device_Undef($)
my ($hash, $arg) = @_;
my $name = $hash->{NAME};
my $iodev = $hash->{IODev}->{NAME};
my $sid = $hash->{SID};
RemoveInternalTimer($hash);
delete($modules{XiaomiSmartHome_Device}{defptr}{$hash->{SID}});
Log3 $name, 4, "$iodev: DEV_Undef> $name - device deleted";
Log3 $name, 1, "$iodev: DEV_Undef> ". $hash->{SID} . " > " . $modules{XiaomiSmartHome_Device}{defptr}{$hash->{SID}} . " > " . $sid ." > " . $modules{XiaomiSmartHome_Device}{defptr}{$sid};
my $error = delete ($modules{XiaomiSmartHome_Device}{defptr}{$sid});
Log3 $name, 1, "$iodev: DEV_Undef> $name - device deleted " . $error;
return undef;
}
@@ -502,8 +512,9 @@ sub XiaomiSmartHome_round {
$p ||= 0;
$n *= 10 ** $p;
$n = int($n + .5 * $sign);
Log3 $name, 5, "$name: DEV_Round>" . " Result_value: " . $n / 10**$p;
return $n / 10**$p;
my $res = sprintf( "%." . $p . "f", $n / 10**$p);
Log3 $name, 5, "$name: DEV_Round>" . " Result_value: " . $res;
return $res;
}

View File

@@ -1,2 +1,2 @@
UPD 2017-12-15_09:45:00 37305 FHEM/71_XiaomiSmartHome.pm
UPD 2017-12-15_09:46:40 28101 FHEM/71_XiaomiSmartHome_Device.pm
UPD 2018-06-22_13:29:31 38872 FHEM/71_XiaomiSmartHome.pm
UPD 2018-06-22_12:45:46 29142 FHEM/71_XiaomiSmartHome_Device.pm