mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-08 19:32:42 +00:00
MAX: better input validation, setters for ["boostDuration","boostValveposition", "decalcification","maxValveSetting","valveOffset"]
git-svn-id: https://svn.fhem.de/fhem/trunk@2489 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
a939707de8
commit
1024d0b4c7
@ -11,6 +11,7 @@ use POSIX;
|
|||||||
require "10_MAX.pm";
|
require "10_MAX.pm";
|
||||||
our %msgCmd2Id;
|
our %msgCmd2Id;
|
||||||
our %device_types;
|
our %device_types;
|
||||||
|
our %boost_durations;
|
||||||
|
|
||||||
sub MAXLAN_Parse($$);
|
sub MAXLAN_Parse($$);
|
||||||
sub MAXLAN_Read($);
|
sub MAXLAN_Read($);
|
||||||
@ -22,8 +23,6 @@ sub MAXLAN_Send(@);
|
|||||||
sub MAXLAN_RequestConfiguration($$);
|
sub MAXLAN_RequestConfiguration($$);
|
||||||
sub MAXLAN_RemoveDevice($$);
|
sub MAXLAN_RemoveDevice($$);
|
||||||
|
|
||||||
my @boost_durations = (0, 5, 10, 15, 20, 25, 30, 60);
|
|
||||||
|
|
||||||
my $reconnect_interval = 2; #seconds
|
my $reconnect_interval = 2; #seconds
|
||||||
|
|
||||||
#the time it takes after sending one command till we see its effect in the L: response
|
#the time it takes after sending one command till we see its effect in the L: response
|
||||||
@ -527,7 +526,7 @@ MAXLAN_Parse($$)
|
|||||||
my ($comforttemp,$ecotemp,$maxsetpointtemp,$minsetpointtemp,$tempoffset,$windowopentemp,$windowopendur,$boost,$decalcifiction,$maxvalvesetting,$valveoffset,$weekprofile) = unpack("CCCCCCCCCCCH*",substr($bindata,18));
|
my ($comforttemp,$ecotemp,$maxsetpointtemp,$minsetpointtemp,$tempoffset,$windowopentemp,$windowopendur,$boost,$decalcifiction,$maxvalvesetting,$valveoffset,$weekprofile) = unpack("CCCCCCCCCCCH*",substr($bindata,18));
|
||||||
#TODO: parse week profile
|
#TODO: parse week profile
|
||||||
my $boostValve = ($boost & 0x1F) * 5;
|
my $boostValve = ($boost & 0x1F) * 5;
|
||||||
my $boostDuration = $boost_durations[$boost >> 5]; #in minutes
|
my $boostDuration = $boost_durations{$boost >> 5}; #in minutes
|
||||||
#There is some trailing data missing, which maps to the weekly program
|
#There is some trailing data missing, which maps to the weekly program
|
||||||
$comforttemp /= 2.0; #convert to degree celcius
|
$comforttemp /= 2.0; #convert to degree celcius
|
||||||
$ecotemp /= 2.0; #convert to degree celcius
|
$ecotemp /= 2.0; #convert to degree celcius
|
||||||
|
@ -30,14 +30,33 @@ use vars qw(%msgCmd2Id);
|
|||||||
5 => "PushButton"
|
5 => "PushButton"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my %boost_durations = (0 => 0, 1 => 5, 2 => 10, 3 => 15, 4 => 20, 5 => 25, 6 => 30, 7 => 60);
|
||||||
|
my %boost_durationsInv = reverse %boost_durations;
|
||||||
|
|
||||||
|
my %decalcDays = (0 => "Sat", 1 => "Sun", 2 => "Mon", 3 => "Tue", 4 => "Wed", 5 => "Thu", 6 => "Fri");
|
||||||
|
my %decalcDaysInv = reverse %decalcDays;
|
||||||
|
|
||||||
|
sub validTemperature { return $_[0] eq "on" || $_[0] eq "off" || ($_[0] ~~ /^\d+(\.[05])?$/ && $_[0] >= 5 && $_[0] <= 30); }
|
||||||
|
sub validWindowOpenDuration { return $_[0] ~~ /^\d+$/ && $_[0] >= 0 && $_[0] <= 60; }
|
||||||
|
sub validMeasurementOffset { return $_[0] ~~ /^-?\d+(\.[05])?$/ && $_[0] >= -3.5 && $_[0] <= 3.5; }
|
||||||
|
sub validBoostDuration { return $_[0] ~~ /^\d+$/ && exists($boost_durationsInv{$_[0]}); }
|
||||||
|
sub validValveposition { return $_[0] ~~ /^\d+$/ && $_[0] >= 0 && $_[0] <= 100; }
|
||||||
|
sub validDecalcification { my ($decalcDay, $decalcHour) = ($_[0] =~ /^(..), (\d{1,2}):00$/);
|
||||||
|
return defined($decalcDay) && defined($decalcHour) && exists($decalcDaysInv{$decalcDay}) && 0 <= $decalcHour && $decalcHour < 24; }
|
||||||
|
|
||||||
my %readingDef = ( #min/max/default
|
my %readingDef = ( #min/max/default
|
||||||
"maximumTemperature" => [4.5, 30.5, 30.5],
|
"maximumTemperature" => [ \&validTemperature, 30.5],
|
||||||
"minimumTemperature" => [4.5, 30.5, 4.5],
|
"minimumTemperature" => [ \&validTemperature, 4.5],
|
||||||
"comfortTemperature" => [4.5, 30.5, 21],
|
"comfortTemperature" => [ \&validTemperature, 21],
|
||||||
"ecoTemperature" => [4.5, 30.5, 17],
|
"ecoTemperature" => [ \&validTemperature, 17],
|
||||||
"windowOpenTemperature" => [4.5, 30.5, 12],
|
"windowOpenTemperature" => [ \&validTemperature, 12],
|
||||||
"windowOpenDuration" => [0, 60, 15],
|
"windowOpenDuration" => [ \&validWindowOpenDuration, 15],
|
||||||
"measurementOffset" => [-3.5, 3.5, 0]
|
"measurementOffset" => [ \&validMeasurementOffset, 0],
|
||||||
|
"boostDuration" => [ \&validBoostDuration, 5 ],
|
||||||
|
"boostValveposition" => [ \&validValveposition, 80 ],
|
||||||
|
"decalcification" => [ \&validDecalcification, "Sat, 12:00" ],
|
||||||
|
"maxValveSetting" => [ \&validValveposition, 100 ],
|
||||||
|
"valveOffset" => [ \&validValveposition, 00 ],
|
||||||
);
|
);
|
||||||
|
|
||||||
%msgId2Cmd = (
|
%msgId2Cmd = (
|
||||||
@ -46,7 +65,8 @@ my %readingDef = ( #min/max/default
|
|||||||
"02" => "Ack",
|
"02" => "Ack",
|
||||||
"03" => "TimeInformation",
|
"03" => "TimeInformation",
|
||||||
"10" => "ConfigWeekProfile",
|
"10" => "ConfigWeekProfile",
|
||||||
"11" => "ConfigTemperatures", #like boost/eco/comfort etc
|
"11" => "ConfigTemperatures", #like eco/comfort etc
|
||||||
|
"12" => "ConfigValve",
|
||||||
"30" => "ShutterContactState",
|
"30" => "ShutterContactState",
|
||||||
"42" => "WallThermostatState", #by WallMountedThermostat
|
"42" => "WallThermostatState", #by WallMountedThermostat
|
||||||
"50" => "PushButtonState",
|
"50" => "PushButtonState",
|
||||||
@ -62,8 +82,6 @@ my %readingDef = ( #min/max/default
|
|||||||
);
|
);
|
||||||
%msgCmd2Id = reverse %msgId2Cmd;
|
%msgCmd2Id = reverse %msgId2Cmd;
|
||||||
|
|
||||||
my @decalcDays = ("Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri");
|
|
||||||
|
|
||||||
my %interfaces = (
|
my %interfaces = (
|
||||||
"Cube" => undef,
|
"Cube" => undef,
|
||||||
"HeatingThermostat" => "thermostat;battery;temperature",
|
"HeatingThermostat" => "thermostat;battery;temperature",
|
||||||
@ -155,18 +173,27 @@ MAX_ParseTemperature($)
|
|||||||
return @_[0] eq "on" ? 30.5 : (@_[0] eq "off" ? 4.5 :@_[0]);
|
return @_[0] eq "on" ? 30.5 : (@_[0] eq "off" ? 4.5 :@_[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
MAX_Validate(@)
|
||||||
|
{
|
||||||
|
my ($name,$val) = @_;
|
||||||
|
return 1 if(!exists($readingDef{$name}));
|
||||||
|
return $readingDef{$name}[0]->($val);
|
||||||
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
MAX_ReadingsVal(@)
|
MAX_ReadingsVal(@)
|
||||||
{
|
{
|
||||||
my ($hash,$name) = @_;
|
my ($hash,$name) = @_;
|
||||||
|
|
||||||
my $val = MAX_ParseTemperature(ReadingsVal($hash->{NAME},$name,""));
|
my $val = MAX_ParseTemperature(ReadingsVal($hash->{NAME},$name,""));
|
||||||
#$readingDef{$name} array is [min, max, default]
|
#$readingDef{$name} array is [validatingFunc, defaultValue]
|
||||||
if(exists($readingDef{$name}) and
|
if(exists($readingDef{$name}) and !$readingDef{$name}[0]->($val)) {
|
||||||
($val eq "" or $val !~ /^-?(\d+\.?\d*|\.\d+)$/ or $val < $readingDef{$name}[0] or $val > $readingDef{$name}[1])) {
|
|
||||||
#Error: invalid value
|
#Error: invalid value
|
||||||
Log 2, "MAX: Invalid value $val for READING $name. Forcing to $readingDef{$name}[2]";
|
Log 2, "MAX: Invalid value $val for READING $name. Forcing to $readingDef{$name}[1]";
|
||||||
$val = $readingDef{$name}[2];
|
$val = $readingDef{$name}[1];
|
||||||
|
|
||||||
|
#Save default value to READINGS
|
||||||
if(exists($hash->{".updateTimestamp"})) {
|
if(exists($hash->{".updateTimestamp"})) {
|
||||||
readingsBulkUpdate($hash,$name,$val);
|
readingsBulkUpdate($hash,$name,$val);
|
||||||
} else {
|
} else {
|
||||||
@ -185,7 +212,7 @@ MAX_Set($@)
|
|||||||
|
|
||||||
return "Invalid IODev" if(MAX_CheckIODev($hash));
|
return "Invalid IODev" if(MAX_CheckIODev($hash));
|
||||||
|
|
||||||
if($setting eq "desiredTemperature" and ($hash->{type} eq "HeatingThermostat" or $hash->{type} eq "WallMountedThermostat")) {
|
if($setting eq "desiredTemperature" and $hash->{type} ~~ ["HeatingThermostat","WallMountedThermostat"]) {
|
||||||
return "missing a value" if(@args == 0);
|
return "missing a value" if(@args == 0);
|
||||||
|
|
||||||
my $temperature;
|
my $temperature;
|
||||||
@ -219,6 +246,30 @@ MAX_Set($@)
|
|||||||
$payload .= $until if(defined($until));
|
$payload .= $until if(defined($until));
|
||||||
return ($hash->{IODev}{Send})->($hash->{IODev},"SetTemperature",$hash->{addr},$payload);
|
return ($hash->{IODev}{Send})->($hash->{IODev},"SetTemperature",$hash->{addr},$payload);
|
||||||
|
|
||||||
|
}elsif($setting ~~ ["boostDuration", "boostValveposition", "decalcification","maxValveSetting","valveOffset"]
|
||||||
|
and $hash->{type} ~~ ["HeatingThermostat","WallMountedThermostat"]){
|
||||||
|
|
||||||
|
if(!MAX_Validate($setting, $args[0])) {
|
||||||
|
my $msg = "Invalid value $args[0] for $setting";
|
||||||
|
Log 1, $msg;
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsSingleUpdate($hash, $setting, $args[0], 0);
|
||||||
|
|
||||||
|
my $boostDuration = MAX_ReadingsVal($hash,"boostDuration");
|
||||||
|
my $boostValveposition = MAX_ReadingsVal($hash,"boostValveposition");
|
||||||
|
my $decalcification = MAX_ReadingsVal($hash,"decalcification");
|
||||||
|
my $maxValveSetting = MAX_ReadingsVal($hash,"maxValveSetting");
|
||||||
|
my $valveOffset = MAX_ReadingsVal($hash,"valveOffset");
|
||||||
|
|
||||||
|
my ($decalcDay, $decalcHour) = ($decalcification =~ /^(..), (\d{1,2}):00$/);
|
||||||
|
my $decalc = ($decalcDaysInv{$decalcDay} << 5) | $decalcHour;
|
||||||
|
my $boost = ($boost_durationsInv{$boostDuration} << 5) | int($boostValveposition/5);
|
||||||
|
|
||||||
|
my $payload = sprintf("%02x%02x%02x%02x", $boost, $decalc, int($maxValveSetting*255/100), int($valveOffset*255/100));
|
||||||
|
return ($hash->{IODev}{Send})->($hash->{IODev},"ConfigValve",$hash->{addr},$payload);
|
||||||
|
|
||||||
}elsif($setting eq "groupid"){
|
}elsif($setting eq "groupid"){
|
||||||
return "argument needed" if(@args == 0);
|
return "argument needed" if(@args == 0);
|
||||||
|
|
||||||
@ -227,6 +278,14 @@ MAX_Set($@)
|
|||||||
}elsif( $setting ~~ ["ecoTemperature", "comfortTemperature", "measurementOffset", "maximumTemperature", "minimumTemperature", "windowOpenTemperature", "windowOpenDuration" ] and ($hash->{type} eq "HeatingThermostat" or $hash->{type} eq "WallMountedThermostat")) {
|
}elsif( $setting ~~ ["ecoTemperature", "comfortTemperature", "measurementOffset", "maximumTemperature", "minimumTemperature", "windowOpenTemperature", "windowOpenDuration" ] and ($hash->{type} eq "HeatingThermostat" or $hash->{type} eq "WallMountedThermostat")) {
|
||||||
return "Cannot set without IODev" if(!exists($hash->{IODev}));
|
return "Cannot set without IODev" if(!exists($hash->{IODev}));
|
||||||
|
|
||||||
|
if(!MAX_Validate($setting, $args[0])) {
|
||||||
|
my $msg = "Invalid value $args[0] for $setting";
|
||||||
|
Log 1, $msg;
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsSingleUpdate($hash, $setting, $args[0], 0);
|
||||||
|
|
||||||
my $comfortTemperature = MAX_ReadingsVal($hash,"comfortTemperature");
|
my $comfortTemperature = MAX_ReadingsVal($hash,"comfortTemperature");
|
||||||
my $ecoTemperature = MAX_ReadingsVal($hash,"ecoTemperature");
|
my $ecoTemperature = MAX_ReadingsVal($hash,"ecoTemperature");
|
||||||
my $maximumTemperature = MAX_ReadingsVal($hash,"maximumTemperature");
|
my $maximumTemperature = MAX_ReadingsVal($hash,"maximumTemperature");
|
||||||
@ -483,7 +542,7 @@ MAX_Parse($$)
|
|||||||
readingsBulkUpdate($shash, "windowOpenDuration", $args[8]);
|
readingsBulkUpdate($shash, "windowOpenDuration", $args[8]);
|
||||||
readingsBulkUpdate($shash, "maxValveSetting", $args[9]);
|
readingsBulkUpdate($shash, "maxValveSetting", $args[9]);
|
||||||
readingsBulkUpdate($shash, "valveOffset", $args[10]);
|
readingsBulkUpdate($shash, "valveOffset", $args[10]);
|
||||||
readingsBulkUpdate($shash, "decalcification", "$decalcDays[$args[11]], $args[12]:00");
|
readingsBulkUpdate($shash, "decalcification", "$decalcDays{$args[11]}, $args[12]:00");
|
||||||
$shash->{internal}{weekProfile} = $args[13];
|
$shash->{internal}{weekProfile} = $args[13];
|
||||||
} else {
|
} else {
|
||||||
$shash->{internal}{weekProfile} = $args[4];
|
$shash->{internal}{weekProfile} = $args[4];
|
||||||
@ -518,8 +577,8 @@ MAX_Parse($$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readingsBulkUpdate($shash, "weekprofile-$i-$decalcDays[$i]-time", $time_prof_str );
|
readingsBulkUpdate($shash, "weekprofile-$i-$decalcDays{$i}-time", $time_prof_str );
|
||||||
readingsBulkUpdate($shash, "weekprofile-$i-$decalcDays[$i]-temp", $temp_prof_str );
|
readingsBulkUpdate($shash, "weekprofile-$i-$decalcDays{$i}-temp", $temp_prof_str );
|
||||||
|
|
||||||
} # Endparse weekprofiles for each day
|
} # Endparse weekprofiles for each day
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user