2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

32_withings/38_netatmo/72_XiaomiDevice: standard battery readings

git-svn-id: https://svn.fhem.de/fhem/trunk@16763 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
moises 2018-05-21 12:48:24 +00:00
parent c1a3b09eaf
commit bc257843a1
4 changed files with 364 additions and 148 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- change: 32_withings/38_netatmo/72_XiaomiDevice: standard battery readings
- bugfix: 98_dewpoint: Use NOTIFYDEV with framework functions
- feature: 57_Calendar: new parameter "limit" (forum #87566)
- bugfix: 55_DWD_OpenData: updateAlertsCache causing "not a HASH reference"

View File

@ -47,11 +47,11 @@ my %device_types = ( 0 => "User related",
64 => "Thermometer", );
my %device_models = ( 1 => { 1 => "Smart Scale", 2 => "Wireless Scale", 3 => "Smart Kid Scale", 4 => "Smart Body Analyzer", 5 => "WiFi Body Scale", 6 => "Cardio Scale", 7 => "Body Scale", },
2 => { 21 => "Smart Baby Monitor", 22 => "Withings Home", },
4 => { 41 => "iOS Blood Pressure Monitor", 42 => "Wireless Blood Pressure Monitor", },
16 => { 51 => "Pulse Ox", 52 => "Activite", 53 => "Activite v2", 54 => "Withings Go", 55 => "Withings Steel HR", },
32 => { 60 => "Withings Aura", 61 => "Aura Sleep Sensor", },
64 => { 70 => "Withings Thermo", }, );
2 => { 21 => "Smart Baby Monitor", 22 => "Home", 22 => "Home v2", },
4 => { 41 => "iOS Blood Pressure Monitor", 42 => "Wireless Blood Pressure Monitor", 43 => "BPM", 44 => "BPM+", },
16 => { 51 => "Pulse Ox", 52 => "Activite", 53 => "Activite v2", 54 => "Go", 55 => "Steel HR", },
32 => { 60 => "Aura", 61 => "Sleep Sensor", 61 => "Aura v2", 62 => "Sleep Mat", },
64 => { 70 => "Thermo", }, );
#Firmware files: cdnfw_withings_net
#Smart Body Analyzer: /wbs02/wbs02_1521.bin
@ -128,6 +128,7 @@ my %measure_types = ( 1 => { name => "Weight (kg)", reading => "weight", },
93 => { name => "Muscle Mass (%)", reading => "muscleRatio", }, # cardio scale
94 => { name => "Bone Mass (%)", reading => "boneRatio", }, # cardio scale
95 => { name => "Hydration (%)", reading => "hydration", }, # body water
122 => { name => "Pulse Transit Time (ms)", reading => "pulseTransitTime", },
#-10 => { name => "Speed", reading => "speed", },
#-11 => { name => "Pace", reading => "pace", },
#-12 => { name => "Altitude", reading => "altitude", },
@ -884,7 +885,7 @@ sub withings_initDevice($) {
if( !defined( $attr{$name}{stateFormat} ) ) {
$attr{$name}{stateFormat} = "batteryLevel %";
$attr{$name}{stateFormat} = "batteryPercent %";
$attr{$name}{stateFormat} = "co2 ppm" if( $device->{model} == 4 );
$attr{$name}{stateFormat} = "voc ppm" if( $device->{model} == 22 );
@ -916,9 +917,10 @@ sub withings_initUser($) {
my $user = withings_getUserDetail( $hash );
$hash->{shortName} = $user->{shortname};
$hash->{gender} = ($user->{gender}==0)?"male":"female" if( defined($hash->{gender}) );
$hash->{gender} = ($user->{gender}==0)?"male":"female" if( defined($user->{gender}) );
$hash->{userName} = ($user->{firstname}?$user->{firstname}:"") ." ". ($user->{lastname}?$user->{lastname}:"");
$hash->{birthdate} = strftime("%Y-%m-%d", localtime($user->{birthdate})) if( defined($user->{birthdate}) );
$hash->{age} = sprintf("%.1f",((int(time()) - int($user->{birthdate}))/(60*60*24*365.24225))) if( defined($user->{birthdate}) );
$hash->{created} = $user->{created};
$hash->{modified} = $user->{modified};
@ -1767,8 +1769,8 @@ sub withings_parseProperties($$) {
readingsBeginUpdate($hash);
if( defined($detail->{batterylvl}) and $detail->{batterylvl} > 0 and $detail->{type} ne '32' and $detail->{model} ne '22') {
readingsBulkUpdate( $hash, "batteryLevel", $detail->{batterylvl}, 1 );
readingsBulkUpdate( $hash, "battery", ($detail->{batterylvl}>20?"ok":"low"), 1 );
readingsBulkUpdate( $hash, "batteryPercent", $detail->{batterylvl}, 1 );
readingsBulkUpdate( $hash, "batteryState", ($detail->{batterylvl}>20?"ok":"low"), 1 );
}
readingsBulkUpdate( $hash, "lastWeighinDate", FmtDateTime($detail->{lastweighindate}), 1 ) if( defined($detail->{lastweighindate}) and $detail->{lastweighindate} > 0 and $detail->{model} ne '60' );
readingsBulkUpdate( $hash, "lastSessionDate", FmtDateTime($detail->{lastsessiondate}), 1 ) if( defined($detail->{lastsessiondate}) );
@ -3374,9 +3376,9 @@ sub withings_DbLog_splitFn($) {
$reading = 'light';
$unit = 'lux';
}
elsif($event =~ m/batteryLevel/)
elsif($event =~ m/batteryPercent/)
{
$reading = 'batteryLevel';
$reading = 'batteryPercent';
$unit = '%';
}
else
@ -3592,8 +3594,8 @@ sub withings_weekdays2Int( $ ) {
<li>light</li>
<li>noise</li>
<li>voc</li>
<li>battery</li>
<li>batteryLevel</li>
<li>batteryState</li>
<li>batteryPercent</li>
</ul><br>
<a name="withings_Get"></a>

View File

@ -440,6 +440,12 @@ netatmo_Define($$)
$hash->{NOTIFYDEV} = "global";
if(IsDisabled($name) || !defined($name)) {
RemoveInternalTimer($hash);
$hash->{STATE} = "Disabled";
return undef;
}
if( $init_done ) {
netatmo_connect($hash) if( $hash->{SUBTYPE} eq "ACCOUNT" );
netatmo_initDevice($hash) if( $hash->{SUBTYPE} eq "DEVICE" );
@ -507,6 +513,12 @@ netatmo_Notify($$)
RemoveInternalTimer($hash);
if(IsDisabled($name) || !defined($name)) {
RemoveInternalTimer($hash);
$hash->{STATE} = "Disabled";
return undef;
}
netatmo_connect($hash) if( $hash->{SUBTYPE} eq "ACCOUNT" );
netatmo_initDevice($hash) if( $hash->{SUBTYPE} eq "DEVICE" );
netatmo_initDevice($hash) if( $hash->{SUBTYPE} eq "MODULE" );
@ -704,7 +716,7 @@ netatmo_getToken($)
url => "https://".$hash->{helper}{apiserver}."/oauth2/token",
timeout => 5,
noshutdown => 1,
data => {grant_type => 'password', client_id => $hash->{helper}{client_id}, client_secret=> $hash->{helper}{client_secret}, username => netatmo_decrypt($hash->{helper}{username}), password => netatmo_decrypt($hash->{helper}{password}), scope => 'read_station read_thermostat write_thermostat write_camera read_camera access_camera read_presence write_presence access_presence read_homecoach'},
data => {grant_type => 'password', client_id => $hash->{helper}{client_id}, client_secret=> $hash->{helper}{client_secret}, username => netatmo_decrypt($hash->{helper}{username}), password => netatmo_decrypt($hash->{helper}{password}), scope => 'read_station read_thermostat write_thermostat read_camera write_camera access_camera read_presence write_presence access_presence read_homecoach'},
});
netatmo_dispatch( {hash=>$hash,type=>'token'},$err,$data );
@ -1075,6 +1087,12 @@ netatmo_initDevice($)
Log3 $name, 1, "$name: no I/O device";
}
if(IsDisabled($name) || !defined($name)) {
RemoveInternalTimer($hash);
$hash->{STATE} = "Disabled";
return undef;
}
my $device;
if( $hash->{Module} ) {
$device = netatmo_getDeviceDetail( $hash, $hash->{Module} );
@ -1098,8 +1116,8 @@ netatmo_initDevice($)
$hash->{last_seen} = FmtDateTime($device->{last_seen}) if(defined($device->{last_seen}));
$hash->{wifi_status} = $device->{wifi_status} if(defined($device->{wifi_status}));
$hash->{rf_status} = $device->{rf_status} if(defined($device->{rf_status}));
$hash->{battery_percent} = $device->{battery_percent} if(defined($device->{battery_percent}));
$hash->{battery_vp} = $device->{battery_vp} if(defined($device->{battery_vp}));
#$hash->{battery_percent} = $device->{battery_percent} if(defined($device->{battery_percent}));
#$hash->{battery_vp} = $device->{battery_vp} if(defined($device->{battery_vp}));
if( $device->{place} ) {
$hash->{country} = $device->{place}{country};
@ -1110,8 +1128,9 @@ netatmo_initDevice($)
$hash->{location} = $device->{place}{location}[1] .",". $device->{place}{location}[0];
}
readingsSingleUpdate($hash, "battery", ($device->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($device->{battery_percent}));
readingsSingleUpdate($hash, "battery_percent", $device->{battery_percent}, 1) if(defined($device->{battery_percent}));
readingsSingleUpdate($hash, "batteryState", ($device->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($device->{battery_percent}));
readingsSingleUpdate($hash, "batteryPercent", $device->{battery_percent}, 1) if(defined($device->{battery_percent}));
readingsSingleUpdate($hash, "batteryVoltage", $device->{battery_vp}/1000, 1) if(defined($device->{battery_vp}));
my $state_format;
if( $device->{data_type} ) {
@ -1145,7 +1164,11 @@ netatmo_initDevice($)
$attr{$name}{stateFormat} = $state_format if( !defined($attr{$name}{stateFormat}) && defined($state_format) && defined($name) );
return undef if(IsDisabled($name) || !defined($name));
if(IsDisabled($name) || !defined($name)) {
RemoveInternalTimer($hash);
$hash->{STATE} = "Disabled";
return undef;
}
InternalTimer(gettimeofday()+90, "netatmo_poll", $hash);
@ -2497,7 +2520,11 @@ netatmo_poll($)
my $name = $hash->{NAME};
return undef if(IsDisabled($name) || !defined($name));
if(IsDisabled($name) || !defined($name)) {
RemoveInternalTimer($hash);
$hash->{STATE} = "Disabled";
return undef;
}
# my $resolve = inet_aton($hash->{helper}{apiserver});
# if(!defined($resolve))
@ -3383,7 +3410,7 @@ netatmo_parseReadings($$;$)
my $rain_sum = ReadingsVal($name,"rain_sum",0);
$rain_sum += $reading;
readingsSingleUpdate($hash,"rain_sum",$rain_sum,1);
Log3 $name, 1, $name.": summed rain ".$reading." (to ".$rain_sum.")";
Log3 $name, 2, $name.": summed rain ".$reading." (to ".$rain_sum.")";
}
@ -3618,10 +3645,11 @@ netatmo_parseGlobal($$)
$device->{wifi_status} = $devicedata->{wifi_status} if(defined($devicedata->{wifi_status}));
$device->{rf_status} = $devicedata->{rf_status} if(defined($devicedata->{rf_status}));
#$device->{battery_percent} = $devicedata->{battery_percent} if(defined($devicedata->{battery_percent}));
$device->{battery_vp} = $devicedata->{battery_vp} if(defined($devicedata->{battery_vp}));
#$device->{battery_vp} = $devicedata->{battery_vp} if(defined($devicedata->{battery_vp}));
readingsSingleUpdate($device, "battery", ($devicedata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($device, "battery_percent", $devicedata->{battery_percent}, 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($device, "batteryState", ($devicedata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($device, "batteryPercent", $devicedata->{battery_percent}, 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($device, "batteryVoltage", $devicedata->{battery_vp}/1000, 1) if(defined($devicedata->{battery_vp}));
if(defined($devicedata->{modules}))
{
@ -3723,10 +3751,11 @@ netatmo_parseGlobal($$)
$module->{wifi_status} = $moduledata->{wifi_status} if(defined($moduledata->{wifi_status}));
$module->{rf_status} = $moduledata->{rf_status} if(defined($moduledata->{rf_status}));
#$module->{battery_percent} = $moduledata->{battery_percent} if(defined($moduledata->{battery_percent}));
$module->{battery_vp} = $moduledata->{battery_vp} if(defined($moduledata->{battery_vp}));
#$module->{battery_vp} = $moduledata->{battery_vp} if(defined($moduledata->{battery_vp}));
readingsSingleUpdate($module, "battery", ($moduledata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "battery_percent", $moduledata->{battery_percent}, 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "batteryState", ($moduledata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "batteryPercent", $moduledata->{battery_percent}, 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "batteryVoltage", $moduledata->{battery_vp}/1000, 1) if(defined($moduledata->{battery_vp}));
}#foreach module
@ -4092,8 +4121,9 @@ netatmo_parseHomeReadings($$;$)
$tag->{notify_rule} = $tagdata->{notify_rule};
$tag->{notify_rule} = $tagdata->{notify_rule};
readingsSingleUpdate($tag, "battery", ($tagdata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($tagdata->{battery_percent}));
readingsSingleUpdate($tag, "battery_percent", $tagdata->{battery_percent}, 1) if(defined($tagdata->{battery_percent}));
readingsSingleUpdate($tag, "batteryState", ($tagdata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($tagdata->{battery_percent}));
readingsSingleUpdate($tag, "batteryPercent", $tagdata->{battery_percent}, 1) if(defined($tagdata->{battery_percent}));
readingsSingleUpdate($tag, "batteryVoltage", $tagdata->{battery_vp}/1000, 1) if(defined($tagdata->{battery_vp}));
}
@ -4837,7 +4867,7 @@ netatmo_parseThermostatReadings($$;$)
$hash->{wifi_status} = $devicedata->{wifi_status} if(defined($devicedata->{wifi_status}));
$hash->{rf_status} = $devicedata->{rf_status} if(defined($devicedata->{rf_status}));
#$hash->{battery_percent} = $devicedata->{battery_percent} if(defined($devicedata->{battery_percent}));
$hash->{battery_vp} = $devicedata->{battery_vp} if(defined($devicedata->{battery_vp}));
#$hash->{battery_vp} = $devicedata->{battery_vp} if(defined($devicedata->{battery_vp}));
$hash->{therm_orientation} = $devicedata->{therm_orientation} if(defined($devicedata->{therm_orientation}));
$hash->{therm_relay_cmd} = $devicedata->{therm_relay_cmd} if(defined($devicedata->{therm_relay_cmd}));
$hash->{udp_conn} = $devicedata->{udp_conn} if(defined($devicedata->{udp_conn}));
@ -4856,8 +4886,9 @@ netatmo_parseThermostatReadings($$;$)
$hash->{timezone} = encode_utf8($devicedata->{place}{timezone});
}
readingsSingleUpdate($hash, "battery", ($devicedata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($hash, "battery_percent", $devicedata->{battery_percent}, 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($hash, "batteryState", ($devicedata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($hash, "batteryPercent", $devicedata->{battery_percent}, 1) if(defined($devicedata->{battery_percent}));
readingsSingleUpdate($hash, "batteryVoltage", $devicedata->{battery_vp}/1000, 1) if(defined($devicedata->{battery_vp}));
if(defined($devicedata->{modules}))
@ -4885,7 +4916,7 @@ netatmo_parseThermostatReadings($$;$)
$module->{wifi_status} = $moduledata->{wifi_status} if(defined($moduledata->{wifi_status}));
$module->{rf_status} = $moduledata->{rf_status} if(defined($moduledata->{rf_status}));
#$module->{battery_percent} = $moduledata->{battery_percent} if(defined($moduledata->{battery_percent}));
$module->{battery_vp} = $moduledata->{battery_vp} if(defined($moduledata->{battery_vp}));
#$module->{battery_vp} = $moduledata->{battery_vp} if(defined($moduledata->{battery_vp}));
$module->{therm_orientation} = $moduledata->{therm_orientation} if(defined($moduledata->{therm_orientation}));
#$module->{therm_relay_cmd} = $moduledata->{therm_relay_cmd} if(defined($moduledata->{therm_relay_cmd}));
$module->{udp_conn} = $moduledata->{udp_conn} if(defined($moduledata->{udp_conn}));
@ -4904,8 +4935,9 @@ netatmo_parseThermostatReadings($$;$)
$module->{timezone} = encode_utf8($moduledata->{place}{timezone});
}
readingsSingleUpdate($module, "battery", ($moduledata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "battery_percent", $moduledata->{battery_percent}, 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "batteryState", ($moduledata->{battery_percent} > 20) ? "ok" : "low", 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "batteryPercent", $moduledata->{battery_percent}, 1) if(defined($moduledata->{battery_percent}));
readingsSingleUpdate($module, "batteryVoltage", $moduledata->{battery_vp}/1000, 1) if(defined($moduledata->{battery_vp}));
#readingsSingleUpdate($module, "name", encode_utf8($moduledata->{module_name}), 1) if(defined($moduledata->{module_name}));
my $setmode = "manual";
@ -6293,6 +6325,14 @@ sub netatmo_DbLog_splitFn($)
{
$unit = "ug/m3";
}
elsif($event =~ m/batteryPercent/)
{
$unit = "%";
}
elsif($event =~ m/batteryVoltage/)
{
$unit = "V";
}
else
{
$value = $parts[1];

View File

@ -6,7 +6,7 @@
# 2018 Markus Moises < vorname at nachname . de >
#
# This module connects to Xiaomi Smart Home WiFi devices
# Currently supported: AirPurifier, Robot Vacuum, Smart Fan, UV Humidifier, Lamps
# Currently supported: Air Purifier, Robot Vacuum, Smart Fan, UV Humidifier, Lamps, Rice Cooker, Power Plugs
#
# https://forum.fhem.de/index.php/topic,73052.0.html
#
@ -96,6 +96,26 @@ my %vacuum_errors = ( '0' => "None",
'254' => "Bin full",
'255' => "Internal error" , );
my %cooker_menus = ( '0000' => "None",
'0001' => "Cooking",
'0002' => "Quick cooking",
'0003' => "Rice porridge",
'0004' => "Heat preservation",
'0100' => "Personal settings" , );
my %cooker_stages = ( '00' => "Idle",
'01' => "Preheating",
'02' => "Water-absorbing",
'03' => "Boiling",
'04' => "Gelantinizing",
'05' => "Braising" , );
sub XiaomiDevice_Initialize($) {
my ($hash) = @_;
my $name = $hash->{NAME};
@ -108,7 +128,7 @@ sub XiaomiDevice_Initialize($) {
$hash->{WriteFn} = "XiaomiDevice_Write";
$hash->{DbLog_splitFn}= "XiaomiDevice_DbLog_splitFn";
$hash->{AttrFn} = "XiaomiDevice_Attr";
$hash->{AttrList} = "subType:AirPurifier,Humidifier,VacuumCleaner,SmartFan,SmartLamp,EyeCare,WaterPurifier,Camera intervalData intervalSettings preset disable:0,1 zone_names point_names ".
$hash->{AttrList} = "subType:AirPurifier,Humidifier,VacuumCleaner,SmartFan,SmartLamp,EyeCare,WaterPurifier,Camera,RiceCooker,PowerPlug intervalData intervalSettings preset disable:0,1 zone_names point_names ".
$readingFnAttributes;
}
@ -272,6 +292,8 @@ sub XiaomiDevice_Define($$$) {
$attr{$name}{stateFormat} = "power" if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "EyeCare" && !defined($attr{$name}{stateFormat}));
$attr{$name}{stateFormat} = "power" if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "WaterPurifier" && !defined($attr{$name}{stateFormat}));
$attr{$name}{stateFormat} = "power" if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "Camera" && !defined($attr{$name}{stateFormat}));
$attr{$name}{stateFormat} = "method" if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "RiceCooker" && !defined($attr{$name}{stateFormat}));
$attr{$name}{stateFormat} = "power" if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "PowerPlug" && !defined($attr{$name}{stateFormat}));
XiaomiDevice_ReadZones($hash) if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "VacuumCleaner");
@ -300,7 +322,10 @@ sub XiaomiDevice_Get($@) {
my $usage = "Unknown argument $command, choose one of data:noArg settings:noArg wifi_stats:noArg device_info:noArg";
$usage = "Unknown argument $command, choose one of data:noArg settings:noArg clean_summary:noArg sound:noArg timer_clean:noArg timer_dnd:noArg log_status:noArg map serial_number:noArg wifi_stats:noArg device_info:noArg timezone:noArg" if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "VacuumCleaner");
if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "VacuumCleaner"){
$usage = "Unknown argument $command, choose one of data:noArg settings:noArg clean_summary:noArg timer_clean:noArg timer_dnd:noArg log_status:noArg serial_number:noArg wifi_stats:noArg device_info:noArg timezone:noArg";
$usage .= " map sound:noArg" if(!defined($hash->{model}) || $hash->{model} ne "roborock.vacuum.c1");
}
return $usage if $command eq '?';
@ -533,6 +558,17 @@ sub XiaomiDevice_Set($$@) {
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "Camera"){
$list .= " on:noArg off:noArg";
}
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "RiceCooker"){
$list .= " stop:noArg nowarn:noArg ack:noArg";
}
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "PowerPlug"){
$list .= " on:noArg off:noArg";
$list .= " power_mode:green,normal";
$list .= " wifi_led:on,off";
$list .= " rt_power:on,off";
$list .= " usb_power:on,off";
$list .= " power_price";
}
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "VacuumCleaner"){
$list .= ' start:noArg stop:noArg pause:noArg spot:noArg charge:noArg locate:noArg dnd_enabled:on,off dnd_start dnd_end move remotecontrol:start,stop,forward,left,right reset_consumable:filter,mainbrush,sidebrush,sensors timezone volume:slider,0,1,100 volume_test:noArg';
$list .= ' carpet_mode:on,off';
@ -541,6 +577,7 @@ sub XiaomiDevice_Set($$@) {
$list .= ' fan_power:slider,1,1,100' if(defined($hash->{model}) && $hash->{model} eq "rockrobo.vacuum.v1");
$list .= ' cleaning_mode:quiet,balanced,turbo,max,mop';
if(!defined($hash->{model}) || $hash->{model} ne "roborock.vacuum.c1") {
if(defined($hash->{helper}{zone_names})) {
$list .= ' zone:'.$hash->{helper}{zone_names};
} else {
@ -551,6 +588,7 @@ sub XiaomiDevice_Set($$@) {
} else {
$list .= ' goto';
}
}
if (defined($hash->{helper}{timers})&&($hash->{helper}{timers}>0))
{
@ -707,8 +745,12 @@ sub XiaomiDevice_Set($$@) {
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "app_stop";
if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "RiceCooker") {
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_func","params":["end02"]}' );
} else {
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"app_stop","params":[""]}' );
}
}
elsif ($cmd eq 'spot')
{
my $packetid = $hash->{helper}{packetid};
@ -915,7 +957,7 @@ sub XiaomiDevice_Set($$@) {
}
elsif($cmd =~ /_days/)
{
my @time = split(":",ReadingsVal($name, "timer".$timerno."_time","00:00" ));
my @time = split(":",ReadingsVal($name, "timer".$timerno."_time","12:00" ));
my $daysstring = join(" ", @arg);
my $program = ReadingsVal($name, "timer".$timerno."_program","start_clean" );
my $power = ReadingsVal($name, "timer".$timerno."_power","77" );
@ -945,7 +987,7 @@ sub XiaomiDevice_Set($$@) {
}
elsif($cmd =~ /_program/)
{
my @time = split(":",ReadingsVal($name, "timer".$timerno."_time","00:00" ));
my @time = split(":",ReadingsVal($name, "timer".$timerno."_time","12:00" ));
my $daysstring = ReadingsVal($name, "timer".$timerno."_days","all" );
my $program = $arg[0];
my $power = ReadingsVal($name, "timer".$timerno."_power","77" );
@ -975,7 +1017,7 @@ sub XiaomiDevice_Set($$@) {
}
elsif($cmd =~ /_power/)
{
my @time = split(":",ReadingsVal($name, "timer".$timerno."_time","00:00" ));
my @time = split(":",ReadingsVal($name, "timer".$timerno."_time","12:00" ));
my $daysstring = ReadingsVal($name, "timer".$timerno."_days","all" );
my $program = ReadingsVal($name, "timer".$timerno."_program","start_clean" );
my $power = $arg[0];
@ -1377,6 +1419,57 @@ sub XiaomiDevice_Set($$@) {
return "WiFi configuration updated.\n\nSSID: ".$arg[0]."\nPassword: ".$arg[1];
}
}
elsif ($cmd eq 'nowarn')
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "nowarn";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_func","params":["nowarn"]}' );
}
elsif ($cmd eq 'ack')
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "ack";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_func","params":["ack"]}' );
}
elsif ($cmd eq 'power_mode')#green,normal
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "power_mode";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_power_mode","params":["'.$arg[0].'"]}' );
}
elsif ($cmd eq 'power_price')#1..999
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "power_price";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_power_price","params":['.$arg[0].']}' );
}
elsif ($cmd eq 'wifi_led')#on,off
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "wifi_led";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_wifi_led","params":["'.$arg[0].'"]}' );
}
elsif ($cmd eq 'rt_power')#on,off
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "rt_power";
$arg[0] = ($arg[0] eq "on") ? 1 : 0;
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"set_rt_power","params":['.$arg[0].']}' );
}
elsif ($cmd eq 'usb_power')#on,off
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "usb_power";
$arg[0] = ($arg[0] eq "on") ? "set_usb_on" : "set_usb_off";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"'.$arg[0].'","params":[]}' );
}
else
{
return SetExtensions($hash, $list, $name, @aa) if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "AirPurifier");
@ -1512,13 +1605,23 @@ sub XiaomiDevice_GetUpdate($)
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "WaterPurifier")
{
$hash->{helper}{packet}{$packetid} = "water_data";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"get_prop","params":["mode","tds","filter1_life","filter1_state","filter_life","filter_state","life","state","level","volume","filter","usage"]}' );
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"get_prop","params":["power","mode","tds","filter1_life","filter1_state","filter_life","filter_state","life","state","level","volume","filter","usage","temperature","uv_life","uv_state","elecval_state"]}' );
}
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "Camera")
{
$hash->{helper}{packet}{$packetid} = "camera_data";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"get_prop","params":["auto_low_light"]}' );
}
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "RiceCooker")
{
$hash->{helper}{packet}{$packetid} = "ricecooker_data";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"get_prop","params":["func", "menu", "stage", "temp", "t_func", "t_precook", "t_cook", "setting", "delay", "version"]}' );
}
elsif( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "PowerPlug")
{
$hash->{helper}{packet}{$packetid} = "powerplug_data";
XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"get_prop","params":["power", "temperature", "current", "mode", "power_consume_rate", "wifi_led", "power_price", "voltage", "power_factor", "elec_leakage"]}' );
}
return undef;
}
@ -1583,6 +1686,18 @@ sub XiaomiDevice_GetSettings($)
return undef;
}
if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "RiceCooker")
{
return undef;
}
if( defined($attr{$name}) && defined($attr{$name}{subType}) && $attr{$name}{subType} eq "PowerPlug")
{
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
$hash->{helper}{packet}{$packetid} = "powerplug_data";
return XiaomiDevice_WriteJSON($hash, '{"id":'.$packetid.',"method":"get_prop","params":["power", "temperature", "current", "mode", "power_consume_rate", "wifi_led", "power_price"]}' );
}
my $packetid = $hash->{helper}{packetid};
$hash->{helper}{packetid} = $packetid+1;
@ -2001,8 +2116,8 @@ sub XiaomiDevice_ParseJSON($$)
readingsBulkUpdate( $hash, "angle_enable", $json->{result}[1], 1 ) if(defined($json->{result}[1]));
readingsBulkUpdate( $hash, "power", $json->{result}[2], 1 ) if(defined($json->{result}[2]));
readingsBulkUpdate( $hash, "charging", $json->{result}[3], 1 ) if(defined($json->{result}[3]));
readingsBulkUpdate( $hash, "batteryLevel", $json->{result}[4], 1 ) if(defined($json->{result}[4]));
readingsBulkUpdate( $hash, "battery", int($json->{result}[4])<20 ? "low" : "ok", 1 ) if(defined($json->{result}[4]));
readingsBulkUpdate( $hash, "batteryPercent", $json->{result}[4], 1 ) if(defined($json->{result}[4]));
readingsBulkUpdate( $hash, "batteryState", int($json->{result}[4])<20 ? "low" : "ok", 1 ) if(defined($json->{result}[4]));
my $fanspeed = 0;
$fanspeed = $json->{result}[5] if(defined($json->{result}[5]));
$fanspeed = $json->{result}[6] if(defined($json->{result}[6]) && int($json->{result}[6])>0);
@ -2044,18 +2159,23 @@ sub XiaomiDevice_ParseJSON($$)
return undef if(!defined($json->{result}));
return undef if(ref($json->{result}) ne "ARRAY");
readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, "mode", $json->{result}[0], 1 ) if(defined($json->{result}[0]));
readingsBulkUpdate( $hash, "tds", $json->{result}[1], 1 ) if(defined($json->{result}[1]));
readingsBulkUpdate( $hash, "filter1_life", $json->{result}[2], 1 ) if(defined($json->{result}[2]));
readingsBulkUpdate( $hash, "filter1_state", ($json->{result}[3]), 1 ) if(defined($json->{result}[3]));
readingsBulkUpdate( $hash, "filter_life", $json->{result}[4], 1 ) if(defined($json->{result}[4]));
readingsBulkUpdate( $hash, "filter_state", $json->{result}[5], 1 ) if(defined($json->{result}[5]));
readingsBulkUpdate( $hash, "life", $json->{result}[6], 1 ) if(defined($json->{result}[6]));
readingsBulkUpdate( $hash, "state", $json->{result}[7], 1 ) if(defined($json->{result}[7]));
readingsBulkUpdate( $hash, "level", $json->{result}[8], 1 ) if(defined($json->{result}[8]));
readingsBulkUpdate( $hash, "volume", $json->{result}[9], 1 ) if(defined($json->{result}[9]));
readingsBulkUpdate( $hash, "filter", $json->{result}[10], 1 ) if(defined($json->{result}[10]));
readingsBulkUpdate( $hash, "usage", $json->{result}[11], 1 ) if(defined($json->{result}[11]));
readingsBulkUpdate( $hash, "power", $json->{result}[0], 1 ) if(defined($json->{result}[0]));
readingsBulkUpdate( $hash, "mode", $json->{result}[1], 1 ) if(defined($json->{result}[1]));
readingsBulkUpdate( $hash, "tds", $json->{result}[2], 1 ) if(defined($json->{result}[2]));
readingsBulkUpdate( $hash, "filter1_life", $json->{result}[3], 1 ) if(defined($json->{result}[3]));
readingsBulkUpdate( $hash, "filter1_state", ($json->{result}[4]), 1 ) if(defined($json->{result}[4]));
readingsBulkUpdate( $hash, "filter_life", $json->{result}[5], 1 ) if(defined($json->{result}[5]));
readingsBulkUpdate( $hash, "filter_state", $json->{result}[6], 1 ) if(defined($json->{result}[6]));
readingsBulkUpdate( $hash, "life", $json->{result}[7], 1 ) if(defined($json->{result}[7]));
readingsBulkUpdate( $hash, "state", $json->{result}[8], 1 ) if(defined($json->{result}[8]));
readingsBulkUpdate( $hash, "level", $json->{result}[9], 1 ) if(defined($json->{result}[9]));
readingsBulkUpdate( $hash, "volume", $json->{result}[10], 1 ) if(defined($json->{result}[10]));
readingsBulkUpdate( $hash, "filter", $json->{result}[11], 1 ) if(defined($json->{result}[11]));
readingsBulkUpdate( $hash, "usage", $json->{result}[12], 1 ) if(defined($json->{result}[12]));
readingsBulkUpdate( $hash, "temperature", $json->{result}[13], 1 ) if(defined($json->{result}[13]));
readingsBulkUpdate( $hash, "uv_life", $json->{result}[14], 1 ) if(defined($json->{result}[14]));
readingsBulkUpdate( $hash, "uv_state", $json->{result}[15], 1 ) if(defined($json->{result}[15]));
readingsBulkUpdate( $hash, "elecval_state", $json->{result}[16], 1 ) if(defined($json->{result}[16]));
readingsEndUpdate($hash,1);
return undef;
}
@ -2070,6 +2190,49 @@ sub XiaomiDevice_ParseJSON($$)
return undef;
}
if($msgtype eq "ricecooker_data")
{
return undef if(!defined($json->{result}));
return undef if(ref($json->{result}) ne "ARRAY");
readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, "func", $json->{result}[0], 1 ) if(defined($json->{result}[0]));
readingsBulkUpdate( $hash, "menu", $cooker_menus{$json->{result}[1]}, 1 ) if(defined($json->{result}[1]));
#readingsBulkUpdate( $hash, "menu", $json->{result}[1], 1 ) if(defined($json->{result}[1]));
readingsBulkUpdate( $hash, "stage", $cooker_stages{substr($json->{result}[1],0,2)}, 1 ) if(defined($json->{result}[2]));
#readingsBulkUpdate( $hash, "stage", $json->{result}[2], 1 ) if(defined($json->{result}[2]));
readingsBulkUpdate( $hash, "temp", unpack('H*', substr($json->{result}[3],-2)), 1 ) if(defined($json->{result}[3]));
#readingsBulkUpdate( $hash, "temp", $json->{result}[3], 1 ) if(defined($json->{result}[3]));
readingsBulkUpdate( $hash, "t_func", $json->{result}[4], 1 ) if(defined($json->{result}[4]));
readingsBulkUpdate( $hash, "t_precook", $json->{result}[5], 1 ) if(defined($json->{result}[5]));
readingsBulkUpdate( $hash, "t_cook", $json->{result}[6], 1 ) if(defined($json->{result}[6]));
readingsBulkUpdate( $hash, "setting", $json->{result}[7], 1 ) if(defined($json->{result}[7]));
readingsBulkUpdate( $hash, "delay", $json->{result}[8], 1 ) if(defined($json->{result}[8]));
readingsBulkUpdate( $hash, "version", $json->{result}[9], 1 ) if(defined($json->{result}[9]));
readingsEndUpdate($hash,1);
return undef;
}
if($msgtype eq "powerplug_data")
{
return undef if(!defined($json->{result}));
return undef if(ref($json->{result}) ne "ARRAY");
return undef if(ref($json->{result}[0]) ne "HASH");
readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, "power", $json->{result}[0]{power}, 1 ) if(defined($json->{result}[0]{power}));
readingsBulkUpdate( $hash, "temperature", $json->{result}[0]{temperature}, 1 ) if(defined($json->{result}[0]{temperature}));
readingsBulkUpdate( $hash, "current", $json->{result}[0]{current}, 1 ) if(defined($json->{result}[0]{current}));
readingsBulkUpdate( $hash, "power_mode", $json->{result}[0]{mode}, 1 ) if(defined($json->{result}[0]{mode}));
readingsBulkUpdate( $hash, "power_consume_rate", $json->{result}[0]{power_consume_rate}, 1 ) if(defined($json->{result}[0]{power_consume_rate}));
readingsBulkUpdate( $hash, "wifi_led", $json->{result}[0]{wifi_led}, 1 ) if(defined($json->{result}[0]{wifi_led}));
readingsBulkUpdate( $hash, "power_price", $json->{result}[0]{power_price}, 1 ) if(defined($json->{result}[0]{power_price}));
readingsBulkUpdate( $hash, "voltage", $json->{result}[0]{voltage}, 1 ) if(defined($json->{result}[0]{voltage}));
readingsBulkUpdate( $hash, "power_factor", $json->{result}[0]{power_factor}, 1 ) if(defined($json->{result}[0]{power_factor}));
readingsBulkUpdate( $hash, "elec_leakage", $json->{result}[0]{elec_leakage}, 1 ) if(defined($json->{result}[0]{elec_leakage}));
#readingsBulkUpdate( $hash, "setting", (($json->{result}[0]{setting} eq "1")?"yes":"no"), 1 ) if(defined($json->{result}[0]{setting}));
readingsEndUpdate($hash,1);
return undef;
}
#{ "result": [ { "msg_ver": 3, "msg_seq": 4, "state": 8, "battery": 100, "clean_time": 3, "clean_area": 0, "error_code": 0, "map_present": 0, "in_cleaning": 0, "fan_power": 10, "dnd_enabled": 1 } ], "id": 1201 }
if($msgtype eq "get_status")
{
@ -2097,8 +2260,8 @@ sub XiaomiDevice_ParseJSON($$)
} elsif(defined($json->{result}[0]{state})) {
readingsBulkUpdate( $hash, "state", $vacuum_states{$json->{result}[0]{state}}, 1 );
}
readingsBulkUpdate( $hash, "batteryLevel", $json->{result}[0]{battery}, 1 ) if(defined($json->{result}[0]{battery}));
readingsBulkUpdate( $hash, "battery", int($json->{result}[0]{battery})<20 ? "low" : "ok", 1 ) if(defined($json->{result}[0]{battery}));
readingsBulkUpdate( $hash, "batteryPercent", $json->{result}[0]{battery}, 1 ) if(defined($json->{result}[0]{battery}));
readingsBulkUpdate( $hash, "batteryState", int($json->{result}[0]{battery})<20 ? "low" : "ok", 1 ) if(defined($json->{result}[0]{battery}));
readingsBulkUpdate( $hash, "last_clean_time", sprintf( "%.2f" ,int($json->{result}[0]{clean_time})/3600), 1) if(defined($json->{result}[0]{clean_time}));#sprintf( "%.1f", int($json->{result}[0]{clean_time})/3600), 1 );
readingsBulkUpdate( $hash, "last_clean_area", sprintf( "%.2f" ,int($json->{result}[0]{clean_area})/1000000), 1 ) if(defined($json->{result}[0]{clean_area}));
readingsBulkUpdate( $hash, "error_code", $vacuum_errors{$json->{result}[0]{error_code}}, 1 ) if(defined($json->{result}[0]{error_code}));
@ -2351,6 +2514,7 @@ sub XiaomiDevice_ParseJSON($$)
{
return undef if(!defined($json->{result}));
return undef if(ref($json->{result}) ne "ARRAY");
return readingsSingleUpdate( $hash, "serial_number", $json->{result}[0], 1 ) if(defined($json->{result}[0]) && ref($json->{result}[0]) eq "");
readingsSingleUpdate( $hash, "serial_number", $json->{result}[0]{serial_number}, 1 ) if(defined($json->{result}[0]{serial_number}));
return undef;
}
@ -2381,12 +2545,16 @@ sub XiaomiDevice_ParseJSON($$)
$hash->{mac} = $json->{result}{mac} if(defined($json->{result}{mac}));
$hash->{token} = $json->{result}{token} if(defined($json->{result}{token}));
$hash->{wifi_firmware} = $json->{result}{wifi_fw_ver} if(defined($json->{result}{wifi_fw_ver}));
$hash->{mcu_firmware} = $json->{result}{mcu_fw_ver} if(defined($json->{result}{mcu_fw_ver}));
$hash->{hardware} = $json->{result}{hw_ver} if(defined($json->{result}{hw_ver}));
return undef;
}
if($msgtype eq "get_current_sound")
{
return undef if(!defined($json->{result}));
return undef if(ref($json->{result}) ne "ARRAY");
return readingsSingleUpdate( $hash, "current_sound", $json->{result}[0], 1 ) if(defined($json->{result}[0]) && ref($json->{result}[0]) eq "");
return undef if(ref($json->{result}[0]) ne "HASH");
readingsSingleUpdate( $hash, "current_sound", ($json->{result}[0]{sid_in_use} eq "3" ? "english" : "chinese"), 1 ) if(defined($json->{result}[0]{sid_in_use}));
return undef;
}
@ -2394,7 +2562,8 @@ sub XiaomiDevice_ParseJSON($$)
{
return undef if(!defined($json->{result}));
return undef if(ref($json->{result}) ne "ARRAY");
readingsSingleUpdate( $hash, "timezone", $json->{result}[0], 1 ) if(defined($json->{result}[0]));
return readingsSingleUpdate( $hash, "timezone", $json->{result}[0], 1 ) if(defined($json->{result}[0]) && ref($json->{result}[0]) eq "");
readingsSingleUpdate( $hash, "timezone", $json->{result}[0]{olson}, 1 ) if(defined($json->{result}[0]) && ref($json->{result}[0]) eq "HASH" && defined($json->{result}[0]{olson}));
return undef;
}
@ -2419,6 +2588,10 @@ sub XiaomiDevice_ParseJSON($$)
return InternalTimer( gettimeofday() + 2, "XiaomiDevice_GetSpeed", $hash) if($msgtype eq "set_limit_hum");
return InternalTimer( gettimeofday() + 5, "XiaomiDevice_GetUpdate", $hash) if($msgtype eq "nowarn" || $msgtype eq "ack");
return InternalTimer( gettimeofday() + 5, "XiaomiDevice_GetUpdate", $hash) if($msgtype eq "power_mode" || $msgtype eq "power_price" || $msgtype eq "wifi_led" || $msgtype eq "usb_power" || $msgtype eq "rt_power");
return readingsSingleUpdate( $hash, "power", "off", 1 ) if($msgtype eq "power_off");
return readingsSingleUpdate( $hash, "power", "on", 1 ) if($msgtype eq "power_on");
return readingsSingleUpdate( $hash, "mode", "natural", 1 ) if($msgtype eq "mode_natural");
@ -2775,7 +2948,7 @@ sub XiaomiDevice_DbLog_splitFn($) {
$unit = "˚C" if($reading =~ /temperature/);
$unit = "h" if($reading =~ /usage/);
$unit = "m³" if($reading =~ /volume/);
$unit = "%" if($reading =~ /batteryLevel/);;
$unit = "%" if($reading =~ /batteryPercent/);;
$unit = "%" if($reading =~ /fan_power/);;
$unit = "h" if($reading =~ /clean_time/);;
$unit = "m²" if($reading =~ /clean_area/);;
@ -3040,7 +3213,7 @@ sub XiaomiDevice_DbLog_splitFn($) {
<ul>
<li><code>subType</code>
<br>
VacuumCleaner / AirPurifier / SmartFan / Humidifier
VacuumCleaner / AirPurifier / SmartFan / Humidifier / RiceCooker / PowerPlug
</li><br>
<li><code>disable</code>
<br>