Many fixes and some new features
add: brightness support for gateway led add: support for swicht 86sw2 add: support gateway with hostname add: check missing perl modules fix: if no password set fix: gateway support if disconnects fix: gateway sid not anymore as reading change: voltage now battery for fhem battery control change: motionOffTime now as parameter
This commit is contained in:
@@ -23,20 +23,34 @@
|
||||
|
||||
package main;
|
||||
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use JSON qw( decode_json );
|
||||
use Data::Dumper;
|
||||
use IO::Socket;
|
||||
use IO::Socket::Multicast;
|
||||
use Crypt::CBC;
|
||||
|
||||
eval "use HTTP::Request::Common";
|
||||
return "\nERROR: Please install HTTP::Request::Common" if($@);
|
||||
eval "use JSON qw( decode_json )";
|
||||
return "\nERROR: Please install JSON qw( decode_json )" if($@);
|
||||
eval "use IO::Socket";
|
||||
return "\nERROR: Please install IO::Socket" if($@);
|
||||
eval "use IO::Socket::Multicast";
|
||||
return "\nERROR: Please install IO::Socket::Multicast" if($@);
|
||||
eval "use Crypt::CBC";
|
||||
return "\nERROR: Please install Crypt::CBC" if($@);
|
||||
eval "use Net::Ping";
|
||||
return "\nERROR: Please install Net::Ping" if($@);
|
||||
|
||||
use Color;
|
||||
use SetExtensions;
|
||||
|
||||
|
||||
|
||||
sub XiaomiSmartHome_Notify($$);
|
||||
sub XiaomiSmartHome_updateSingleReading($$);
|
||||
sub XiaomiSmartHome_updateAllReadings($);
|
||||
my $iv="\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58\x56\x2e";
|
||||
my $version = "0.10";
|
||||
my $version = "0.18";
|
||||
my %XiaomiSmartHome_gets = (
|
||||
"getDevices" => ["get_id_list", '^.+get_id_list_ack' ],
|
||||
|
||||
@@ -45,7 +59,7 @@ my %XiaomiSmartHome_gets = (
|
||||
my %sets = (
|
||||
"password" => 1,
|
||||
"rgb:colorpicker,RGB" => 1,
|
||||
#"pct:colorpicker,BRI,0,300,1300" =>1,
|
||||
"pct:colorpicker,BRI,0,1,100" => 1,
|
||||
"off" => 0,
|
||||
"on" => 0,
|
||||
);
|
||||
@@ -66,22 +80,23 @@ sub XiaomiSmartHome_Initialize($) {
|
||||
$hash->{ReadFn} = 'XiaomiSmartHome_Read';
|
||||
$hash->{WriteFn} = "XiaomiSmartHome_Write";
|
||||
$hash->{AttrList} = "disable:1,0 " .
|
||||
"Room " .
|
||||
$readingFnAttributes;
|
||||
|
||||
$hash->{MatchList} = { "1:XiaomiSmartHome_Device" => "^.+magnet",
|
||||
"2:XiaomiSmartHome_Device" => "^.+motion",
|
||||
"3:XiaomiSmartHome_Device" => "^.+sensor_ht",
|
||||
"4:XiaomiSmartHome_Device" => "^.+switch",
|
||||
"5:XiaomiSmartHome_Device" => "^.+cube",
|
||||
"6:XiaomiSmartHome_Device" => "^.+plug"};
|
||||
"5:XiaomiSmartHome_Device" => "^.+cube",
|
||||
"6:XiaomiSmartHome_Device" => "^.+plug",
|
||||
"7:XiaomiSmartHome_Device" => "^.+86sw2"};
|
||||
FHEM_colorpickerInit();
|
||||
}
|
||||
}
|
||||
#####################################
|
||||
|
||||
sub XiaomiSmartHome_Read($) {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
Log3 $name, 5, "$name: Read> Read start";
|
||||
my $buf = "";
|
||||
my $ret = sysread($hash->{CD}, $buf, 1024);
|
||||
if (!defined($ret) || $ret <= 0)
|
||||
@@ -94,27 +109,49 @@ sub XiaomiSmartHome_Read($) {
|
||||
|
||||
my $json = $hash->{helper}{JSON}->incr_parse($buf);
|
||||
my $decoded = decode_json($buf);
|
||||
if ( ! $decoded ) {
|
||||
Log3 $name, 4, "$name: Read> Error no JSON Data " . $buf;
|
||||
return;
|
||||
}
|
||||
if ($json)
|
||||
{
|
||||
Log3 $name, 5, "$name> Read:" . $buf;
|
||||
readingsBeginUpdate( $hash );
|
||||
if ($decoded->{'model'} eq 'gateway'){
|
||||
if ($decoded->{'cmd'} eq 'report'){
|
||||
my $data = decode_json($decoded->{data});
|
||||
if (defined $data->{rgb}){
|
||||
Log3 $name, 4, "$name>" . " SID: " . $decoded->{'sid'} . " Type: Gateway" . " RGB: " . $data->{rgb} ;
|
||||
readingsBulkUpdate($hash, "RGB", $data->{rgb} , 1 );
|
||||
Log3 $name, 5, "$name: Read> " . $buf;
|
||||
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->{'model'} && $decoded->{'model'} eq 'gateway' ){
|
||||
if ($decoded->{'cmd'} eq 'report'){
|
||||
my $data = decode_json($decoded->{data});
|
||||
if (defined $data->{rgb}){
|
||||
Log3 $name, 4, "$name: Read>" . " SID: " . $decoded->{'sid'} . " Type: Gateway" . " RGB: " . $data->{rgb} ;
|
||||
readingsBulkUpdate($hash, "RGB", $data->{rgb} , 1 );
|
||||
}
|
||||
}
|
||||
elsif ($decoded->{'cmd'} eq 'heartbeat'){
|
||||
my $data = decode_json($decoded->{data});
|
||||
if ($data->{ip} eq $hash->{GATEWAY_IP}){
|
||||
readingsBulkUpdate($hash, 'heartbeat', $decoded->{'sid'}, 1 );
|
||||
readingsBulkUpdate($hash, 'token', $decoded->{'token'}, 1 );
|
||||
}
|
||||
else {
|
||||
Log3 $name, 4, "$name: Read> IP-Heartbeat Data didnt match! $data->{ip} " . $hash->{GATEWAY_IP} ;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($decoded->{'cmd'} eq 'heartbeat'){
|
||||
readingsBulkUpdate($hash, 'HEARTBEAT', $decoded->{'sid'}, 1 );
|
||||
readingsBulkUpdate($hash, 'token', $decoded->{'token'}, 1 );
|
||||
if ($decoded->{'cmd'} eq 'write_ack'){
|
||||
Log3 $name, 4, "$name: Read> Write answer " . $hash->{GATEWAY} ;
|
||||
my $data = decode_json($decoded->{data});
|
||||
if ($data->{error}){
|
||||
readingsBulkUpdate($hash, 'heartbeat', $data->{error}, 1 );
|
||||
}
|
||||
else {
|
||||
readingsBulkUpdate($hash, 'heartbeat', "Write_OK", 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log3 $name, 4, "$name> Dispatch! " . $buf;
|
||||
Log3 $name, 4, "$name: Read> dispatch " . $buf;
|
||||
Dispatch($hash, $buf, undef);
|
||||
}
|
||||
}
|
||||
readingsEndUpdate( $hash, 1 );
|
||||
}
|
||||
}
|
||||
@@ -134,30 +171,82 @@ sub XiaomiSmartHome_getLocalIP(){
|
||||
}
|
||||
#####################################
|
||||
|
||||
sub XiaomiSmartHome_getGatewaySID($){
|
||||
my ($hash, $def) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $json;
|
||||
my $decoded;
|
||||
my $timeout = $hash->{TIMEOUT} ? $hash->{TIMEOUT} : 3;
|
||||
my $sidsock = IO::Socket::Multicast->new( Proto => 'udp',LocalAddr => $hash->{FHEMIP}, LocalPort =>'4321', ReuseAddr => 1, Timeout => $timeout) or die "Creating socket: $!\n";
|
||||
$sidsock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0)) or die "setsockopt: $!";
|
||||
if ($sidsock){
|
||||
my $msg = '{"cmd":"whois"}';
|
||||
$sidsock->mcast_send($msg,'224.0.0.50:4321') or die "send: $!";
|
||||
eval {
|
||||
$sidsock->recv($msg, 1024) or die "recv: $!";
|
||||
$json = $hash->{helper}{JSON}->incr_parse($msg);
|
||||
$decoded = decode_json($msg);
|
||||
$sidsock->close();
|
||||
};
|
||||
if ($@) {
|
||||
Log3 $name, 1, "$name: getGatewaySID> Error $@\n";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
if ($json)
|
||||
{
|
||||
if ($decoded->{'sid'} ne '')
|
||||
{
|
||||
Log3 $name, 3, "$name: Find SID for Gateway: $decoded->{'sid'}";
|
||||
return $decoded->{'sid'};
|
||||
# XiaomiSmartHome_connect($hash) if( $init_done);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log3 $name, 5, "$name: Did not find a SID for Gateway disconnecting";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
}
|
||||
}
|
||||
#####################################
|
||||
|
||||
sub XiaomiSmartHome_Define($$) {
|
||||
my ($hash, $def) = @_;
|
||||
my @param = split('[ \t]+', $def);
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
if(int(@param) < 3) {
|
||||
return "too few parameters: define <name> XiaomiSmartHome <GatewayIP>";
|
||||
}
|
||||
my $p = Net::Ping->new();
|
||||
if ( ! $p->ping($param[2])){
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
Log3 $name, 5, "$name: Ping ERROR Gateway disconnecting";
|
||||
$p->close();
|
||||
}
|
||||
my $definition = $param[2];
|
||||
|
||||
$hash->{DEF} = $definition;
|
||||
$hash->{NOTIFYDEV} = "global";
|
||||
$hash->{NAME} = $param[0];
|
||||
$hash->{VERSION} = $version;
|
||||
$hash->{GATEYWAY} = $param[2];
|
||||
$hash->{GATEWAY} = $param[2];
|
||||
$hash->{GATEWAY_IP} = $param[2];
|
||||
$hash->{helper}{JSON} = JSON->new->utf8();
|
||||
$hash->{FHEMIP} = XiaomiSmartHome_getLocalIP();
|
||||
$hash->{STATE} = "initialized";
|
||||
$hash->{helper}{host} = $definition;
|
||||
$hash->{helper}{JSON} = JSON->new->utf8();
|
||||
Log3 $hash->{NAME}, 5, "$hash->{NAME}> $definition";
|
||||
$attr{$hash->{NAME}}{webCmd} = "rgb:rgb ff0000:rgb 00ff00:rgb 0000ff:on:off";
|
||||
$hash->{SID} = XiaomiSmartHome_getGatewaySID($hash);
|
||||
$hash->{helper}{host} = $definition;
|
||||
Log3 $name, 5, "$name: $definition";
|
||||
# Define devStateIcon
|
||||
$attr{$hash->{NAME}}{devStateIcon} = '{Color_devStateIcon(ReadingsVal($name,"rgb","000000"))}' if(!defined($attr{$hash->{NAME}}{devStateIcon}));
|
||||
|
||||
$attr{$hash->{NAME}}{room} = "MiSmartHome" if( !defined( $attr{$hash->{NAME}}{room} ) );
|
||||
XiaomiSmartHome_connect($hash) if( $init_done);
|
||||
|
||||
InternalTimer(gettimeofday() + 5, "XiaomiSmartHome_connect", $hash, 0);
|
||||
|
||||
return undef;
|
||||
}
|
||||
@@ -176,35 +265,57 @@ sub XiaomiSmartHome_Write($@)
|
||||
{
|
||||
my ($hash,$cmd,$val,$iohash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
if ( $hash->{helper}{ConnectionState} eq 'Disconnected') {
|
||||
Log3 $name, 1, "$name: Write> Cannot write iam disconnected";
|
||||
return undef;
|
||||
}
|
||||
else{
|
||||
my $p = Net::Ping->new();
|
||||
if ( ! $p->ping($hash->{GATEWAY})){
|
||||
Log3 $name, 1, "$name: Write> Ping to $hash->{helper}{host} failed";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
$p->close();
|
||||
return undef;
|
||||
}
|
||||
|
||||
}
|
||||
my $GATEWAY = inet_ntoa(inet_aton($hash->{GATEWAY}));
|
||||
$hash->{GATEWAY_IP} = $GATEWAY;
|
||||
my $msg;
|
||||
if ($cmd eq 'read')
|
||||
if ($cmd eq 'read')
|
||||
{
|
||||
$msg = '{"cmd":"' .$cmd . '","sid":"' . $val . '"}';
|
||||
}
|
||||
if ($cmd eq 'rgb')
|
||||
{
|
||||
# TODO SID des Gateway nicht im und aus dem Reading!!
|
||||
$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{READINGS}{HEARTBEAT}{VAL} . '","short_id":0,"key":"8","data":"{\"rgb\":' . $val . ',\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
|
||||
|
||||
else {
|
||||
if ( $hash->{READINGS}{password}{VAL} !~ /^[a-zA-Z0-9]{16}$/ )
|
||||
{
|
||||
Log3 $name, 1, "$name: Write> Password not SET!";
|
||||
readingsSingleUpdate($hash, "password", "giveaPassword!", 1);
|
||||
return "for $cmd, wrong password, it must be hex and 16 characters";
|
||||
}
|
||||
else {
|
||||
if ($cmd eq 'rgb')
|
||||
{
|
||||
$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{SID} . '","short_id":0,"key":"8","data":"{\"rgb\":' . $val . ',\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
|
||||
}
|
||||
if ($cmd eq 'pct')
|
||||
{
|
||||
$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) .'\"}" }';
|
||||
}
|
||||
}
|
||||
if ($cmd eq 'illumination')
|
||||
{
|
||||
# TODO SID des Gateway nicht im und aus dem Reading!!
|
||||
#$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{READINGS}{HEARTBEAT}{VAL} . '","short_id":0,"key":"8","data":"{\"illumination\":\"' . $val . '\",\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
|
||||
$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{READINGS}{HEARTBEAT}{VAL} . '","short_id":0,"key":"8","data":"{\"mid\":\"3\",\"key\":\"'. XiaomiSmartHome_EncryptKey($hash) .'\"}" }';
|
||||
#$msg = '{"cmd":"write","model":"gateway","sid":"' . $hash->{READINGS}{HEARTBEAT}{VAL} . '","short_id":0,"key":"8","data":"{\"hue\":\"170\",\"saturation\":\"254\", \"color_temperature\":\"65279\", \"x\":\"10\", \"y\":\"10\",\"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, "Master ($name) - socket not connected" unless($hash->{CD});
|
||||
}
|
||||
return Log3 $name, 4, "$name: Write> - socket not connected" unless($hash->{CD});
|
||||
|
||||
Log3 $name, 4, "$name> $msg " . $hash->{GATEYWAY};
|
||||
Log3 $name, 3, "$name: Write> $msg " . $GATEWAY;
|
||||
my $sock = $hash->{CD};
|
||||
my $MAXLEN = 1024;
|
||||
$sock->mcast_send($msg,$hash->{GATEYWAY} .':9898') or die "send: $!";
|
||||
|
||||
$sock->mcast_send($msg,$GATEWAY .':9898') or die "send: $!";
|
||||
Log3 $name, 5, "$name: Write> End " . $GATEWAY;
|
||||
return undef;
|
||||
}
|
||||
#####################################
|
||||
@@ -212,13 +323,18 @@ sub XiaomiSmartHome_Write($@)
|
||||
sub XiaomiSmartHome_EncryptKey($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
if (defined $hash->{READINGS}{password}{VAL}){
|
||||
my $name = $hash->{NAME};
|
||||
if ( $hash->{READINGS}{password}{VAL} =~ /^[a-zA-Z0-9]{16}$/ ) {
|
||||
my $key = $hash->{READINGS}{password}{VAL};
|
||||
my $cipher = Crypt::CBC->new(-key => $key, -cipher => 'Cipher::AES',-iv => $iv, -literal_key => 1, -header => "none", -keysize => 16 );
|
||||
my $encryptkey = $cipher->encrypt_hex($hash->{READINGS}{token}{VAL});
|
||||
$encryptkey = substr($encryptkey, 0, 32);
|
||||
return $encryptkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log3 $name, 1, "$name: EncryptKey> Password not SET!";
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
#####################################
|
||||
@@ -230,12 +346,12 @@ sub XiaomiSmartHome_Get($@)
|
||||
if ($opt eq "UpdateAll")
|
||||
{
|
||||
XiaomiSmartHome_updateAllReadings($hash);
|
||||
Log3 $name, 5, "$name> UpdateALLReadings Started";
|
||||
Log3 $name, 5, "$name: Get> UpdateALLReadings Started";
|
||||
}
|
||||
elsif($opt eq "UpdateSingle")
|
||||
{
|
||||
XiaomiSmartHome_updateSingleReading($hash,$args);
|
||||
Log3 $name, 5, "$name> UpdateSingel Started";
|
||||
Log3 $name, 5, "$name: Get> UpdateSingel Started";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -248,15 +364,17 @@ sub XiaomiSmartHome_Notify($$)
|
||||
{
|
||||
my ($own_hash, $dev_hash) = @_;
|
||||
my $ownName = $own_hash->{NAME}; # own name / hash
|
||||
Log3 $ownName, 3, "$ownName> NotifyStart";
|
||||
Log3 $ownName, 5, "$ownName: Notify> NotifyStart";
|
||||
return "" if(IsDisabled($ownName)); # Return without any further action if the module is disabled
|
||||
|
||||
$attr{$own_hash->{NAME}}{webCmd} = "pct:rgb:rgb ff0000:rgb 00ff00:rgb 0000ff:on:off" if ( ! $attr{$own_hash->{NAME}}{webCmd} || $attr{$own_hash->{NAME}}{webCmd} eq "rgb:rgb ff0000:rgb 00ff00:rgb 0000ff:on:off" );
|
||||
readingsSingleUpdate($own_hash, "pct", 100, 1) if ( ! $own_hash->{READINGS}{pct}{VAL});
|
||||
my $devName = $dev_hash->{NAME}; # Device that created the events
|
||||
my $events = deviceEvents($dev_hash, 1);
|
||||
if($devName eq "global" && grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
|
||||
{
|
||||
Log3 $ownName, 3, "$ownName> Starting Connect";
|
||||
XiaomiSmartHome_connect($own_hash);
|
||||
Log3 $ownName, 5, "$ownName: Notify> Starting Connect after global";
|
||||
XiaomiSmartHome_connect($own_hash);
|
||||
CommandDeleteReading( undef, "$ownName HEARTBEAT" ) if(defined(ReadingsVal($ownName,"HEARTBEAT",undef)));
|
||||
}
|
||||
}
|
||||
#####################################
|
||||
@@ -265,32 +383,46 @@ sub XiaomiSmartHome_Set($@)
|
||||
{
|
||||
my ( $hash, $name, $cmd, @args ) = @_;
|
||||
my $dec_num;
|
||||
my $MIpct;
|
||||
my @match = grep( $_ =~ /^$cmd($|:)/, keys %sets );
|
||||
#-- check argument
|
||||
return SetExtensions($hash, join(" ", keys %sets), $name, $cmd, @args) unless @match == 1;
|
||||
return "$cmd expects $sets{$match[0]} parameters" unless (@args eq $sets{$match[0]});
|
||||
|
||||
return "\"set $name\" needs at least one argument" unless(defined($cmd));
|
||||
|
||||
|
||||
if (!defined $hash->{READINGS}{pct}) {
|
||||
$MIpct = $hash->{READINGS}{pct}{VAL};
|
||||
}
|
||||
else {
|
||||
$MIpct = 64;
|
||||
}
|
||||
if($cmd eq "password")
|
||||
{
|
||||
if($args[0] =~ /^[a-zA-Z0-9_.-]*$/)
|
||||
#if($args[0] =~ /^[a-zA-Z0-9_.-]*$/)
|
||||
if($args[0] =~ /^[a-zA-Z0-9]{16}$/)
|
||||
{
|
||||
readingsSingleUpdate( $hash, $cmd, $args[0], 0 );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Unknown value $args[0] for $cmd, wrong password, it must be hex";
|
||||
return "Unknown value $args[0] for $cmd, wrong password, it must be hex and 16 characters";
|
||||
}
|
||||
}
|
||||
if ( $hash->{READINGS}{password}{VAL} !~ /^[a-zA-Z0-9]{16}$/)
|
||||
{
|
||||
readingsSingleUpdate($hash, "password", "giveaPassword!", 1);
|
||||
Log3 $name, 1, "$name: Set> Password not SET!";
|
||||
return "for $cmd, wrong password, it must be hex and 16 characters";
|
||||
}
|
||||
elsif($cmd eq "rgb")
|
||||
{
|
||||
my $ownName = $hash->{NAME};
|
||||
Log3 $ownName, 4, "$ownName> Set $cmd, $args[0]";
|
||||
$dec_num = sprintf("%d", hex('ff' . $args[0]));
|
||||
Log3 $ownName, 4, "$ownName> Set $cmd, $dec_num";
|
||||
|
||||
Log3 $ownName, 4, "$ownName: Set> $cmd, $args[0]";
|
||||
$dec_num = sprintf("%d", hex($MIpct . $args[0]));
|
||||
Log3 $ownName, 4, "$ownName: Set> $cmd, $dec_num";
|
||||
$hash->{helper}{prevrgbvalue} = $args[0];
|
||||
readingsSingleUpdate( $hash, 'rgb', $args[0], 1 );
|
||||
readingsSingleUpdate( $hash, 'state', 'on', 1 );
|
||||
XiaomiSmartHome_Write($hash,$cmd,$dec_num);
|
||||
@@ -299,7 +431,7 @@ sub XiaomiSmartHome_Set($@)
|
||||
{
|
||||
$hash->{helper}{prevrgbvalue} = $hash->{READINGS}{rgb}{VAL};
|
||||
readingsSingleUpdate( $hash, 'state', 'off', 1 );
|
||||
readingsSingleUpdate( $hash, 'rgb', 'off', 0 );
|
||||
readingsSingleUpdate( $hash, 'rgb', '000000', 0 );
|
||||
XiaomiSmartHome_Write($hash,'rgb', 0);
|
||||
}
|
||||
elsif($cmd eq "on")
|
||||
@@ -308,7 +440,7 @@ sub XiaomiSmartHome_Set($@)
|
||||
readingsBulkUpdate( $hash, 'state', 'on', 1 );
|
||||
if ($hash->{helper}{prevrgbvalue})
|
||||
{
|
||||
$dec_num = sprintf("%d", hex('ff' . $hash->{helper}{prevrgbvalue}));
|
||||
$dec_num = sprintf("%d", hex($MIpct . $hash->{helper}{prevrgbvalue}));
|
||||
readingsBulkUpdate( $hash, 'rgb', $hash->{helper}{prevrgbvalue}, 1 );
|
||||
XiaomiSmartHome_Write($hash,'rgb', $dec_num);
|
||||
}
|
||||
@@ -322,8 +454,14 @@ sub XiaomiSmartHome_Set($@)
|
||||
elsif($cmd eq "pct")
|
||||
{
|
||||
my $ownName = $hash->{NAME};
|
||||
Log3 $ownName, 4, "$ownName> Set $cmd, $args[0]";
|
||||
XiaomiSmartHome_Write($hash,'illumination',$args[0]);
|
||||
Log3 $ownName, 4, "$ownName: Set> $cmd, $args[0], $hash->{helper}{prevrgbvalue}";
|
||||
readingsSingleUpdate( $hash, 'pct', $args[0], 1 );
|
||||
readingsSingleUpdate( $hash, 'rgb', $hash->{helper}{prevrgbvalue}, 1 );
|
||||
readingsSingleUpdate( $hash, 'state', 'on', 1 );
|
||||
my $MIpct = sprintf( "%.0f", (0.64 * $args[0]));
|
||||
Log3 $ownName, 4, "$ownName: Set> $cmd, $MIpct";
|
||||
my $rgb = sprintf("%d", hex($MIpct . $hash->{helper}{prevrgbvalue}));
|
||||
XiaomiSmartHome_Write($hash,'pct',$rgb);
|
||||
}
|
||||
|
||||
else
|
||||
@@ -338,7 +476,17 @@ sub XiaomiSmartHome_Set($@)
|
||||
|
||||
|
||||
sub XiaomiSmartHome_Attr(@) {
|
||||
|
||||
my ($cmd,$NAME,$name, $val) = @_;
|
||||
if ($cmd eq "delete"){
|
||||
delete $attr{$NAME}{$name};
|
||||
CommandDeleteAttr(undef, "$NAME $name");
|
||||
Log3 $name, 1, "$name: Attr> delete $name";
|
||||
}
|
||||
if ($cmd eq "create"){
|
||||
$attr{$NAME}{$name} = $val;
|
||||
Log3 $name, 1, "$name: Attr> create $name $val";
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
#####################################
|
||||
|
||||
@@ -346,40 +494,58 @@ sub XiaomiSmartHome_connect($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
Log3 $name, 3, "$name> ConnectStart";
|
||||
my $GATEWAY_IP;
|
||||
Log3 $name, 5, "$name: connect> ConnectStart";
|
||||
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
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";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
$p->close();
|
||||
return undef;
|
||||
}
|
||||
if( $hash->{GATEWAY} !~ m/^\d+\.\d+\.\d+\.\d+$/ ){
|
||||
eval {
|
||||
$GATEWAY_IP = inet_ntoa(inet_aton($hash->{GATEWAY})) ;
|
||||
$hash->{GATEWAY_IP} = $GATEWAY_IP;
|
||||
Log3 $name, 4, "$name: Connect> Set GATEWAYs IP: " . $GATEWAY_IP;
|
||||
};
|
||||
if ($@) {
|
||||
Log3 $name, 1, "$name: Connect> Error $@\n";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
Log3 $name, 4, "$name> connecting";
|
||||
|
||||
my $sock = IO::Socket::Multicast->new( Proto => 'udp', LocalPort =>'9898', ReuseAddr => 1) or die "Creating socket: $!\n";
|
||||
$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);
|
||||
|
||||
if ($sock)
|
||||
{
|
||||
Log3 $name, 3, "$name> connected";
|
||||
|
||||
$hash->{helper}{ConnectionState} = "Connected";
|
||||
|
||||
if ($hash->{helper}{ConnectionState} ne ReadingsVal($name, "state", "" ))
|
||||
{
|
||||
readingsSingleUpdate($hash, "state", $hash->{helper}{ConnectionState}, 1);
|
||||
}
|
||||
|
||||
$hash->{FD} = $sock->fileno();
|
||||
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";
|
||||
$sock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0)) or die "setsockopt: $!";
|
||||
if ($sock)
|
||||
{
|
||||
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";
|
||||
$hash->{SID} = XiaomiSmartHome_getGatewaySID($hash);
|
||||
if ($hash->{helper}{ConnectionState} ne ReadingsVal($name, "state", "" ))
|
||||
{
|
||||
readingsSingleUpdate($hash, "state", $hash->{helper}{ConnectionState}, 1);
|
||||
}
|
||||
$hash->{FD} = $sock->fileno();
|
||||
$hash->{CD} = $sock;
|
||||
$selectlist{$name} = $hash;
|
||||
readingsSingleUpdate($hash, "password", 'giveaPassword!', 1) if(!defined $hash->{READINGS}{password}{VAL});
|
||||
InternalTimer(gettimeofday() + 7, "XiaomiSmartHome_updateAllReadings", $hash, 0);
|
||||
}
|
||||
|
||||
$selectlist{$name} = $hash;
|
||||
|
||||
XiaomiSmartHome_updateAllReadings($hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log3 $name, 1, "$name> connect to $hash->{helper}{host} failed";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Log3 $name, 1, "$name: connect> connect to $hash->{helper}{host} failed";
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
#####################################
|
||||
@@ -397,11 +563,13 @@ sub XiaomiSmartHome_disconnect($)
|
||||
}
|
||||
|
||||
return if (!$hash->{CD});
|
||||
Log3 $name, 3, "$name> disconnecting";
|
||||
|
||||
close($hash->{CD});
|
||||
Log3 $name, 3, "$name: disconnect> disconnecting";
|
||||
|
||||
close($hash->{CD}) if($hash->{CD});
|
||||
delete($hash->{FD});
|
||||
delete($hash->{CD});
|
||||
|
||||
delete($selectlist{$name});
|
||||
|
||||
|
||||
return undef;
|
||||
}
|
||||
@@ -411,11 +579,11 @@ sub XiaomiSmartHome_updateSingleReading($$)
|
||||
{
|
||||
my ($hash, $sensor) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $GATEYWAY = $hash->{GATEYWAY};
|
||||
my $GATEWAY = $hash->{GATEWAY};
|
||||
my $sock = $hash->{CD};
|
||||
my $MAXLEN = 1024;
|
||||
|
||||
Log3 $name, 4, "$name> PushSingelRead:" . $sensor;
|
||||
Log3 $name, 4, "$name: updateSingleReading> PushSingelRead:" . $sensor;
|
||||
XiaomiSmartHome_Write($hash, 'read', $sensor);
|
||||
|
||||
}
|
||||
@@ -425,30 +593,62 @@ sub XiaomiSmartHome_updateAllReadings($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
my $GATEYWAY = $hash->{GATEYWAY};
|
||||
Log3 $name, 5, "name> updateAllReadings> Starting UpdateALLReadings";
|
||||
my $GATEWAY;
|
||||
my $p = Net::Ping->new();
|
||||
if ( ! $p->ping($hash->{GATEWAY})){
|
||||
Log3 $name, 4, "$name: updateAllReadings> Ping to $hash->{helper}{host} failed";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
$p->close();
|
||||
return undef;
|
||||
}
|
||||
if( $hash->{GATEWAY} !~ m/^\d+\.\d+\.\d+\.\d+$/ ){
|
||||
eval {
|
||||
$GATEWAY = inet_ntoa(inet_aton($hash->{GATEWAY})) ;
|
||||
Log3 $name, 4, "$name: updateAllReadings> Using DNS to IP: " . $GATEWAY;
|
||||
};
|
||||
if ($@) {
|
||||
Log3 $name, 1, "$name: updateAllReadings> Error $@\n";
|
||||
$hash->{STATE} = "Disconnected";
|
||||
XiaomiSmartHome_disconnect($hash);
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$GATEWAY = $hash->{GATEWAY};
|
||||
}
|
||||
|
||||
if ( $hash->{helper}{ConnectionState} eq 'Disconnected')
|
||||
{
|
||||
Log3 $name, 1, "$name: updateAllReadings> Gateway is $hash->{STATE} trying to reconnect to $hash->{GATEWAY}";
|
||||
XiaomiSmartHome_connect($hash);
|
||||
return undef;
|
||||
}
|
||||
my $sock = $hash->{CD};
|
||||
my $MAXLEN = 1024;
|
||||
|
||||
my $msg = '{"cmd" : "get_id_list"}';
|
||||
$sock->mcast_send($msg, $GATEYWAY .':9898') or die "send: $!";
|
||||
$sock->mcast_send($msg, $GATEWAY .':9898') or die "send: $!";
|
||||
eval {
|
||||
$sock->recv($msg, $MAXLEN) or die "recv: $!";
|
||||
Log3 $name, 5, "$name> " . $msg;
|
||||
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> Read:" . $msg;
|
||||
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> PushRead:" . $sensor;
|
||||
Log3 $name, 4, "$name: updateAllReadings> PushRead:" . $sensor;
|
||||
my $msg = '{"cmd":"read","sid":"' . $sensor . '" }';
|
||||
$sock->mcast_send($msg, $GATEYWAY .':9898') or die "send: $!";
|
||||
$sock->mcast_send($msg, $GATEWAY .':9898') or die "send: $!";
|
||||
eval {
|
||||
$sock->recv($msg, $MAXLEN) or die "recv: $!";
|
||||
Log3 $name, 5, "$name> " . $msg;
|
||||
Log3 $name, 5, "$name: updateAllReadings> " . $msg;
|
||||
Dispatch($hash, $msg, undef);
|
||||
}
|
||||
|
||||
@@ -456,6 +656,7 @@ sub XiaomiSmartHome_updateAllReadings($)
|
||||
}
|
||||
}
|
||||
}
|
||||
#return undef;
|
||||
}
|
||||
#####################################
|
||||
|
||||
@@ -463,8 +664,8 @@ sub XiaomiSmartHome_updateAllReadings($)
|
||||
|
||||
=pod
|
||||
=item device
|
||||
=item summary Module fpr XiaomiSmartHome Gateway to use with FHEM
|
||||
=item summary_DE Modul um ein XiaomiSmartHome Gateyway in FHEM zu nutzen
|
||||
=item summary Module for XiaomiSmartHome Gateway to use with FHEM
|
||||
=item summary_DE Modul um ein XiaomiSmartHome Gateway in FHEM zu nutzen
|
||||
|
||||
=begin html
|
||||
|
||||
|
||||
@@ -25,23 +25,24 @@ package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $version = "0.11";
|
||||
my $version = "0.18";
|
||||
sub XiaomiSmartHome_Device_updateSReading($);
|
||||
|
||||
#####################################
|
||||
|
||||
|
||||
#####################################
|
||||
sub XiaomiSmartHome_Device_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = "^.+magnet|motion|sensor_ht|switch|plug|cube";
|
||||
$hash->{Match} = "^.+magnet|motion|sensor_ht|switch|plug|cube|86sw2";
|
||||
$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 ".
|
||||
"do_not_notify:1,0 ignore:1,0 dummy:1,0 showtime:1,0 valueFn:textField-long motionOffTimer:1,5,10 ".
|
||||
"do_not_notify:1,0 ignore:1,0 dummy:1,0 showtime:1,0 valueFn:textField-long".
|
||||
$readingFnAttributes ;
|
||||
}
|
||||
#####################################
|
||||
@@ -64,6 +65,8 @@ sub XiaomiSmartHome_Device_Set($@)
|
||||
return "\"set $name\" needs at least one argument" unless(defined($cmd));
|
||||
|
||||
my $setlist = "";
|
||||
$setlist .= "motionOffTimer:1,5,10 " if ($hash->{MODEL} eq 'motion');
|
||||
#$setlist = "open:noArg close:noArg " if ($hash->{MODEL} eq 'magnet');
|
||||
$setlist .= "power:on,off " if ($hash->{MODEL} eq 'plug');
|
||||
|
||||
if($cmd eq "power")
|
||||
@@ -77,6 +80,16 @@ sub XiaomiSmartHome_Device_Set($@)
|
||||
IOWrite($hash,"power","off",$hash);
|
||||
}
|
||||
}
|
||||
if($cmd eq "open")
|
||||
{
|
||||
readingsSingleUpdate($hash, "state", "open", 1 );
|
||||
return;
|
||||
}
|
||||
if($cmd eq "motionOffTimer")
|
||||
{
|
||||
readingsSingleUpdate($hash, "motionOffTimer", "$args[0]", 1 );;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Unknown argument $cmd, choose one of $setlist";
|
||||
@@ -91,7 +104,7 @@ sub XiaomiSmartHome_Device_on_timeout($){
|
||||
my $name = $hash->{LASTInputDev};
|
||||
if ($hash->{STATE} eq 'motion') {
|
||||
readingsSingleUpdate($hash, "state", "off", 1 );
|
||||
Log3 $name, 3, "$name>" . " SID: " . $hash->{SID} . " Type: " . $hash->{MODEL} . " Status: off";
|
||||
Log3 $name, 3, "$name: DEV_Timeout>" . " SID: " . $hash->{SID} . " Type: " . $hash->{MODEL} . " Status: off";
|
||||
}
|
||||
}
|
||||
#####################################
|
||||
@@ -100,11 +113,11 @@ sub XiaomiSmartHome_Device_Read($$$){
|
||||
my $decoded = decode_json($msg);
|
||||
my $sid = $decoded->{'sid'};
|
||||
my $model = $decoded->{'model'};
|
||||
Log3 $name, 5, "$name: SID: " . $hash->{SID} . " " . $hash->{TYPE};
|
||||
Log3 $name, 5, "$name: DEV_Read> SID: " . $hash->{SID} . " " . $hash->{TYPE};
|
||||
my $data = decode_json($decoded->{data});
|
||||
readingsBeginUpdate( $hash );
|
||||
if (defined $data->{status}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Status: " . $data->{status};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Status: " . $data->{status};
|
||||
readingsBulkUpdate($hash, "state", "$data->{status}", 1 );
|
||||
if ($data->{status} eq 'motion' && $hash->{MODEL} eq 'motion'){
|
||||
readingsBulkUpdate($hash, "no_motion", "0", 1 );
|
||||
@@ -114,51 +127,63 @@ sub XiaomiSmartHome_Device_Read($$$){
|
||||
}
|
||||
}
|
||||
if (defined $data->{no_motion}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_motion: " . $data->{no_motion};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_motion: " . $data->{no_motion};
|
||||
readingsBulkUpdate($hash, "no_motion", "$data->{no_motion}", 1 );
|
||||
}
|
||||
if (defined $data->{no_close}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_close: " . $data->{no_close};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " NO_close: " . $data->{no_close};
|
||||
readingsBulkUpdate($hash, "no_close", "$data->{no_close}", 1 );
|
||||
}
|
||||
if (defined $data->{voltage}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Voltage: " . $data->{voltage};
|
||||
readingsBulkUpdate($hash, "voltage", "$data->{voltage}", 1 );
|
||||
my $bat = ($data->{voltage}/1000);
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Voltage: " . $data->{voltage};
|
||||
readingsBulkUpdate($hash, "battery", $bat, 1 );
|
||||
}
|
||||
if (defined $data->{temperature}){
|
||||
my $temp = $data->{temperature};
|
||||
$temp =~ s/(^[-+]?\d+?(?=(?>(?:\d{2})+)(?!\d))|\G\d{2}(?=\d))/$1./g;
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Temperature: " . $temp;
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Temperature: " . $temp;
|
||||
readingsBulkUpdate($hash, "temperature", "$temp", 1 );
|
||||
}
|
||||
if (defined $data->{humidity}){
|
||||
my $hum = $data->{humidity};
|
||||
$hum =~ s/(^[-+]?\d+?(?=(?>(?:\d{2})+)(?!\d))|\G\d{2}(?=\d))/$1./g;
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Humidity: " . $hum;
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Humidity: " . $hum;
|
||||
readingsBulkUpdate($hash, "humidity", "$hum", 1 );
|
||||
}
|
||||
#86sw2 start
|
||||
if (defined $data->{channel_0}){
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Channel_0: " . $data->{channel_0};
|
||||
readingsBulkUpdate($hash, "channel_0", "$data->{channel_0}", 1 );
|
||||
}
|
||||
if (defined $data->{channel_1}){
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Channel_1: " . $data->{channel_1};
|
||||
readingsBulkUpdate($hash, "channel_1", "$data->{channel_1}", 1 );
|
||||
}
|
||||
#86sw2 end
|
||||
#plug start
|
||||
if (defined $data->{load_voltage}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Voltage: " . $data->{load_voltage};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Voltage: " . $data->{load_voltage};
|
||||
readingsBulkUpdate($hash, "LOAD_Voltage", "$data->{load_voltage}", 1 );
|
||||
}
|
||||
if (defined $data->{load_power}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Power: " . $data->{load_power};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " LOAD_Power: " . $data->{load_power};
|
||||
readingsBulkUpdate($hash, "LOAD_Power", "$data->{load_power}", 1 );
|
||||
}
|
||||
if (defined $data->{power_consumed}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " POWER_Consumed: " . $data->{power_consumed};
|
||||
Log3 $name, 3, "$name:" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " POWER_Consumed: " . $data->{power_consumed};
|
||||
readingsBulkUpdate($hash, "POWER_Consumed", "$data->{power_consumed}", 1 );
|
||||
}
|
||||
if (defined $data->{inuse}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " InUse: " . $data->{inuse};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " InUse: " . $data->{inuse};
|
||||
readingsBulkUpdate($hash, "inuse", "$data->{inuse}", 1 );
|
||||
}
|
||||
#plug end
|
||||
#cube start
|
||||
if (defined $data->{rotate}){
|
||||
Log3 $name, 3, "$name>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Rotate: " . $data->{rotate};
|
||||
Log3 $name, 3, "$name: DEV_Read>" . " SID: " . $sid . " Type: " . $hash->{MODEL} . " Rotate: " . $data->{rotate};
|
||||
readingsBulkUpdate($hash, "rotate", "$data->{rotate}", 1 );
|
||||
readingsBulkUpdate($hash, "state", "rotate", 1 );
|
||||
}
|
||||
#cube end
|
||||
if ($decoded->{'cmd'} eq 'heartbeat'){
|
||||
@@ -180,13 +205,13 @@ sub XiaomiSmartHome_Device_Parse($$) {
|
||||
|
||||
if (my $io_hash = $modules{XiaomiSmartHome_Device}{defptr}{$sid})
|
||||
{
|
||||
Log3 $name, 4, "$name> IS DEFINED " . $model . " : " .$sid;
|
||||
Log3 $name, 4, "$name: DEV_Parse> IS DEFINED " . $model . " : " .$sid;
|
||||
XiaomiSmartHome_Device_Read($io_hash, $msg, $name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Log3 $name, 4, "$name> UNDEFINED " . $model . " : " .$sid;
|
||||
Log3 $name, 4, "$name: DEV_Parse> UNDEFINED " . $model . " : " .$sid;
|
||||
return "UNDEFINED XMI_$sid XiaomiSmartHome_Device $sid $model $name";
|
||||
}
|
||||
}
|
||||
@@ -197,18 +222,21 @@ sub XiaomiSmartHome_Device_update($){
|
||||
my $model = $hash->{MODEL};
|
||||
my $name = $hash->{NAME};
|
||||
my $value_fn = AttrVal( $name, "valueFn", "" );
|
||||
my $mot = AttrVal( $name, "motionOffTimer", "" );
|
||||
#my $mot = AttrVal( $name, "motionOffTimer", "" );
|
||||
my $mot = $hash->{READINGS}{motionOffTimer}{VAL} if ($hash->{READINGS}{motionOffTimer});
|
||||
if( $value_fn =~ m/^{.*}$/s ) {
|
||||
|
||||
my $LASTCMD = ReadingsVal($name,"lastCmd",undef);
|
||||
|
||||
my $value_fn = eval $value_fn;
|
||||
Log3 $name, 3, $name .": valueFn: ". $@ if($@);
|
||||
Log3 $name, 3, $name .": DEV_Update valueFn: ". $@ if($@);
|
||||
return undef if( !defined($value_fn) );
|
||||
}
|
||||
if( $model eq 'motion') {
|
||||
XiaomiSmartHome_Device_mot($hash, $mot) if( $mot);
|
||||
XiaomiSmartHome_Device_mot($hash, $hash->{READINGS}{motionOffTimer}{VAL}) if( $hash->{READINGS}{motionOffTimer});
|
||||
}
|
||||
# Update delete old reading Voltage
|
||||
CommandDeleteReading( undef, "$name voltage" ) if(defined(ReadingsVal($name,"voltage",undef)));
|
||||
}
|
||||
#####################################
|
||||
|
||||
@@ -228,9 +256,9 @@ sub XiaomiSmartHome_Device_Define($$) {
|
||||
|
||||
if(defined($hash->{IODev}->{NAME})) {
|
||||
my $IOname = $hash->{IODev}->{NAME};
|
||||
Log3 $name, 3, $IOname . "> " .$name. ": " . $type . " I/O device is " . $hash->{IODev}->{NAME};
|
||||
Log3 $name, 3, $IOname . ": DEV_Define> " .$name. ": " . $type . " I/O device is " . $hash->{IODev}->{NAME};
|
||||
} else {
|
||||
Log3 $name, 1, "$name $type - no I/O device";
|
||||
Log3 $name, 1, "$name DEV_Define> $type - no I/O device";
|
||||
}
|
||||
$iodev = $hash->{IODev}->{NAME};
|
||||
|
||||
@@ -238,7 +266,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 );
|
||||
|
||||
Log3 $name, 3, $iodev . "> " . $name . ": defined as ". $hash->{MODEL};
|
||||
Log3 $name, 3, $iodev . ": DEV_Define> " . $name . ": defined as ". $hash->{MODEL};
|
||||
$attr{$name}{room} = "MiSmartHome" if( !defined( $attr{$name}{room} ) );
|
||||
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} ) );
|
||||
@@ -251,8 +279,8 @@ sub XiaomiSmartHome_Device_Define($$) {
|
||||
}
|
||||
|
||||
if( $init_done ) {
|
||||
InternalTimer( gettimeofday()+int(rand(2)), "XiaomiSmartHome_Device_updateSReading", $hash, 0 );
|
||||
Log3 $name, 4, $iodev . "> " . $name . " Init Done set InternalTimer for Update";
|
||||
InternalTimer(gettimeofday() + 2, "XiaomiSmartHome_Device_updateSReading", $hash, 0 );
|
||||
Log3 $name, 4, $iodev . ": DEV_Define> " . $name . " Init Done set InternalTimer for Update";
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
@@ -260,8 +288,8 @@ sub XiaomiSmartHome_Device_Define($$) {
|
||||
sub XiaomiSmartHome_Device_updateSReading($) {
|
||||
|
||||
my $hash = shift;
|
||||
#my $name = $hash->{NAME};
|
||||
#Log3 $name, 3, $name . " Updae SR";
|
||||
my $name = $hash->{NAME};
|
||||
Log3 $name, 3, "$name: DEV_updateSReading> for $hash->{SID}";
|
||||
RemoveInternalTimer($hash,'XiaomiSmartHome_Device_updateSReading');
|
||||
IOWrite($hash,'read',"$hash->{SID}");
|
||||
}
|
||||
@@ -275,7 +303,7 @@ sub XiaomiSmartHome_Device_Undef($)
|
||||
my $iodev = $hash->{IODev}->{NAME};
|
||||
RemoveInternalTimer($hash);
|
||||
delete($modules{XiaomiSmartHome_Device}{defptr}{$hash->{SID}});
|
||||
Log3 $name, 3, "$iodev> $name - device deleted";
|
||||
Log3 $name, 3, "$iodev: DEV_Undef> $name - device deleted";
|
||||
return undef;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
UPD 2017-04-03_14:31:37 15333 FHEM/71_XiaomiSmartHome.pm
|
||||
UPD 2017-04-03_22:28:16 10007 FHEM/71_XiaomiSmartHome_Device.pm
|
||||
UPD 2017-04-28_20:38:35 22335 FHEM/71_XiaomiSmartHome.pm
|
||||
UPD 2017-04-28_20:38:37 11413 FHEM/71_XiaomiSmartHome_Device.pm
|
||||
Reference in New Issue
Block a user