mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-01 20:20:10 +00:00
30_HUEBridge.pm, 31_HUEDevice.pm: better timestamp handling for polling and events, better handling of ignored resource types in events
git-svn-id: https://svn.fhem.de/fhem/trunk@25534 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
01408639ad
commit
51a00eca30
@ -735,6 +735,12 @@ HUEBridge_Set($@)
|
||||
#HUEBridge_openEventStream( $hash );
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'close') {
|
||||
HUEBridge_closeWebsocket($hash);
|
||||
HUEBridge_closeEventStream($hash);
|
||||
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'statusRequest') {
|
||||
return "usage: statusRequest" if( @args != 0 );
|
||||
|
||||
@ -1287,6 +1293,7 @@ HUEBridge_Get($@)
|
||||
$result->{$key}{class} = '' if( !defined($result->{$key}{class}) ); #deCONZ fix
|
||||
$result->{$key}{lights} = [] if( !defined($result->{$key}{lights}) ); #deCONZ fix
|
||||
$ret .= sprintf( "%2i: %-15s %-15s %-15s %-15s", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type}, $result->{$key}{class} );
|
||||
$ret .= ' (ignored)' if( $hash->{helper}{ignored}{$code} );
|
||||
if( !$arg && $hash->{helper}{lights} ) {
|
||||
$ret .= sprintf( " %s\n", join( ",", map { my $l = $hash->{helper}{lights}{$_}{name}; $l?$l:$_;} @{$result->{$key}{lights}} ) );
|
||||
} else {
|
||||
@ -1385,16 +1392,17 @@ HUEBridge_Get($@)
|
||||
my $fhem_name = '';
|
||||
$fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) );
|
||||
$fhem_name = "" if( !$fhem_name );
|
||||
$ret .= sprintf( "%2i: %-15s %-15s %-20s", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type} );
|
||||
$ret .= sprintf( "%2i: %-20s %-15s %-20s", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type} );
|
||||
$ret .= ' (ignored)' if( $hash->{helper}{ignored}{$code} );
|
||||
$ret .= sprintf( "\n%-56s %s", '', encode_json($result->{$key}{state}) ) if( $arg && $arg eq 'detail' );
|
||||
$ret .= sprintf( "\n%-56s %s", '', encode_json($result->{$key}{config}) ) if( $arg && $arg eq 'detail' );
|
||||
$ret .= sprintf( "\n%-56s %s", '', encode_json($result->{$key}{capabilities}) ) if( $arg && $arg eq 'detail' );
|
||||
$ret .= "\n";
|
||||
}
|
||||
if( $arg && $arg eq 'detail' ) {
|
||||
$ret = sprintf( "%2s %-15s %-15s %-20s %s\n", "ID", "NAME", "FHEM", "TYPE", "STATE,CONFIG,CAPABILITIES" ) .$ret if( $ret );
|
||||
$ret = sprintf( "%2s %-20s %-15s %-20s %s\n", "ID", "NAME", "FHEM", "TYPE", "STATE,CONFIG,CAPABILITIES" ) .$ret if( $ret );
|
||||
} else {
|
||||
$ret = sprintf( "%2s %-15s %-15s %-20s\n", "ID", "NAME", "FHEM", "TYPE" ) .$ret if( $ret );
|
||||
$ret = sprintf( "%2s %-20s %-15s %-20s\n", "ID", "NAME", "FHEM", "TYPE" ) .$ret if( $ret );
|
||||
}
|
||||
return $ret;
|
||||
|
||||
@ -1428,6 +1436,9 @@ HUEBridge_Get($@)
|
||||
$ret = sprintf( "%2s %-25s %-15s %s\t%s\n", "ID", "NAME", "FHEM", "MODE", "CONFIGURED" ) .$ret if( $ret );
|
||||
return $ret;
|
||||
|
||||
} elsif($cmd eq 'ignored' ) {
|
||||
return join( "\n", keys %{$hash->{helper}{ignored}} );
|
||||
|
||||
} elsif($cmd eq 'v2resource' ) {
|
||||
if( $arg ) {
|
||||
my $ret;
|
||||
@ -1766,11 +1777,13 @@ HUEBridge_Parse($$)
|
||||
|
||||
$hash->{updatestate} .= " [$devicetypes]" if( $devicetypes );
|
||||
}
|
||||
|
||||
} elsif ( defined( $hash->{swupdate} ) ) {
|
||||
delete( $hash->{updatestate} );
|
||||
delete( $hash->{helper}{updatestate} );
|
||||
}
|
||||
|
||||
#update state timestamp
|
||||
readingsSingleUpdate($hash, 'state', $hash->{READINGS}{state}{VAL}, 0);
|
||||
}
|
||||
|
||||
@ -1823,6 +1836,11 @@ HUEBridge_Autocreate($;$$)
|
||||
$result->{0} = { name => "Lightset 0", type => 'LightGroup' };
|
||||
foreach my $id ( sort {$a<=>$b} keys %{$result} ) {
|
||||
my $code = $name ."-G". $id;
|
||||
if( defined($modules{HUEDevice}{defptr}{$code}) ) {
|
||||
Log3 $name, 5, "$name: id '$id' already defined as '$modules{HUEDevice}{defptr}{$code}->{NAME}'";
|
||||
next;
|
||||
}
|
||||
|
||||
if( $result->{$id}{type} eq 'Entertainment' ) {
|
||||
Log3 $name, 4, "$name: ignoring group $id ($result->{$id}{name}) of type $result->{$id}{type} in autocreate";
|
||||
$ignored[1]++;
|
||||
@ -1830,11 +1848,6 @@ HUEBridge_Autocreate($;$$)
|
||||
next;
|
||||
}
|
||||
|
||||
if( defined($modules{HUEDevice}{defptr}{$code}) ) {
|
||||
Log3 $name, 5, "$name: id '$id' already defined as '$modules{HUEDevice}{defptr}{$code}->{NAME}'";
|
||||
next;
|
||||
}
|
||||
|
||||
my $devname= "HUEGroup" . $id;
|
||||
$devname = $name ."_". $devname if( $hash->{helper}{count} );
|
||||
my $define= "$devname HUEDevice group $id IODev=$name";
|
||||
@ -1861,6 +1874,11 @@ HUEBridge_Autocreate($;$$)
|
||||
$result = HUEBridge_Call($hash,undef, 'sensors', undef);
|
||||
foreach my $id ( sort {$a<=>$b} keys %{$result} ) {
|
||||
my $code = $name ."-S". $id;
|
||||
if( defined($modules{HUEDevice}{defptr}{$code}) ) {
|
||||
Log3 $name, 5, "$name: id '$id' already defined as '$modules{HUEDevice}{defptr}{$code}->{NAME}'";
|
||||
next;
|
||||
}
|
||||
|
||||
if( $result->{$id}{type} eq 'CLIPGenericStatus' ) {
|
||||
Log3 $name, 4, "$name: ignoring sensor $id ($result->{$id}{name}) of type $result->{$id}{type} in autocreate";
|
||||
$ignored[2]++;
|
||||
@ -1868,11 +1886,6 @@ HUEBridge_Autocreate($;$$)
|
||||
next;
|
||||
}
|
||||
|
||||
if( defined($modules{HUEDevice}{defptr}{$code}) ) {
|
||||
Log3 $name, 5, "$name: id '$id' already defined as '$modules{HUEDevice}{defptr}{$code}->{NAME}'";
|
||||
next;
|
||||
}
|
||||
|
||||
my $devname= "HUESensor" . $id;
|
||||
$devname = $name ."_". $devname if( $hash->{helper}{count} );
|
||||
my $define= "$devname HUEDevice sensor $id IODev=$name";
|
||||
@ -2208,7 +2221,7 @@ HUEBridge_dispatch($$$;$)
|
||||
my $hash = $param->{hash};
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
Log3 $name, 4, "$name: dispatch";
|
||||
Log3 $name, 4, "$name: dispatch". ($param->{url}?": $param->{url}":"");
|
||||
Log3 $name, 5, "HUEBridge_dispatch". ($param->{type}?": $param->{type}":"");
|
||||
|
||||
my $type = $param->{type};
|
||||
@ -2216,7 +2229,7 @@ HUEBridge_dispatch($$$;$)
|
||||
if( $err ) {
|
||||
Log3 $name, 2, "$name: http request failed: $err";
|
||||
|
||||
if( $type eq 'event' ) {
|
||||
if( $type && $type eq 'event' ) {
|
||||
if( defined($hash->{helper}{HTTP_CONNECTION}) && defined($hash->{helper}{HTTP_CONNECTION}{lastID}) ) {
|
||||
$hash->{EventStream} = 'terminated';
|
||||
Log3 $name, 2, "$name: EventStream: $hash->{EventStream}";
|
||||
@ -2298,7 +2311,7 @@ HUEBridge_dispatch($$$;$)
|
||||
Log3 $name, 2, "$name: EventStream: json error: $@ in $value" if( $@ );
|
||||
|
||||
return undef if( !$json );
|
||||
Log3 $name, 4, "$name: EventStream: received: ". Dumper $json;
|
||||
Log3 $name, 5, "$name: EventStream: received: ". Dumper $json;
|
||||
|
||||
my $changed = "";
|
||||
for my $event ( @{$json} ) {
|
||||
@ -2306,7 +2319,7 @@ HUEBridge_dispatch($$$;$)
|
||||
Log3 $name, 4, "$name: EventStream: got $event->{type} event";
|
||||
|
||||
for my $data ( @{$event->{data}} ) {
|
||||
Log3 $name, 4, "$name: with part for resource type $data->{type}";
|
||||
Log3 $name, 4, "$name: event part for resource type $data->{type}";
|
||||
|
||||
my(undef, $t, $id) = split( '/', $data->{id_v1} );
|
||||
if( !defined($t) || !defined($id) ) {
|
||||
@ -2319,7 +2332,8 @@ HUEBridge_dispatch($$$;$)
|
||||
$code = $name ."-S". $id if( $t eq 'sensors' );
|
||||
$code = $name ."-G". $id if( $t eq 'groups' );
|
||||
if( !$code ) {
|
||||
Log3 $name, 3, "$name: EventStream: ignoring event for $t";
|
||||
# handle events for scenes ?
|
||||
Log3 $name, 4, "$name: EventStream: ignoring event for $t";
|
||||
next;
|
||||
}
|
||||
|
||||
@ -2400,8 +2414,25 @@ HUEBridge_dispatch($$$;$)
|
||||
}
|
||||
|
||||
} elsif( $data->{type} eq 'entertainment_configuration' ) {
|
||||
Log3 $name, 4, "$name: ignoring resource type $data->{type}";
|
||||
$handled = 0;
|
||||
|
||||
} elsif( $data->{type} eq 'bridge_home' ) {
|
||||
HUEBridge_getv2resources($hash, 1);
|
||||
Log3 $name, 4, "$name: ignoring resource type $data->{type}";
|
||||
$handled = 0;
|
||||
|
||||
} elsif( $data->{type} eq 'room' ) {
|
||||
Log3 $name, 4, "$name: ignoring resource type $data->{type}";
|
||||
$handled = 0;
|
||||
|
||||
} elsif( $data->{type} eq 'zone' ) {
|
||||
Log3 $name, 4, "$name: ignoring resource type $data->{type}";
|
||||
$handled = 0;
|
||||
|
||||
} elsif( $data->{type} eq 'grouped_light' ) {
|
||||
Log3 $name, 4, "$name: ignoring resource type $data->{type}";
|
||||
$handled = 0;
|
||||
|
||||
} elsif( $data->{type} eq 'light'
|
||||
|| $data->{type} eq 'grouped_light' ) {
|
||||
@ -2433,7 +2464,7 @@ HUEBridge_dispatch($$$;$)
|
||||
}
|
||||
|
||||
if( $handled ) {
|
||||
Log3 $name, 4, "$name: created from event: ". Dumper $obj;
|
||||
Log3 $name, 5, "$name: created from event: ". Dumper $obj;
|
||||
|
||||
if( HUEDevice_Parse($chash, $obj) && !$chash->{helper}{devtype} ) {
|
||||
$changed .= "," if( $changed );
|
||||
|
@ -81,8 +81,16 @@ my %hueModels = (
|
||||
icon => 'hue_filled_white_and_color_e27_b22', },
|
||||
LWB014 => {name => 'Hue Lux' ,type => 'Dimmable light' ,subType => 'dimmer',
|
||||
icon => 'hue_filled_white_and_color_e27_b22', },
|
||||
LWO003 => {name => 'Hue White Filament Bulb G125' ,type => 'Dimmable light' ,subType => 'dimmer',
|
||||
icon => 'hue_filled_filament', },
|
||||
LWV001 => {name => 'Hue White Filament Bulb' ,type => 'Dimmable light' ,subType => 'dimmer',
|
||||
icon => 'hue_filled_filament', },
|
||||
LTO001 => {name => 'Hue Filament Bulb G93' ,type => 'Color temperature light' ,subType => 'ctdimmer',
|
||||
icon => 'hue_filled_filament', },
|
||||
LTO002 => {name => 'Hue Filament Bulb G125' ,type => 'Color temperature light' ,subType => 'ctdimmer',
|
||||
icon => 'hue_filled_filament', },
|
||||
LTO004 => {name => 'Hue Filament Bulb G25' ,type => 'Color temperature light' ,subType => 'ctdimmer',
|
||||
icon => 'hue_filled_filament', },
|
||||
LTW001 => {name => 'Hue A19 White Ambience' ,type => 'Color temperature light' ,subType => 'ctdimmer',
|
||||
icon => 'hue_filled_white_and_color_e27_b22', },
|
||||
LTW004 => {name => 'Hue A19 White Ambience' ,type => 'Color temperature light' ,subType => 'ctdimmer', },
|
||||
@ -494,14 +502,15 @@ HUEDevice_Define($$) {
|
||||
HUEDevice_GetUpdate($hash);
|
||||
|
||||
} else {
|
||||
InternalTimer(gettimeofday()+10, "HUEDevice_GetUpdate", $hash, 0);
|
||||
InternalTimer(gettimeofday()+10, "HUEDevice_GetUpdate", $hash, 0) if( $hash->{INTERVAL} );
|
||||
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HUEDevice_Undefine($$)
|
||||
sub
|
||||
HUEDevice_Undefine($$)
|
||||
{
|
||||
my ($hash,$arg) = @_;
|
||||
|
||||
@ -1461,8 +1470,8 @@ HUEDevice_Parse($$)
|
||||
|
||||
if( ref($result) ne "HASH" ) {
|
||||
if( ref($result) && $HUEDevice_hasDataDumper) {
|
||||
#Log3 $name, 2, "$name: got wrong status message for $name: ". Dumper $result;
|
||||
Log3 $name, 2, "$name: got wrong status message for $name: $result";
|
||||
Log3 $name, 2, "$name: got wrong status message for $name: ". Dumper $result;
|
||||
#Log3 $name, 2, "$name: got wrong status message for $name: $result";
|
||||
} else {
|
||||
Log3 $name, 2, "$name: got wrong status message for $name: $result";
|
||||
}
|
||||
@ -1670,6 +1679,7 @@ HUEDevice_Parse($$)
|
||||
|
||||
$hash->{power} = $result->{power} if( defined($result->{power}) );
|
||||
|
||||
|
||||
if( $hash->{helper}->{devtype} eq 'S' ) {
|
||||
my %readings;
|
||||
|
||||
@ -1689,6 +1699,7 @@ HUEDevice_Parse($$)
|
||||
$hash->{tholddark} = $config->{tholddark} if( defined($config->{tholddark}) );
|
||||
$hash->{sensitivity} = $config->{sensitivity} if( defined($config->{sensitivity}) );
|
||||
|
||||
|
||||
$readings{battery} = $config->{battery} if( defined($config->{battery}) );
|
||||
$readings{batteryPercent} = $config->{battery} if( defined($config->{battery}) );
|
||||
|
||||
@ -1705,8 +1716,8 @@ HUEDevice_Parse($$)
|
||||
$readings{mode} = $config->{mode} if( defined ($config->{mode}) );
|
||||
}
|
||||
|
||||
my $lastupdated = '';
|
||||
my $lastupdated_local = '';
|
||||
my $lastupdated;
|
||||
my $ts;
|
||||
my $offset = 0;
|
||||
if( my $state = $result->{state} ) {
|
||||
$lastupdated = $state->{lastupdated};
|
||||
@ -1714,30 +1725,25 @@ HUEDevice_Parse($$)
|
||||
return undef if( !$lastupdated );
|
||||
return undef if( $lastupdated eq 'none' );
|
||||
|
||||
substr( $lastupdated, 10, 1, ' ' ) if($lastupdated);
|
||||
$ts = time_str2num($lastupdated);
|
||||
|
||||
if( my $iohash = $hash->{IODev} ) {
|
||||
substr( $lastupdated, 10, 1, '_' );
|
||||
my $sec = SVG_time_to_sec($lastupdated);
|
||||
|
||||
$lastupdated = FmtDateTime($sec);
|
||||
|
||||
if( my $offset_bridge = $iohash->{helper}{offsetUTC} ) {
|
||||
$offset = $offset_bridge;
|
||||
Log3 $name, 4, "$name: use offsetUTC $offset from bridge";
|
||||
}else{
|
||||
#we do not have received the offsetUTC from the bridge, use the system offsetUTC until we received it
|
||||
Log3 $name, 5, "$name: using offsetUTC $offset from bridge";
|
||||
} else {
|
||||
# bridge has no offsetUTC configured, use the system offsetUTC for now
|
||||
my @t = localtime(time);
|
||||
$offset = timegm(@t) - timelocal(@t);
|
||||
Log3 $name, 4, "$name: use offsetUTC $offset from system";
|
||||
Log3 $name, 5, "$name: using offsetUTC $offset from system";
|
||||
}
|
||||
|
||||
#add offset to UTC for displaying in fhem
|
||||
$sec += $offset;
|
||||
$lastupdated_local = FmtDateTime($sec);
|
||||
$ts += $offset;
|
||||
$lastupdated = FmtDateTime($ts);
|
||||
|
||||
}else{
|
||||
$lastupdated_local = $lastupdated;
|
||||
} else {
|
||||
# what to do? can this happen?
|
||||
Log3 $name, 1, "$name: HUEDevice_Parse called without hash->{IODev}";
|
||||
|
||||
}
|
||||
|
||||
@ -1799,25 +1805,8 @@ HUEDevice_Parse($$)
|
||||
}
|
||||
}
|
||||
|
||||
$hash->{lastupdated} = ReadingsVal( $name, '.lastupdated', '' ) if( !$hash->{lastupdated} );
|
||||
$hash->{lastupdated_local} = ReadingsVal( $name, '.lastupdated_local', '' ) if( !$hash->{lastupdated_local} );
|
||||
|
||||
substr($hash->{lastupdated},10, 1, '_' ) if( $hash->{lastupdated} );
|
||||
substr($lastupdated,10, 1, '_' ) if( $lastupdated );
|
||||
my $hlu = SVG_time_to_sec( $hash->{lastupdated} );
|
||||
my $lu = SVG_time_to_sec( $lastupdated );
|
||||
return undef if( $hash->{lastupdated}
|
||||
&& $hlu <= $lu
|
||||
&& !defined($result->{v2_service})
|
||||
#&& $hash->{lastupdated} eq $lastupdated
|
||||
#&& (!defined($readings{state}) || $readings{state} eq ReadingsVal( $name, 'state', '' ))
|
||||
);
|
||||
|
||||
Log3 $name, 4, "$name: lastupdated: $lastupdated, hash->{lastupdated}: $hash->{lastupdated}, lastupdated_local: $lastupdated_local, offsetUTC: $offset";
|
||||
#Log3 $name, 5, "$name: ". Dumper $result if($HUEDevice_hasDataDumper);
|
||||
|
||||
$hash->{lastupdated} = $lastupdated;
|
||||
$hash->{lastupdated_local} = $lastupdated_local;
|
||||
CommandDeleteReading( undef, "$name .lastupdated" );
|
||||
CommandDeleteReading( undef, "$name .lastupdated_local" );
|
||||
|
||||
if( scalar keys %readings ) {
|
||||
readingsBeginUpdate($hash);
|
||||
@ -1825,27 +1814,22 @@ HUEDevice_Parse($$)
|
||||
my $i = 0;
|
||||
foreach my $key ( keys %readings ) {
|
||||
if( defined($readings{$key}) ) {
|
||||
if( $lastupdated_local) {
|
||||
$hash->{'.updateTimestamp'} = $lastupdated_local;
|
||||
$hash->{CHANGETIME}[$i] = $lastupdated_local;
|
||||
my $rut = ReadingsTimestamp($name,$key,undef);
|
||||
if( !defined($result->{v2_service}) && defined($rut) && $ts <= time_str2num($rut) ) {
|
||||
Log3 $name, 4, "$name: ignoring reading $key with timestamp $lastupdated, current reading timestamp is $rut";
|
||||
next;
|
||||
}
|
||||
|
||||
if( $lastupdated ) {
|
||||
$hash->{'.updateTimestamp'} = $lastupdated;
|
||||
$hash->{CHANGETIME}[$i] = $lastupdated;
|
||||
}
|
||||
readingsBulkUpdate($hash, $key, $readings{$key}, 1);
|
||||
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
|
||||
if( $lastupdated_local ) {
|
||||
$hash->{'.updateTimestamp'} = $lastupdated_local;
|
||||
$hash->{CHANGETIME}[$i] = $lastupdated_local;
|
||||
readingsBulkUpdate($hash, '.lastupdated_local', $lastupdated_local, 0);
|
||||
}
|
||||
|
||||
if( $lastupdated ) {
|
||||
readingsBulkUpdate($hash, '.lastupdated', $lastupdated, 0);
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash,1);
|
||||
delete $hash->{CHANGETIME};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user