mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-15 22:26:04 +00:00
48_MieleAtHome: v1.2.0 - support set targetTemperature and mode
git-svn-id: https://svn.fhem.de/fhem/trunk@25100 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
f0d8d23053
commit
ad83e0df00
@ -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.
|
||||
- feature: 48_MieleAtHome: support set targetTemperature and mode
|
||||
- bugfix: 50_Signalbot: Fixed issue with Babble and invite
|
||||
- bugfix: 73_ElectricityCalculator: use Data:Dumper inserted
|
||||
- bugfix: 73_GasCalculator: use Data:Dumper inserted
|
||||
|
@ -35,10 +35,11 @@ use Encode qw(encode_utf8);
|
||||
use List::Util qw[min max];
|
||||
use JSON;
|
||||
|
||||
my $version = "1.1.1";
|
||||
my $version = "1.2.0";
|
||||
|
||||
my $MAH_hasMimeBase64 = 1;
|
||||
|
||||
# DONE: <option value="processAction">processAction</option>
|
||||
use constant PROCESS_ACTIONS => {
|
||||
0x01 => "start", # 1 START
|
||||
0x02 => "stop", # 2 STOP
|
||||
@ -49,11 +50,13 @@ use constant PROCESS_ACTIONS => {
|
||||
0x07 => "stopSuperCooling", # 7 STOP SUPERCOOLING
|
||||
};
|
||||
|
||||
# DONE: <option value="light">light</option>
|
||||
use constant LIGHT_ACTIONS => {
|
||||
0x01 => "enable", # 1 Enable
|
||||
0x02 => "disable", # 2 Disable
|
||||
};
|
||||
|
||||
# DONE: <option value="ventilationStep">ventilationStep</option>
|
||||
use constant VENTILATION_STEPS => {
|
||||
0x01 => "Step1", # 1 Step1
|
||||
0x02 => "Step2", # 2 Step2
|
||||
@ -61,11 +64,20 @@ use constant VENTILATION_STEPS => {
|
||||
0x04 => "Step4", # 4 Step4
|
||||
};
|
||||
|
||||
# DONE: <option value="modes">modes</option>
|
||||
use constant MODE_ACTIONS => {
|
||||
0x00 => "normalOperationMode", # 0 Normal operation mode
|
||||
0x01 => "sabbathMode", # 1 Sabbath mode
|
||||
};
|
||||
|
||||
# DONE: <option value="startTime">startTime</option>
|
||||
# DONE: <option value="powerOff">powerOff</option>
|
||||
# DONE: <option value="powerOn">powerOn</option>
|
||||
# DONE: <option value="targetTemperature">targetTemperature</option>
|
||||
|
||||
# TODO: <option value="programId">programId</option>
|
||||
# TODO: <option value="targetTemperature">targetTemperature</option>
|
||||
# TODO: <option value="deviceName">deviceName</option>
|
||||
# TODO: <option value="colors">colors</option>
|
||||
# TODO: <option value="modes">modes</option>
|
||||
|
||||
use constant COUNTRIES => {
|
||||
"Miele-Deutschland" => "de-DE",
|
||||
@ -404,7 +416,7 @@ sub MAH_SetFn($$@)
|
||||
}
|
||||
elsif( $cmd eq 'startTime') {
|
||||
return "usage: startTime <OFFSET_H:MM>" if(@args != 1);
|
||||
return MAH_setStartTime($hash, $args[0])
|
||||
return MAH_setStartTime($hash, $args[0]);
|
||||
}
|
||||
elsif( $cmd eq 'update' ) {
|
||||
return "use $cmd without arguments" if(@args != 0);
|
||||
@ -413,11 +425,19 @@ sub MAH_SetFn($$@)
|
||||
}
|
||||
elsif( $cmd eq 'ventilationStep') {
|
||||
return "usage: ventilationStep <step>" if(@args != 1);
|
||||
return MAH_setVentilationStep($hash, $args[0])
|
||||
return MAH_setVentilationStep($hash, $args[0]);
|
||||
}
|
||||
elsif( $cmd eq 'light') {
|
||||
return "usage: light enable|disable" if(@args != 1);
|
||||
return MAH_setLight($hash, $args[0])
|
||||
return MAH_setLight($hash, $args[0]);
|
||||
}
|
||||
elsif( $cmd eq 'mode') {
|
||||
return "usage: mode <mode>" if(@args != 1);
|
||||
return MAH_setMode($hash, $args[0]);
|
||||
}
|
||||
elsif( $cmd =~ /targetTemperature_zone([0-9]+)/) {
|
||||
return "usage: targetTemperature_zone${1} <temp>" if(@args != 1);
|
||||
return MAH_setTargetTemperature($hash, $1, $args[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -436,32 +456,49 @@ sub MAH_SetFn($$@)
|
||||
}
|
||||
}
|
||||
|
||||
# light actions
|
||||
my $lightCmds = "";
|
||||
my @lightIds = split(/,/, ReadingsVal($name, "actions_light", ""));
|
||||
foreach my $lightId (@lightIds) {
|
||||
if (defined LIGHT_ACTIONS->{$lightId}) {
|
||||
$lightCmds .= LIGHT_ACTIONS->{$lightId} . ",";
|
||||
}
|
||||
}
|
||||
chop($lightCmds); # remove trailing ','
|
||||
# light
|
||||
my $lightCmds = MAH_getAvailableCommands($hash, "actions_light", LIGHT_ACTIONS());
|
||||
$list .= "light:${lightCmds} " if ($lightCmds ne "");
|
||||
|
||||
# ventilation steps
|
||||
my $ventilationStepCmds = "";
|
||||
my @ventilationStepIds = split(/,/, ReadingsVal($name, "actions_ventilationStep", ""));
|
||||
foreach my $ventilationStepId (@ventilationStepIds) {
|
||||
if (defined VENTILATION_STEPS->{$ventilationStepId}) {
|
||||
$ventilationStepCmds .= VENTILATION_STEPS->{$ventilationStepId} . ",";
|
||||
my $ventilationStepCmds = MAH_getAvailableCommands($hash, "actions_ventilationStep", VENTILATION_STEPS());
|
||||
$list .= "ventilationStep:${ventilationStepCmds} " if ($ventilationStepCmds ne "");
|
||||
|
||||
# modes
|
||||
my $modeCmds = MAH_getAvailableCommands($hash, "actions_modes", MODE_ACTIONS());
|
||||
$list .= "mode:${modeCmds} " if ($modeCmds ne "");
|
||||
|
||||
# target temperatures
|
||||
my @availableTargetTemperatures = split(/ /, ReadingsVal($name, "actions_targetTemperature", ""));
|
||||
foreach my $targetTemperature (@availableTargetTemperatures) {
|
||||
if ($targetTemperature =~ /^([0-9]+)\[(-?[0-9]+),(-?[0-9]+)\]$/) {
|
||||
$list .= "targetTemperature_zone$1:slider,$2,1,$3 "
|
||||
}
|
||||
}
|
||||
chop($ventilationStepCmds); # remove trailing ','
|
||||
$list .= "ventilationStep:${ventilationStepCmds} " if ($ventilationStepCmds ne "");
|
||||
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# returns the strings of the commands from const ACTIONS that are currently available (via `actions_...`)
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
sub MAH_getAvailableCommands($$$)
|
||||
{
|
||||
my ($hash, $action_reading, $ACTIONS) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my $cmds = "";
|
||||
my @ids = split(/,/, ReadingsVal($name, $action_reading, ""));
|
||||
foreach my $id (@ids) {
|
||||
if (defined $ACTIONS->{$id}) {
|
||||
$cmds .= $ACTIONS->{$id} . ",";
|
||||
}
|
||||
}
|
||||
chop($cmds); # remove trailing ','
|
||||
return $cmds;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# SetFn
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
@ -716,7 +753,7 @@ sub MAH_onOauthLoginReply($$$)
|
||||
}
|
||||
|
||||
if ($code eq "") {
|
||||
$code = scrapeGrantAccessPage($hash, $data);
|
||||
$code = MAH_scrapeGrantAccessPage($hash, $data);
|
||||
if ($code ne "") {
|
||||
MAH_Log($hash, 5, "Bearer found in HTML");
|
||||
}
|
||||
@ -731,7 +768,7 @@ sub MAH_onOauthLoginReply($$$)
|
||||
MAH_doThirdpartyTokenRequest($hash, $code, "");
|
||||
}
|
||||
|
||||
sub scrapeGrantAccessPage($$)
|
||||
sub MAH_scrapeGrantAccessPage($$)
|
||||
{
|
||||
my ($hash, $data) = (@_);
|
||||
|
||||
@ -1036,9 +1073,25 @@ sub MAH_onGetDeviceIdentAndStateReply($$$)
|
||||
readingsBulkUpdate($hash, "signalFailure", $json->{state}->{signalFailure});
|
||||
readingsBulkUpdate($hash, "signalInfo", $json->{state}->{signalInfo});
|
||||
|
||||
# target temperature
|
||||
my @targetTemperatures = MAH_decodeTemperature($hash, @{$json->{state}->{targetTemperature}});
|
||||
if (scalar(@targetTemperatures) == 1) {
|
||||
readingsBulkUpdate($hash, "targetTemperature", ${targetTemperatures[0]});
|
||||
} else {
|
||||
for (my $i = 0; $i < scalar(@targetTemperatures); $i++) {
|
||||
readingsBulkUpdate($hash, "targetTemperature_zone".($i+1), ${targetTemperatures[$i]});
|
||||
}
|
||||
}
|
||||
|
||||
# temperature
|
||||
readingsBulkUpdate($hash, "targetTemperature", MAH_decodeTemperature($hash, @{$json->{state}->{targetTemperature}}));
|
||||
readingsBulkUpdate($hash, "temperature", MAH_decodeTemperature($hash, @{$json->{state}->{temperature}}));
|
||||
my @temperatures = MAH_decodeTemperature($hash, @{$json->{state}->{temperature}});
|
||||
if (scalar(@temperatures) == 1) {
|
||||
readingsBulkUpdate($hash, "temperature", ${temperatures[0]});
|
||||
} else {
|
||||
for (my $i = 0; $i < scalar(@temperatures); $i++) {
|
||||
readingsBulkUpdate($hash, "temperature_zone".($i+1), ${temperatures[$i]});
|
||||
}
|
||||
}
|
||||
|
||||
#eta & state
|
||||
my ($eta, $etaHR) = MAH_calculateETA($json->{state}->{remainingTime},
|
||||
@ -1122,27 +1175,20 @@ sub MAH_onGetDeviceActionsReply($$$)
|
||||
return;
|
||||
}
|
||||
|
||||
# possible processAction out of
|
||||
# 1 START
|
||||
# 2 STOP
|
||||
# 3 PAUSE
|
||||
# 4 START SUPERFREEZING
|
||||
# 5 STOP SUPERFREEZING
|
||||
# 6 START SUPERCOOLING
|
||||
# 7 STOP SUPERCOOLING
|
||||
|
||||
no strict "refs";
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "actions_processAction", join(",", @{$json->{processAction}}));
|
||||
readingsBulkUpdate($hash, "actions_light", join(",", @{$json->{light}}));
|
||||
readingsBulkUpdate($hash, "actions_startTime", join(",", @{$json->{startTime}}));
|
||||
readingsBulkUpdate($hash, "actions_ventilationStep", join(",", @{$json->{ventilationStep}}));
|
||||
readingsBulkUpdate($hash, "actions_programId", join(",", @{$json->{programId}}));
|
||||
readingsBulkUpdate($hash, "actions_startTime", join(",", MAH_parseActionsStartTime($json->{startTime})));
|
||||
readingsBulkUpdate($hash, "actions_deviceName", $json->{deviceName});
|
||||
readingsBulkUpdate($hash, "actions_powerOn", defined($json->{powerOn}) ? $json->{powerOn} : "0");
|
||||
readingsBulkUpdate($hash, "actions_powerOff", defined($json->{powerOff}) ? $json->{powerOff} : "0");
|
||||
readingsBulkUpdate($hash, "actions_processAction", join(",", @{$json->{processAction}}));
|
||||
readingsBulkUpdate($hash, "actions_light", join(",", @{$json->{light}}));
|
||||
readingsBulkUpdate($hash, "actions_startTime", join(",", MAH_parseActionsStartTime($json->{startTime})));
|
||||
readingsBulkUpdate($hash, "actions_ventilationStep", join(",", @{$json->{ventilationStep}}));
|
||||
readingsBulkUpdate($hash, "actions_programId", join(",", @{$json->{programId}}));
|
||||
readingsBulkUpdate($hash, "actions_targetTemperature", MAH_parseActionsTargetTemperature($hash,$json->{targetTemperature}));
|
||||
readingsBulkUpdate($hash, "actions_deviceName", $json->{deviceName});
|
||||
readingsBulkUpdate($hash, "actions_powerOff", defined($json->{powerOff}) ? $json->{powerOff} : "0");
|
||||
readingsBulkUpdate($hash, "actions_powerOn", defined($json->{powerOn}) ? $json->{powerOn} : "0");
|
||||
# readingsBulkUpdate($hash, "actions_colors", );
|
||||
readingsBulkUpdate($hash, "actions_modes", join(",", @{$json->{modes}}));
|
||||
readingsEndUpdate($hash, 1 );
|
||||
|
||||
use strict "refs";
|
||||
@ -1152,6 +1198,14 @@ sub MAH_onGetDeviceActionsReply($$$)
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# format time from array
|
||||
# "targetTemperature":[
|
||||
# {"value_raw":600,"value_localized":6.0,"unit":"Celsius"},
|
||||
# {"value_raw":-1800,"value_localized":-18.0,"unit":"Celsius"},
|
||||
# {"value_raw":-32768,"value_localized":null,"unit":"Celsius"}],
|
||||
# "temperature":[
|
||||
# {"value_raw":593,"value_localized":5.93,"unit":"Celsius"},
|
||||
# {"value_raw":-1800,"value_localized":-18.0,"unit":"Celsius"},
|
||||
# {"value_raw":-32768,"value_localized":null,"unit":"Celsius"}],
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
sub MAH_decodeTemperature($@)
|
||||
{
|
||||
@ -1165,7 +1219,7 @@ sub MAH_decodeTemperature($@)
|
||||
}
|
||||
}
|
||||
|
||||
return join(", ", @retval);
|
||||
return @retval;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
@ -1187,6 +1241,40 @@ sub MAH_parseActionsStartTime($)
|
||||
return "[?]";
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# parse the target temperature from actions
|
||||
# [
|
||||
# {
|
||||
# "zone": 1,
|
||||
# "min": 1,
|
||||
# "max": 9
|
||||
# },
|
||||
# {
|
||||
# "zone": 2,
|
||||
# "min": -26,
|
||||
# "max": -16
|
||||
# }
|
||||
# ]
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
sub MAH_parseActionsTargetTemperature($$)
|
||||
{
|
||||
my ($hash,$json) = @_;
|
||||
|
||||
no strict "refs";
|
||||
|
||||
my $retval = "";
|
||||
my @zones = @{$json};
|
||||
for (my $i = 0; $i < scalar(@zones); $i++) {
|
||||
my $zone = $zones[$i];
|
||||
$retval .= $zone->{zone} . "[" . $zone->{min} . "," . $zone->{max} . "] ";
|
||||
}
|
||||
|
||||
use strict "refs";
|
||||
|
||||
chop($retval); # remove trailing space
|
||||
return $retval;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# calculate the estimated time of arrival (as HH:MM and as human readable version)
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
@ -1353,6 +1441,51 @@ sub MAH_setLight($$)
|
||||
return MAH_setAction($hash, "light", "${lightActionId}");
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# MAH_setMode
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
sub MAH_setMode($$)
|
||||
{
|
||||
my ($hash, $modeActionName) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my ($modeActionId) = grep{ MODE_ACTIONS->{$_} eq $modeActionName } keys %{MODE_ACTIONS()};
|
||||
if (!defined $modeActionId) {
|
||||
return "invalid mode action: '${modeActionName}'";
|
||||
}
|
||||
|
||||
my @availableModeActions = split(/,/, ReadingsVal($name, "actions_modes", ""));
|
||||
if (! grep {$_ eq $modeActionId} @availableModeActions) {
|
||||
return "'${modeActionName}' is currently not available";
|
||||
}
|
||||
|
||||
return MAH_setAction($hash, "modes", "${modeActionId}");
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# MAH_setTargetTemperature
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
sub MAH_setTargetTemperature($$$)
|
||||
{
|
||||
my ($hash, $zone, $temp) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my @availableTargetTemperatures = split(/ /, ReadingsVal($name, "actions_targetTemperature", ""));
|
||||
foreach my $targetTemperature (@availableTargetTemperatures) {
|
||||
if ($targetTemperature =~ /^([0-9]+)\[(-?[0-9]+),(-?[0-9]+)\]$/) {
|
||||
if ($1 eq $zone) {
|
||||
if ($2 <= int($temp) && int($temp) <= $3) {
|
||||
return MAH_setAction($hash, "targetTemperature", "[{\"zone\": $zone, \"value\": $temp}]");
|
||||
} else {
|
||||
return "temperature for zone ${zone} out of range, must be between ${2} and ${3}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "zone ${zone} not setable";
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
# MAH_setVentilationStep
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
@ -1829,6 +1962,9 @@ sub MAH_Log($$$)
|
||||
my $subroutine = ( split(':', $modAndSub) )[2];
|
||||
my $name = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : "MieleAtHome";
|
||||
|
||||
# replace non-printable characters by "<xx>"
|
||||
$logMessage =~ s/([\x{00}-\x{1f}\x{7f}-\x{ffffffff}])/'<'.unpack('(H2)',$1).'>'/ge;
|
||||
|
||||
Log3($hash, $logLevel, "${name} (MieleAtHome::${subroutine}:${line}) " . $logMessage);
|
||||
#Log3($hash, $logLevel, "${name} (MieleAtHome::${subroutine}:${line}) Stack was: " . MAH_getStacktrace());
|
||||
}
|
||||
@ -1955,6 +2091,10 @@ sub MAH_getStacktrace()
|
||||
<dt><code><b>light [enable|disable]</b></code></dt>
|
||||
enable/disable the light of your device. only available depending on the type and state of your appliance.
|
||||
</li>
|
||||
<li><a id="MieleAtHome-set-mode"></a>
|
||||
<dt><code><b>mode <mode></b></code></dt>
|
||||
set the <i>mode</i> of your applience. can be either <i>sabbathMode</i> or <i>normalOperationMode</i>.
|
||||
</li>
|
||||
<li><a id="MieleAtHome-set-on"></a>
|
||||
<dt><code><b>on</b></code></dt>
|
||||
power up your device. only available depending on the type and state of your appliance.
|
||||
@ -1999,6 +2139,10 @@ sub MAH_getStacktrace()
|
||||
<dt><code><b>stopSuperCooling</b></code></dt>
|
||||
stop super cooling your device. only available depending on the type and state of your appliance.
|
||||
</li>
|
||||
<li><a id="MieleAtHome-set-targetTemperature"></a>
|
||||
<dt><code><b>targetTemperature_zoneN <temp></b></code></dt>
|
||||
set the <i>targetTemperature</i> of zone <i>N</i> of your applience. The available temperature-range is determined by the Miele-API.
|
||||
</li>
|
||||
<li><a id="MieleAtHome-set-update"></a>
|
||||
<dt><code><b>update</b></code></dt>
|
||||
instantly update all readings.
|
||||
|
Loading…
x
Reference in New Issue
Block a user