##############################################
# 98_THRESHOLD by Damian Sordyl
#
# This file is part of fhem.
#
# Fhem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Fhem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see .
#
##############################################################################
package main;
use strict;
use warnings;
sub THRESHOLD_setValue($$);
##########################
sub
THRESHOLD_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "THRESHOLD_Define";
$hash->{SetFn} = "THRESHOLD_Set";
$hash->{NotifyFn} = "THRESHOLD_Notify";
$hash->{AttrList} = "disable:0,1 loglevel:0,1,2,3,4,5,6 state_format state_cmd1_gt state_cmd2_lt";
}
##########################
sub
THRESHOLD_Define($$$)
{
my ($hash, $def) = @_;
my @b =split (/\|/,$def);
my @a = split("[ \t][ \t]*", $b[0]);
my $cmd1_gt="";
my $cmd2_lt="";
my $cmd_default=0;
my $actor;
my $init_desired_value;
my $target_sensor;
my $target_reading;
my $offset=0;
my $pn = $a[0];
if (@b > 6 || @a < 3 || @a > 6) {
my $msg = "wrong syntax: define THRESHOLD " .
":::: AND|OR :: ".
"||||:|state_format";
Log3 $pn,2, $msg;
return $msg;
}
# Sensor
my ($sensor, $reading, $hysteresis,$s4,$s5,$s6) = split(":", $a[2], 6);
if(!$defs{$sensor}) {
my $msg = "$pn: Unknown sensor device $sensor specified";
Log3 $pn,2, $msg;
return $msg;
}
$reading = "temperature" if (!defined($reading));
if (!defined($hysteresis) or ($hysteresis eq "")) {
if ($reading eq "temperature" or $reading eq "temp") {
$hysteresis=1;
} elsif ($reading eq "humidity") {
$hysteresis=10;
} else {
$hysteresis=0;
}
} elsif ($hysteresis !~ m/^[\d\.]*$/ ) {
my $msg = "$pn: value:$hysteresis, hysteresis needs a numeric parameter";
Log3 $pn,2, $msg;
return $msg;
}
if (defined($s6)) { # target_sensor:target_reading:offset
$target_sensor=$s4;
$target_reading=$s5;
$offset=$s6;
} elsif (defined($s5)) { # init_desired_value:offset or target_sensor:offset or target_sensor:target_reading
if ($s5 =~ m/^[-\d\.]*$/) { # offset
$offset=$s5;
} else { # target_reading
$target_reading=$s5;
}
if ($s4 =~ m/^[-\d\.]*$/) { # init_desired_value
$init_desired_value=$s4;
} else { # target_sensor
$target_sensor=$s4;
}
} elsif (defined($s4)) { # target_sensor or init_desired_value
if ($s4 =~ m/^[-\d\.]*$/) { # init_desired_value
$init_desired_value=$s4;
} else { # target_sensor
$target_sensor=$s4;
$target_reading="temperature";
}
}
if (defined($target_sensor)) {
if (!$defs{$target_sensor}) {
my $msg = "$pn: Unknown sensor device $target_sensor specified";
Log3 $pn,2, $msg;
return $msg;
}
}
# Modify DEF
if ($hash->{sensor})
{
delete $hash->{sensor};
delete $hash->{sensor_reading};
delete $hash->{hysteresis};
delete $hash->{target_sensor};
delete $hash->{target_reading};
delete $hash->{init_desired_value};
delete $hash->{offset};
delete $hash->{cmd1_gt};
delete $hash->{cmd2_lt};
delete $hash->{cmd_default};
delete $hash->{STATE};
delete $hash->{operator};
delete $hash->{sensor2};
delete $hash->{sensor2_reading};
delete $hash->{sensor2_state};
}
# Sensor2
if (defined($a[3])) {
my $operator=$a[3];
if (($operator eq "AND") or ($operator eq "OR")) {
my ($sensor2, $sensor2_reading, $state) = split(":", $a[4], 3);
if (defined ($sensor2)) {
if(!$defs{$sensor2}) {
my $msg = "$pn: Unknown sensor2 device $sensor2 specified";
Log3 $pn,2, $msg;
return $msg;
}
}
$sensor2_reading = "state" if (!defined ($sensor2_reading));
$state = "open" if (!defined ($state));
$hash->{operator} = $operator;
$hash->{sensor2} = $sensor2;
$hash->{sensor2_reading} = $sensor2_reading;
$hash->{sensor2_state} = $state;
$actor = $a[5];
} else {
$actor = $a[3];
}
}
if (defined ($actor)) {
if (!$defs{$actor}) {
my $msg = "$pn: Unknown actor device $actor specified";
Log3 $pn,2, $msg;
return $msg;
}
}
if (@b == 1) { # no actor parameters
if (!defined($actor)) {
$attr{$pn}{state_cmd1_gt}="off";
$attr{$pn}{state_cmd2_lt}="on";
$attr{$pn}{state_format} = "_sc";
$hysteresis = 0;
$cmd_default = 0;
} else {
$cmd1_gt = "set $actor off";
$cmd2_lt = "set $actor on";
$attr{$pn}{state_cmd1_gt}="off";
$attr{$pn}{state_cmd2_lt} = "on";
$cmd_default = 2;
$attr{$pn}{state_format} = "_m _dv _sc";
}
} else { # actor parameters
$cmd1_gt = $b[1] if (defined($b[1]));
$cmd2_lt = $b[2] if (defined($b[2]));
$cmd_default = (!($b[3])) ? 0 : $b[3];
if ($cmd_default !~ m/^[0-2]$/ ) {
my $msg = "$pn: value:$cmd_default, cmd_default_index needs 0,1,2";
Log3 $pn,2, $msg;
return $msg;
}
if (defined($b[4])) {
my ($st_cmd1_gt, $st_cmd2_lt) = split(":", $b[4], 2);
$attr{$pn}{state_cmd1_gt} = $st_cmd1_gt if (defined($st_cmd1_gt));
$attr{$pn}{state_cmd2_lt} = $st_cmd2_lt if (defined($st_cmd2_lt));
$attr{$pn}{state_format} = "_sc";
}
if (defined($b[5])) {
$attr{$pn}{state_format} = $b[5];
} elsif (defined($b[4])){
$attr{$pn}{state_format} = "_sc";
} else {
$attr{$pn}{state_format} = "_m _dv";
}
}
if (defined($actor)) {
$cmd1_gt =~ s/@/$actor/g;
$cmd2_lt =~ s/@/$actor/g;
}
$hash->{sensor} = $sensor;
$hash->{sensor_reading} = $reading;
$hash->{hysteresis} = $hysteresis;
$hash->{target_sensor} = $target_sensor if (defined ($target_sensor));
$hash->{target_reading} = $target_reading if (defined ($target_reading));
$hash->{init_desired_value} = $init_desired_value if (defined ($init_desired_value));
$hash->{offset} = $offset;
$hash->{cmd1_gt} = SemicolonEscape($cmd1_gt);
$hash->{cmd2_lt} = SemicolonEscape($cmd2_lt);
$hash->{cmd_default} = $cmd_default;
$hash->{STATE} = 'initialized';
readingsBeginUpdate ($hash);
if (defined ($init_desired_value))
{
my $mode="active";
readingsBulkUpdate ($hash, "threshold_min", $init_desired_value-$hysteresis+$offset);
readingsBulkUpdate ($hash, "threshold_max", $init_desired_value+$offset);
readingsBulkUpdate ($hash, "cmd","wait for next cmd");
readingsBulkUpdate ($hash, "desired_value", $init_desired_value);
readingsBulkUpdate ($hash, "mode", $mode);
}
if (defined ($target_sensor))
{
my $mode="external";
readingsBulkUpdate ($hash, "cmd", "wait for next cmd");
readingsBulkUpdate ($hash, "mode", "external");
}
readingsEndUpdate ($hash, 1);
return undef;
}
##########################
sub
THRESHOLD_Set($@)
{
my ($hash, @a) = @_;
my $pn = $hash->{NAME};
my $ret="";
return "$pn, need a parameter for set" if(@a < 2);
my $arg = $a[1];
my $value = (defined $a[2]) ? $a[2] : "";
my $desired_value = ReadingsVal($pn,"desired_value","");
my $target_sensor =
my $offset = $hash->{offset};
my $mode;
my $state_format = AttrVal($pn, "state_format", "_m _dv");
if ($arg eq "desired" ) {
return "$pn: set desired value:$value, desired value needs a numeric parameter" if(@a != 3 || $value !~ m/^[-\d\.]*$/);
if ($desired_value ne "") {
return $ret if ($desired_value == $value);
}
Log3 $pn,2, "set $pn $arg $value";
$mode = "active";
$state_format =~ s/\_m/$mode/g;
$state_format =~ s/\_dv/$value/g;
$state_format =~ s/\_s1v//g;
$state_format =~ s/\_s2s//g;
$state_format =~ s/\_sc//g;
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "mode", $mode);
readingsBulkUpdate ($hash, "state", $state_format) if ($state_format);
readingsBulkUpdate ($hash, "threshold_min",$value-$hash->{hysteresis}+$offset);
readingsBulkUpdate ($hash, "threshold_max", $value+$offset);
readingsBulkUpdate ($hash, "cmd","wait for next cmd");
readingsBulkUpdate ($hash, "desired_value", $value);
readingsEndUpdate ($hash, 1);
} elsif ($arg eq "deactivated" ) {
return "$pn: set deactivated, set desired value first" if ($desired_value eq "");
$ret=CommandAttr(undef, "$pn disable 1");
if (!$ret) {
readingsBeginUpdate ($hash);
$mode = "deactivated";
$state_format =~ s/\_m/$mode/g;
$state_format =~ s/\_dv//g;
$state_format =~ s/\_s1v//g;
$state_format =~ s/\_s2s//g;
$state_format =~ s/\_sc//g;
readingsBulkUpdate ($hash, "state", $state_format) if ($state_format);
readingsBulkUpdate ($hash, "mode", "deactivated");
readingsEndUpdate ($hash, 1);
}
} elsif ($arg eq "active" ) {
return "$pn: set active, set desired value first" if ($desired_value eq "");
$ret=CommandDeleteAttr(undef, "$pn disable");
if (!$ret) {
$mode="active";
readingsBeginUpdate ($hash);
$state_format =~ s/\_m/$mode/g;
$state_format =~ s/\_dv//g;
$state_format =~ s/\_s1v//g;
$state_format =~ s/\_s2s//g;
$state_format =~ s/\_sc//g;
readingsBulkUpdate ($hash, "mode", $mode);
readingsBulkUpdate ($hash, "state", $state_format) if ($state_format);
readingsBulkUpdate ($hash, "cmd","wait for next cmd");
readingsEndUpdate ($hash, 1);
}
} elsif ($arg eq "external" ) {
$ret=CommandDeleteAttr(undef, "$pn disable");
if (!$ret) {
return "$pn: no target_sensor defined" if (!$hash->{target_sensor});
$mode="external";
readingsBeginUpdate ($hash);
$state_format =~ s/\_m/$mode/g;
$state_format =~ s/\_dv//g;
$state_format =~ s/\_s1v//g;
$state_format =~ s/\_s2s//g;
$state_format =~ s/\_sc//g;
readingsBulkUpdate ($hash, "mode", $mode);
readingsBulkUpdate ($hash, "state", $state_format) if ($state_format);
readingsBulkUpdate ($hash, "cmd","wait for next cmd");
readingsEndUpdate ($hash, 1);
}
} elsif ($arg eq "hysteresis" ) {
return "$pn: set hysteresis value:$value, hysteresis needs a numeric parameter" if (@a != 3 || $value !~ m/^[\d\.]*$/ );
$hash->{hysteresis} = $value;
if ($desired_value ne "") {
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "threshold_min",$desired_value-$hash->{hysteresis}+$offset);
readingsBulkUpdate ($hash, "threshold_max", $desired_value+$offset);
readingsBulkUpdate ($hash, "cmd","wait for next cmd");
readingsEndUpdate ($hash, 1);
}
} elsif ($arg eq "offset" ) {
return "$pn: set offset value:$value, offset needs a numeric parameter" if (@a != 3 || $value !~ m/^[-\d\.]*$/ );
$offset = $value;
$hash->{offset} = $offset;
if ($desired_value ne "") {
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "threshold_min",$desired_value-$hash->{hysteresis}+$offset);
readingsBulkUpdate ($hash, "threshold_max", $desired_value+$offset);
readingsBulkUpdate ($hash, "cmd","wait for next cmd");
readingsEndUpdate ($hash, 1);
}
} elsif ($arg eq "cmd1_gt" ) {
readingsBeginUpdate ($hash);
THRESHOLD_setValue ($hash,1);
THRESHOLD_set_state ($hash);
readingsEndUpdate ($hash, 1);
} elsif ($arg eq "cmd2_lt" ) {
readingsBeginUpdate ($hash);
THRESHOLD_setValue ($hash,2);
THRESHOLD_set_state ($hash);
readingsEndUpdate ($hash, 1);
} else {
return "$pn: unknown argument $a[1], choose one of desired active external deactivated hysteresis offset cmd1_gt cmd2_lt"
}
return $ret;
}
##########################
sub
THRESHOLD_Notify($$)
{
my ($hash, $dev) = @_;
my $pn = $hash->{NAME};
return "" if($attr{$pn} && $attr{$pn}{disable});
my $sensor = $hash->{sensor};
my $reading = $hash->{sensor_reading};
my $target_sensor = $hash->{target_sensor};
my $target_reading = $hash->{target_reading};
my $sensor2 = $hash->{sensor2};
my $reading2 = $hash->{sensor2_reading};
my $s_value;
my $t_value;
my $sensor_max;
my $sensor_min;
my $name = $dev->{NAME};
SELECT:{
if (($name eq $sensor) and (ReadingsVal($pn,"desired_value","") ne "")) {last SELECT;}
if ($sensor2) {
if (($name eq $sensor2) and (ReadingsVal($pn,"desired_value","") ne "")) {last SELECT;}
}
if ($target_sensor) {
if (ReadingsVal($pn,"mode","") eq "external") {
if ($name eq $target_sensor) {last SELECT;}
}
}
return "";
}
if (!($defs{$sensor}{READINGS}{$reading})) {
my $msg = "$pn: no reading yet for $sensor $reading";
Log3 $pn,2, $msg;
return"";
} else {
my $instr = $defs{$sensor}{READINGS}{$reading}{VAL};
$instr =~ /[^\d^\-^.]*([-\d.]*)/;
$s_value = $1;
}
if ($sensor2) {
if (!($defs{$sensor2}{READINGS}{$reading2})) {
my $msg = "$pn: no reading yet for $sensor2 $reading2";
Log3 $pn,2, $msg;
return"";
}
}
my $mode = ReadingsVal($pn,"mode","");
#compatibility hack
if (!$mode) {
my $desired_value = ReadingsVal($pn,"desired_value","");
$mode="active";
my $state_format = AttrVal($pn, "state_format", "_m _dv");
$state_format =~ s/\_m/$mode/g;
$state_format =~ s/\_dv/$desired_value/g;
$state_format =~ s/\_s1v//g;
$state_format =~ s/\_s2s//g;
$state_format =~ s/\_sc//g;
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "state", $state_format) if ($state_format);
readingsBulkUpdate ($hash, "threshold_min", $desired_value-$hash->{hysteresis}+$hash->{offset});
readingsBulkUpdate ($hash, "threshold_max", $desired_value+$hash->{offset});
readingsBulkUpdate ($hash, "mode", $mode);
readingsEndUpdate ($hash, 1);
}
if (($target_reading) && $mode eq "external")
{
if (!($defs{$target_sensor}{READINGS}{$target_reading})) {
my $msg = "$pn: no reading yet for $target_sensor $target_reading";
Log3 $pn,2, $msg;
return"";
} else {
my $instr = $defs{$target_sensor}{READINGS}{$target_reading}{VAL};
$instr =~ /[^\d^\-^.]*([-\d.]*)/;
$t_value = $1;
$sensor_max = $t_value+$hash->{offset};
$sensor_min = $t_value-$hash->{hysteresis}+$hash->{offset};
}
}
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "sensor_value",$s_value) if (defined($s_value) and ($s_value ne ReadingsVal($pn,"sensor_value","")));
readingsBulkUpdate ($hash, "desired_value",$t_value) if (defined($t_value) and ($t_value ne ReadingsVal($pn,"desired_value","")));
if (defined ($sensor_max)) {
readingsBulkUpdate ($hash, "threshold_max",$sensor_max) if ($sensor_max ne ReadingsVal($pn,"threshold_max",""));
} else {
$sensor_max = ReadingsVal($pn,"threshold_max","");
}
if (defined ($sensor_min)) {
readingsBulkUpdate ($hash, "threshold_min",$sensor_min) if ($sensor_min ne ReadingsVal($pn,"threshold_min",""));
} else {
$sensor_min = ReadingsVal($pn,"threshold_min","");
}
my $cmd_now="";
if (($sensor_min ne "") and ($sensor_max ne ""))
{
my $cmd_default = $hash->{cmd_default};
if (!$hash->{operator}) {
if ($s_value > $sensor_max) {
THRESHOLD_setValue($hash,1);
} elsif ($s_value < $sensor_min) {
THRESHOLD_setValue($hash,2);
} else {
THRESHOLD_setValue($hash,$cmd_default) if (ReadingsVal($pn,"cmd","") eq "wait for next cmd" && $cmd_default != 0);
}
} else {
my $s2_state = $defs{$sensor2}{READINGS}{$reading2}{VAL};
my $sensor2_state = $hash->{sensor2_state};
readingsBulkUpdate ($hash, "sensor2_state",$s2_state) if ($s2_state ne ReadingsVal($pn,"sensor2_state",""));
if ($hash->{operator} eq "AND") {
if (($s_value > $sensor_max) && ($s2_state eq $sensor2_state)) {
THRESHOLD_setValue($hash,1);
} elsif (($s_value < $sensor_min) || ($s2_state ne $sensor2_state)){
THRESHOLD_setValue($hash,2);
} else {
THRESHOLD_setValue($hash,$cmd_default) if (ReadingsVal($pn,"cmd","") eq "wait for next cmd" && $cmd_default != 0);
}
} elsif ($hash->{operator} eq "OR") {
if (($s_value > $sensor_max) || ($s2_state eq $sensor2_state)) {
THRESHOLD_setValue($hash,1);
} elsif (($s_value < $sensor_min) && ($s2_state ne $sensor2_state)){
THRESHOLD_setValue($hash,2);
} else {
THRESHOLD_setValue($hash,$cmd_default) if (ReadingsVal($pn,"cmd","") eq "wait for next cmd" && $cmd_default != 0);
}
}
}
}
THRESHOLD_set_state ($hash);
readingsEndUpdate ($hash, 1);
return "";
}
sub
THRESHOLD_set_state($)
{
my ($hash) = @_;
my $pn=$hash->{NAME};
my $state_old = ReadingsVal($pn, "state","");
my $mode = ReadingsVal($pn,"mode","");
my $desired_value = ReadingsVal($pn,"desired_value","");
my $sensor_value = ReadingsVal($pn,"sensor_value","");
my $sensor2_state = ReadingsVal($pn,"sensor2_state","");
my $cmd = ReadingsVal($pn,"cmd","");
# my %h_state_cmd = (cmd1_gt=>state_cmd1_gt, cmd2_lt=>state_cmd2_lt);
my $state_cmd = AttrVal ($pn, "state_".$cmd,"");
my $state_format = AttrVal($pn, "state_format", "_m _dv");
$state_format =~ s/\_m/$mode/g;
$state_format =~ s/\_dv/$desired_value/g;
$state_format =~ s/\_s1v/$sensor_value/g;
$state_format =~ s/\_s2s/$sensor2_state/g;
$state_format =~ s/\_sc/$state_cmd/g;
if (($state_format) and ($state_old ne $state_format)) {
readingsBulkUpdate ($hash, "state", $state_format);
}
}
sub
THRESHOLD_setValue($$)
{
my ($hash, $cmd_nr) = @_;
my $pn = $hash->{NAME};
my @cmd_sym = ("cmd1_gt","cmd2_lt");
my $cmd_sym_now = $cmd_sym[$cmd_nr-1];
if (ReadingsVal($pn,"cmd","") ne $cmd_sym_now) {
my $ret=0;
my @cmd =($hash->{cmd1_gt},$hash->{cmd2_lt});
my @state_cmd = (AttrVal($pn,"state_cmd1_gt",""),AttrVal($pn,"state_cmd2_lt",""));
my $cmd_now = $cmd[$cmd_nr-1];
my $state_cmd_now = $state_cmd[$cmd_nr-1];
if ($cmd_now ne "") {
if ($ret = AnalyzeCommandChain(undef, $cmd_now)) {
Log3 $pn,2 , "output of $pn $cmd_now: $ret";
}
}
readingsBulkUpdate ($hash, "cmd",$cmd_sym_now);
}
}
1;
=pod
=begin html
THRESHOLD
Diverse controls can be realized by means of the module by evaluation of sensor data.
In the simplest case, this module reads any sensor that provides values in decimal and execute FHEM/Perl commands, if the value of the sensor is higher or lower than the threshold value.
A typical application is the simulation of a thermostat or humidistat.
With one or more such modules, complex systems can be implemented for heating, cooling, ventilation, dehumidification or shading.
But even simple notification when crossing or falling below a specific value can be easily realized. It no if-statements in Perl or notify definitions need to be made.
This leads to quickly create and clear controls, without having to necessarily go into the Perl matter.
Some application examples are at the end of the module description.
According to the definition of a module type THRESHOLD eg:
define <name> THRESHOLD <sensor> <actor>
It is controlled by setting a desired value with:
set <name> desired <value>
The module begins with the control system only when a desired value is set!
The specification of the desired value may also come from another sensor. This control may take place by the comparison of two sensors.
Likewise, any wall thermostats can be used (eg, HM, MAX, FHT) for the definition of the reference temperature.
The switching behavior can also be influenced by another sensor or sensor group.
The combination of multiple THRESHOLD modules together is possible, see examples below.
Define
define <name> THRESHOLD <sensor>:<reading>:<hysteresis>:<target_value>:<offset> AND|OR <sensor2>:<reading2>:<state> <actor>|<cmd1_gt>|<cmd2_lt>|<cmd_default_index>|<state_cmd1_gt>:<state_cmd2_lt>|<state_format>
- sensor
a defined sensor in FHEM
- reading (optional)
reading of the sensor, which includes a value in decimal
default value: temperature
- hysteresis (optional)
Hysteresis, this provides the threshold_min = desired_value - hysteresis
default value: 1 at temperature, 10 at huminity
- target_value (optional)
number: Initial value, if no value is specified, it must be set with "set desired value".
else:<sensorname>:<reading>, an additional sensor can be specified, which sets the target value dynamically.
default value: no value
- offset (optional)
Offset to desired value
This results:
threshold_max = desired_value + offset and threshold_min = desired_value - hysteresis + offset
Defaultwert: 0
- AND|OR (optional)
logical operator with an optional second sensor
- sensor2 (optional, nur in Verbindung mit AND oder OR)
the second sensor
- reading2 (optional)
reading of the second sensor
default value: state
- state (optional)
state of the second sensor
default value: open
- actor (optional)
actor device defined in FHEM
- cmd1_gt (optional)
FHEM/Perl command that is executed, if the value of the sensor is higher than desired value and/or the value of sensor 2 is matchted. @ is a placeholder for the specified actor.
default value: set actor off, if actor defined
- cmd2_lt (optional)
FHEM/Perl command that is executed, if the value of the sensor is lower than threshold_min or the value of sensor 2 is not matchted. @ is a placeholder for the specified actor.
default value: set actor on, if actor defined
- cmd_default_index (optional)
Index of command that is executed after setting the desired value until the desired value or threshold_min value is reached.
0 - no command
1 - cmd1_gt
2 - cmd2_lt
default value: 2, if actor defined, else 0
- state_cmd1_gt (optional, is defined as an attribute at the same time and can be changed there)
state, which is displayed, if FHEM/Perl-command cmd1_gt was executed. If state_cmd1_gt state ist set, other states, such as active or deactivated are suppressed.
default value: none
- state_cmd2_lt (optional, is defined as an attribute at the same time and can be changed there)
state, which is displayed, if FHEM/Perl-command cmd1_gt was executed. If state_cmd1_gt state ist set, other states, such as active or deactivated are suppressed.
default value: none
- state_format (optional, is defined as an attribute at the same time and can be changed there)
Format of the state output: arbitrary text with placeholders.
Possible placeholders:
_m: mode
_dv: desired_value
_s1v: sensor_value
_s2s: sensor2_state
_sc: state_cmd
Default value: _m _dv _sc, _sc when state_cmd1_gt and state_cmd2_lt set without actor.
Examples:
Example for heating:
It is heated up to the desired value of 20. If the value below the threshold_min value of 19 (20-1)
the heating is switched on again.
define thermostat THRESHOLD temp_sens heating
set thermostat desired 20
Example for heating with window contact:
define thermostat THRESHOLD temp_sens OR win_sens heating
Example for heating with multiple window contacts:
define W_ALL structure W1 W2 W3 ...
attr W_ALL clientstate_behavior relative
attr W_ALL clientstate_priority closed open
then:
define thermostat THRESHOLD S1 OR W_ALL heating
More examples for dehumidification, air conditioning, watering:
define hygrostat THRESHOLD hym_sens:humidity dehydrator|set @ on|set @ off|1
define hygrostat THRESHOLD hym_sens:humidity AND Sensor2:state:close dehydrator|set @ on|set @ off|1
define thermostat THRESHOLD temp_sens:temperature:1 aircon|set @ on|set @ off|1
define thermostat THRESHOLD temp_sens AND Sensor2:state:close aircon|set @ on|set @ off|1
define hygrostat THRESHOLD hym_sens:humidity:20 watering|set @ off|set @ on|2
It can also FHEM/perl command chains are specified:
Examples:
define thermostat THRESHOLD sensor |set Switch1 on;;set Switch2 on|set Switch1 off;;set Switch2 off|1
define thermostat THRESHOLD sensor alarm|{Log 2,"value is exceeded"}|set @ on;;set Switch2 on
define thermostat THRESHOLD sensor ||{Log 2,"value is reached"}|
Examples of the reference input by another sensor:
Hot water circulation: The return temperature is 5 degrees (offset) below the hot water tank temperature and can vary by up to 4 degrees (hysteresis).
define TH_water_circulation THRESHOLD return_w:temperature:4:water_storage:temperature:-5 circualtion_pump
Control of heating by a wall thermostat with acquisition the desired and actual temperature from the wall thermostat:
define TH_heating THRESHOLD WT:measured-temp:1:WT:desired-temp heating
set TH_heating desired 17
overrides the desired-values from the wall thermostat until called set TH_heating external
Examples of customized state output:
define thermostat THRESHOLD sensor aircon|set @ on|set @ off|2|on:off
Example of state output (eg for state evaluation in other modules) without executing code:
define thermostat THRESHOLD sensor:temperature:0:30
by reason of default values:
define thermostat THRESHOLD sensor:temperature:0:30||||off:on|_sc
Example of combining several THRESHOLD modules together:
It should be heated when the room temperature drops below 21 degrees and the outside temperature is below 15 degrees:
define TH_outdoor THRESHOLD outdoor:temperature:0:15
define TH_room THRESHOLD indoor OR TH_outdoor:state:off heating
set TH_room desired 21
An example of time-dependent heating in combination with Heating_Control module:
define TH_living_room THRESHOLD T_living_room heating
define HC_living_room Heating_Control TH_living_room 06:00|22 22:00|18 set @ desired %
Examples of customized state output:
State output: <mode> <state_cmd> <desired_value> <sensor_value>
define TH_living_room THRESHOLD T_living_room heating|set @ off|set @ on|2|off:on|_m _sc _dv _s1v
or
define TH_living_room THRESHOLD T_living_room heating
attr TH_living_room state_cmd1_gt off
attr TH_living_room state_cmd2_lt on
attr TH_living_room state_format _m _sc _dv _s1v
Set
-
set <name> desired <value>
Set the desired value. If no desired value is set, the module is not active.
-
set <name> deactivated <value>
Module is disabled.
-
set <name> active <value>
Module is activated. If under target_value a sensor for reference input has been defined, the current setpoint will be inhibited until set "set external".
set <name> externel
Module is activated, reference input comes from the target sensor, if a sensor has been defined under target_value.
-
set <name> hysteresis <value>
Set hysteresis value.
set <name> offset <value>
Set offset value.
Defaultwert: 0
set <name> cmd1_gt
Executes the command defined in cmd1_gt.
set <name> cmd2_lt
Executes the command defined in cmd2_lt.
Get
Attributes
=end html
=begin html_DE
THRESHOLD
Vielfältige Steuerungen, bei denen durch die Auswertung von Sensordaten eine Steuerung erfolgen soll, können mit Hilfe dieses Moduls realisiert werden.
Nach der Definition eines THRESHOLD-Moduls und der Vorgabe eines Sollwertes beginnt bereits das definierte Modul mit der Steuerung. Im einfachsten Fall liest das Modul einen Sensor aus, der Werte als Dezimalzahlen liefert
und schaltet beim Überschreiten einer definierten Schwellen-Obergrenze (Sollwert)
bzw. beim Unterschreiten einer Schwellen-Untergrenze einen Aktor oder führt beliebige FHEM/Perl-Befehle aus.
Typisches Anwendungsgebiet ist z. B. die Nachbildung eines Thermostats oder Hygrostats.
Mit Hilfe des Moduls, bzw. vieler solcher Module, lassen sich einfache oder auch komplexe Steuerungen für Heizung, Kühlung, Lüftung, Entfeuchtung, Beschattung oder z. B. einfache Benachrichtung
beim Über- oder Unterschreiten eines bestimmten Wertes realisieren. Dabei müssen keine If-Abfragen in Perl oder Notify-Definitionen vorgenommen werden.
Das führt, nicht nur bei FHEM-Anfängern, zu schnell erstellten und übersichtlichen Steuerungen, ohne zwingend in die Perl-Materie einsteigen zu müssen.
Am Ende der Beschreibung befinden sich einige Anwendungsbeipiele des Moduls.
Nach der Definition eines Moduls vom Typ THRESHOLD z. B. mit:
define <name> THRESHOLD <sensor> <actor>
erfolgt die eigentliche Steuerung über die Vorgabe eines Sollwertes. Das geschieht über:
set <name> desired <value>
Das Modul beginnt mit der Steuerung erst dann, wenn ein Sollwert gesetzt wird!
Alternativ kann die Vorgabe des Sollwertes von einem weiteren Sensor kommen. Damit kann eine Steuerung durch den Vergleich zweier Sensoren stattfinden.
Typisches Anwendungsbeispiel ist z. B. die Steuerung von Umwälz- oder Zirkulationspumpen.
Ebenso können beliebige Wandthermostate (z. B. HM, MAX, FHT) für die Vorgabe der Solltemperatur genutzt werden.
Optional kann das Schaltverhalten zusätzlich durch einen weiteren Sensor oder eine Sensorgruppe,
definiert über structure (z. B. Fensterkontakte), über eine AND- bzw. OR-Verknüpfung beeinflusst werden.
Auch die Kombination mehrerer THRESHOLD-Module miteinander ist möglich, siehe Beispiele unten.
Define
define <name> THRESHOLD <sensor>:<reading>:<hysteresis>:<target_value>:<offset> AND|OR <sensor2>:<reading2>:<state> <actor>|<cmd1_gt>|<cmd2_lt>|<cmd_default_index>|<state_cmd1_gt>:<state_cmd2_lt>|<state_format>
- sensor
ein in FHEM definierter Sensor
- reading (optional)
Reading des Sensors, der einen Wert als Dezimalzahl beinhaltet
Defaultwert: temperature
- hysteresis (optional)
Hysterese, daraus errechnet sich die Untergrenze = Sollwert - hysteresis
Defaultwert: 1 bei Temperaturen, 10 bei Feuchtigkeit
- target_value (optional)
bei Zahl: Initial-Sollwert, wenn kein Wert vorgegeben wird, muss er mit "set desired value" gesetzt werden.
sonst: <sensorname>:<reading>, hier kann ein weiterer Sensor angegeben werden, der den Sollwert dynamisch vorgibt.
Defaultwert: kein
- offset (optional)
Offset zum Sollwert
Damit errechnet sich: die Sollwertobergrenze = Sollwert + offset und die Sollwertuntergrenze = Sollwert - Hysterese + offset
Defaultwert: 0
- AND|OR (optional)
Verknüpfung mit einem optionalen zweiten Sensor
- sensor2 (optional, nur in Verbindung mit AND oder OR)
ein definierter Sensor, dessen Status abgefragt wird
- reading2 (optional)
Reading, der den Status des Sensors beinhaltet
Defaultwert: state
- state (optional)
Status des Sensors, der zu einer Aktion führt
Defaultwert: open
- actor (optional)
ein in FHEM definierter Aktor
- cmd1_gt (optional)
FHEM/Perl Befehl, der beim Überschreiten des Sollwertes ausgeführt wird bzw.
wenn status des sensor2 übereinstimmt. @ ist ein Platzhalter für den angegebenen Aktor.
Defaultwert: set actor off, wenn Aktor angegeben ist
- cmd2_lt (optional)
FHEM/Perl Befehl, der beim Unterschreiten der Untergrenze (Sollwert-Hysterese) ausgeführt wird bzw.
wenn status des sensor2 nicht übereinstimmt. @ ist ein Platzhalter für den angegebenen Aktor.
Defaultwert: set actor on, wenn Aktor angegeben ist
- cmd_default_index (optional)
FHEM/Perl Befehl, der nach dem Setzen des Sollwertes ausgeführt wird, bis Sollwert oder die Untergrenze erreicht wird.
0 - kein Befehl
1 - cmd1_gt
2 - cmd2_lt
Defaultwert: 2, wenn Aktor angegeben ist, sonst 0
- state_cmd1_gt (optional, wird gleichzeitig als Attribut definiert)
Status, der angezeigt wird, wenn FHEM/Perl-Befehl cmd1_gt ausgeführt wurde.
Defaultwert: kein
- state_cmd2_lt (optional, wird gleichzeitig als Attribut definiert)
Status, der angezeigt wird, wenn FHEM/Perl-Befehl cmd2_lt ausgeführt wurde.
Defaultwert: kein
- state_format (optional, wird gleichzeitig als Attribut definiert und kann dort verändert werden)
Format der Statusanzeige: beliebiger Text mit Platzhaltern
Mögliche Platzhalter:
_m: mode
_dv: desired_value
_s1v: sensor_value
_s2s: sensor2_state
_sc: state_cmd
Defaultwert: _m _dv _sc, _sc, wenn state_cmd1_gt und state_cmd2_lt ohne Aktor gesetzt wird.
Beispiele:
Beispiel für ein einfaches Heizungsthermostat:
Es soll bis 20 Grad geheizt werden. Beim Unterschreiten der Untergrenze von 19 Grad (Sollwert-Hysterese) wird die Heizung wieder eingeschaltet.
define TH_room THRESHOLD temp_room heating
set TH_room desired 20
Beispiel für Heizung mit Fensterkontakt:
define TH_room THRESHOLD temp_room OR win_sens heating
Beispiel für Heizung mit mehreren Fensterkontakten:
define W_ALL structure W1 W2 W3 ....
attr W_ALL clientstate_behavior relative
attr W_ALL clientstate_priority closed open
define thermostat THRESHOLD S1 OR W_ALL heating
Einige weitere Bespiele für Entfeuchtung, Klimatisierung, Bewässerung:
define hygrostat THRESHOLD hym_sens:humidity dehydrator|set @ on|set @ off|1
define hygrostat THRESHOLD hym_sens:humidity AND Sensor2:state:close dehydrator|set @ on|set @ off|1
define thermostat THRESHOLD temp_sens:temperature:1 aircon|set @ on|set @ off|1
define thermostat THRESHOLD temp_sens AND Sensor2:state:close aircon|set @ on|set @ off|1
define hygrostat THRESHOLD hym_sens:humidity:20 watering|set @ off|set @ on|2
Beispiele für die Ausführung beliebiger FHEM/Perl-Befehlsketten:
define thermostat THRESHOLD sensor |set Switch1 on;;set Switch2 on|set Switch1 off;;set Switch2 off|1
define thermostat THRESHOLD sensor alarm|{Log 2,"Wert überschritten"}|set @ on;;set Switch2 on
define thermostat THRESHOLD sensor ||{Log 2,"Wert unterschritten"}|
Beispiele für die Sollwert-Vorgabe durch einen weiteren Sensor:
Warmwasserzirkulation: Die Rücklauftemperatur soll 5 Grad (offset) unter der Warmwasserspeichertemperatur liegen und bis zu 4 Grad (Hysterese) schwanken können.
define TH_water_circulation THRESHOLD return_w:temperature:4:water_storage:temperature:-5 circualtion_pump
Steuerung einer Heizung durch ein Wandthermostat mit Übernahme der Soll- und Ist-Temperatur vom Wandthermostat:
define TH_Heizung THRESHOLD WT:measured-temp:1:WT:desired-temp Heizung
Mit set TH_Heizung desired 17
wird die Vorgabe vom Wandthermostat übersteuert bis set TH_Heizung external
aufgerufen wird.
Beispiele mit angepasster Statusanzeige:
define thermostat THRESHOLD sensor aircon|set @ on|set @ off|2|on:off
Beispiel für reine Zustandanzeige (z. B. für Zustandsauswertung in anderen Modulen) ohne Ausführung von Code:
define thermostat THRESHOLD sensor:temperature:0:30
entspricht wegen Defaultwerte:
define thermostat THRESHOLD sensor:temperature:0:30||||off:on|_sc
Beispiel für Kombination mehrerer THRESHOLD-Module miteinander:
Es soll geheizt werden, wenn die Zimmertemperatur unter 21 Grad fällt und die Außentemperatur unter 15 Grad ist:
define TH_outdoor THRESHOLD outdoor:temperature:0:15
define TH_room THRESHOLD indoor OR TH_outdoor:state:off heating
set TH_room desired 21
Beispiel für zeitabhängiges Heizen in Kombination mit Heating_Control-Modul:
define TH_living_room THRESHOLD T_living_room heating
define HC_living_room Heating_Control TH_living_room 06:00|22 22:00|18 set @ desired %
Beispiele für Anpassung der Statusanzeige des Moduls:
Anzeige von <mode> <state_cmd> <desired_value> <sensor_value>
define TH_living_room THRESHOLD T_living_room heating|set @ off|set @ on|2|off:on|_m _sc _dv _s1v
oder
define TH_living_room THRESHOLD T_living_room heating
attr TH_living_room state_cmd1_gt off
attr TH_living_room state_cmd2_lt on
attr TH_living_room state_format _m _sc _dv _s1v
Set
set <name> desired <value>
Setzt den Sollwert. Wenn kein Sollwert gesetzt ist, ist das Modul nicht aktiv.
Sollwert-Vorgabe durch einen Sensor wird hiermit übersteuert, solange bis "set external" gesetzt wird.
set <name> deactivated <value>
Modul wird deaktiviert.
set <name> active
Modul wird aktiviert, falls unter target_value ein Sensor für die Sollwert-Vorgabe definiert wurde, wird der aktuelle Sollwert solange eingefroren bis "set external" gesetzt wird.
set <name> externel
Modul wird aktiviert, Sollwert-Vorgabe kommt vom Sensor, falls ein Sensor unter target_value definierte wurde.
set <name> hysteresis <value>
Setzt Hysterese-Wert.
set <name> offset <value>
Setzt Offset-Wert.
Defaultwert: 0
set <name> cmd1_gt
Führt das unter cmd1_gt definierte Kommando aus.
set <name> cmd2_lt
Führt das unter cmd2_lt definierte Kommando aus.
Get
Attributes
=end html_DE
=cut