fhem-mirror/FHEM/11_FHT.pm
2020-11-18 21:01:30 +00:00

1406 lines
46 KiB
Perl

# $Id$
##############################################################################
#
# 11_FHT.pm
# Copyright by
# e-mail:
#
# 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.
#
# Foobar 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
package main;
use strict;
use warnings;
sub doSoftBuffer($);
sub softBufferTimer($);
sub getFhtMin($);
sub getFhtBuffer($);
my %codes = (
"00" => "actuator",
"01" => "actuator1",
"02" => "actuator2",
"03" => "actuator3",
"04" => "actuator4",
"05" => "actuator5",
"06" => "actuator6",
"07" => "actuator7",
"08" => "actuator8",
"14" => "mon-from1",
"15" => "mon-to1",
"16" => "mon-from2",
"17" => "mon-to2",
"18" => "tue-from1",
"19" => "tue-to1",
"1a" => "tue-from2",
"1b" => "tue-to2",
"1c" => "wed-from1",
"1d" => "wed-to1",
"1e" => "wed-from2",
"1f" => "wed-to2",
"20" => "thu-from1",
"21" => "thu-to1",
"22" => "thu-from2",
"23" => "thu-to2",
"24" => "fri-from1",
"25" => "fri-to1",
"26" => "fri-from2",
"27" => "fri-to2",
"28" => "sat-from1",
"29" => "sat-to1",
"2a" => "sat-from2",
"2b" => "sat-to2",
"2c" => "sun-from1",
"2d" => "sun-to1",
"2e" => "sun-from2",
"2f" => "sun-to2",
"3e" => "mode",
"3f" => "holiday1", # Not verified
"40" => "holiday2", # Not verified
"41" => "desired-temp",
"XX" => "measured-temp", # sum of next. two, never really sent
"42" => "measured-low",
"43" => "measured-high",
"44" => "warnings",
"45" => "manu-temp", # No clue what it does.
"4b" => "ack",
"53" => "can-xmit",
"54" => "can-rcv",
"60" => "year",
"61" => "month",
"62" => "day",
"63" => "hour",
"64" => "minute",
"65" => "report1",
"66" => "report2",
"69" => "ack2",
"7d" => "start-xmit",
"7e" => "end-xmit",
"82" => "day-temp",
"84" => "night-temp",
"85" => "lowtemp-offset", # Alarm-Temp.-Differenz
"8a" => "windowopen-temp",
);
my %cantset = (
"actuator" => 1,
"actuator1" => 1,
"actuator2" => 1,
"actuator3" => 1,
"actuator4" => 1,
"actuator5" => 1,
"actuator6" => 1,
"actuator7" => 1,
"actuator8" => 1,
"ack" => 1,
"ack2" => 1,
"battery" => 1,
"can-xmit" => 1,
"can-rcv" => 1,
"start-xmit" => 1,
"end-xmit" => 1,
"lowtemp" => 1,
"measured-temp" => 1,
"measured-high" => 1,
"measured-low" => 1,
"warnings" => 1,
"window" => 1,
"windowsensor" => 1,
);
# additional warnings
my %warnings = (
"battery" => 1,
"lowtemp" => 1,
"window" => 1,
"windowsensor" => 1,
);
my %priority = (
"desired-temp"=> 1,
"mode" => 2,
"report1" => 3,
"report2" => 3,
"holiday1" => 4,
"holiday2" => 5,
"day-temp" => 6,
"night-temp" => 7,
);
my %c2m = (0 => "auto", 1 => "manual", 2 => "holiday", 3 => "holiday_short");
my %m2c; # Reverse c2m
my %c2b; # command->button hash (reverse of codes)
my %c2bset; # command->button hash (settable values)
my $defmin = 0; # min fhtbuf free bytes before sending commands
my $retryafter = 240; # in seconds, only when fhtsoftbuffer is active
my $cmdcount = 0;
#####################################
sub
FHT_Initialize($)
{
my ($hash) = @_;
foreach my $k (keys %codes) {
my $v = $codes{$k};
$c2b{$v} = $k;
$c2bset{$v} = $k if(!$cantset{$v});
}
foreach my $k (keys %c2m) {
$m2c{$c2m{$k}} = $k;
}
# { Dispatch($defs{CUL}, "810b04028309830151024130001d", undef) }
# 810c0426 0909a001 1111 1600
# 810c04b3 0909a001 1111 44006900
# 810b0402 83098301 1111 41301d
# 81090421 c409c401 1111 00
# 810c0d20 0909a001 3232 7e006724 (NYI)
$hash->{Match} = "^81..(04|09|0d)..(0909a001|83098301|c409c401)..";
$hash->{SetFn} = "FHT_Set";
$hash->{DefFn} = "FHT_Define";
$hash->{UndefFn} = "FHT_Undef";
$hash->{ParseFn} = "FHT_Parse";
$hash->{StateFn} = "FHT_State";
$hash->{AttrList} = "IODev do_not_notify:1,0 model:fht80b dummy:1,0 " .
"showtime:1,0 retrycount " .
"minfhtbuffer lazy tmpcorr ignore:1,0 ".
$readingFnAttributes;
$hash->{AutoCreate}=
{ "FHT.*" => { GPLOT => "fht:Temp/Act,", FILTER => "%NAME" } };
}
sub
FHT_Set($@)
{
my ($hash, @a) = @_;
my $ret = "";
return "\"set $a[0]\" needs at least two parameters" if(@a < 2);
my $name = shift(@a);
# Replace refreshvalues with report1 and report2, and time with hour/minute
for(my $i = 0; $i < @a; $i++) {
splice(@a,$i,1,("report1","255","report2","255"))
if($a[$i] eq "refreshvalues");
if($a[$i] eq "time") {
my @t = localtime;
splice(@a,$i,1,("hour",$t[2],"minute",$t[1]));
}
if($a[$i] eq "date") {
my @t = localtime;
splice(@a,$i,1,("year",$t[5]-100,"month",$t[4]+1,"day",$t[3]));
}
}
my $ncmd = 0;
my $arg = "020183" . $hash->{CODE};
my ($cmd, $allcmd, $val) = ("", "", "");
my $lazy= defined($attr{$name}) &&
defined($attr{$name}{"lazy"}) &&
($attr{$name}{"lazy"}>0);
my $readings= $hash->{READINGS};
while(@a) {
$cmd = shift(@a);
if(!defined($c2b{$cmd})) {
my $cmdList = join(" ",sort keys %c2bset);
my @list = map { ($_.".0", $_+0.5) } (6..30);
pop @list;
my $tmpList="on,off,".join(",",@list);
$cmdList =~ s/-temp/-temp:$tmpList/g; # FHEMWEB sugar
$cmdList =~ s/(-from.|-to.)/$1:time/g;
$cmdList .= " date:noArg time:noArg";
return "Unknown argument $cmd, choose one of $cmdList";
}
return "Readonly parameter $cmd"
if(defined($cantset{$cmd}));
return "\"set $name $cmd\" needs a parameter"
if(@a < 1);
$val = shift(@a);
$arg .= $c2b{$cmd};
if ($cmd =~ m/-temp/) {
if(!($val eq "on" || $val eq "off" ||
($val =~ m/^\d*\.?\d+$/ && $val >= 5.5 && $val <= 30.5))) {
my @list = map { ($_.".0", $_+0.5) } (6..30);
pop @list;
return "Invalid temperature $val, choose one of on off "
. join(" ",@list);
}
$val = 30.5 if($val eq "on");
$val = 5.5 if($val eq "off");
my $a = int($val*2);
$arg .= sprintf("%02x", $a);
$val = sprintf("%.1f", $a/2);
} elsif($cmd =~ m/-from/ || $cmd =~ m/-to/) {
return "Invalid timeformat, use HH:MM"
if($val !~ m/^([0-2]\d):([0-5]\d)/);
my $a = ($1*6) + ($2/10);
$arg .= sprintf("%02x", $a);
my $nt = sprintf("%02d:%02d", $1, int($2/10)*10);
$ret .= "Rounded $cmd to $nt" if($nt ne $val);
$val = $nt;
} elsif($cmd eq "mode") {
return "Invalid mode, choose one of " . join(" ", sort keys %m2c)
if(!defined($m2c{$val}));
$arg .= sprintf("%02x", $m2c{$val});
} elsif ($cmd eq "lowtemp-offset") {
return "Invalid lowtemperature-offset, must between 1 and 5"
if($val !~ m/^[1-5]$/);
$arg .= sprintf("%02x", $val);
$val = "$val.0";
} else { # Holiday1, Holiday2
return "Invalid argument, must be between 1 and 255"
if($val !~ m/^\d+$/ || $val < 0 || $val > 255);
$arg .= sprintf("%02x", $val) if(defined($val));
}
if($lazy &&
$cmd ne "report1" && $cmd ne "report2" && $cmd ne "refreshvalues" &&
defined($readings->{$cmd}) && $readings->{$cmd}{VAL} eq $val) {
$ret .= "Lazy mode ignores $cmd";
Log3 $name, 2, "Lazy mode ignores $cmd $val";
} else {
$ncmd++;
$allcmd .=" " if($allcmd);
$allcmd .= $cmd;
$allcmd .= " $val" if(defined($val));
}
}
return "Too many commands specified, an FHT only supports up to 8"
if($ncmd > 8);
return $ret if(!$ncmd);
my $ioname = "";
$ioname = $hash->{IODev}->{NAME} if($hash->{IODev});
if($attr{$ioname} && $attr{$ioname}{fhtsoftbuffer}) {
my $io = $hash->{IODev};
my %h = (HASH => $hash, CMD => $allcmd, ARG => $arg);
my $prio = $priority{$cmd};
$prio = "9" if(!$prio);
my $key = $prio . ":" . gettimeofday() . ":" . $cmdcount++;
$io->{SOFTBUFFER}{$key} = \%h;
doSoftBuffer($io);
} else {
IOWrite($hash, "04", $arg);
Log3 $name, 2, "FHT set $name $allcmd";
}
return $ret;
}
#####################################
sub
FHT_Define($$)
{
my ($hash, $def) = @_;
my @a = split(" ", $def);
return "wrong syntax: define <name> FHT CODE" if(int(@a) != 3);
my $id = lc($a[2]);
return "Define $a[0]: wrong CODE format: specify a 4 digit hex value"
if($id !~ m/^[a-f0-9][a-f0-9][a-f0-9][a-f0-9]$/i);
return "FHT id $id is already used by $modules{FHT}{defptr}{$id}{NAME}"
if($modules{FHT}{defptr}{$id});
$modules{FHT}{defptr}{$id} = $hash;
delete($modules{FHT}{defptr}{lc($hash->{OLDDEF})}) # Modify
if($hash->{OLDDEF});
$hash->{CODE} = $id;
AssignIoPort($hash);
# Check if the CULs id collides with our id.
if($hash->{IODev} && $hash->{IODev}{TYPE} eq "CUL") {
$hash->{IODev}{FHTID} =~ m/^(..)(..)$/;
my ($i1, $i2) = (hex($1), hex($2));
$id =~ m/^(..)(..)$/;
my ($l1, $l2) = (hex($1), hex($2));
if($l2 == $i2 && $l1 >= $i1 && $l1 <= $i1+7) {
my $err = "$a[0]: CODE collides with the FHTID of the corresponding CUL";
Log3 $a[0], 1, $err;
return $err;
}
}
$hash->{webCmd} = "desired-temp"; # Hint for FHEMWEB
$modules{FHT}{defptr}{$id} = $hash;
return undef;
}
#####################################
sub
FHT_Undef($$)
{
my ($hash, $name) = @_;
delete($modules{FHT}{defptr}{$hash->{CODE}}) if($hash && $hash->{CODE});
return undef;
}
#####################################
sub
FHT_Parse($$)
{
my ($hash, $msg) = @_;
$msg = lc($msg);
my $dev = substr($msg, 16, 4);
my $cde = substr($msg, 20, 2);
my $val = (length($msg) > 26 ? substr($msg, 26, 2) : undef);
my $confirm = 0;
if(!defined($modules{FHT}{defptr}{$dev})) {
# it might be our own FHT8v, then be silent
foreach my $d (%defs) {
my $dp = $defs{$d};
next if(!$dp->{TYPE} || $dp->{TYPE} ne "FHT8V");
return "" if($dp->{addr} eq $dev);
}
Log3 $hash, 3, "FHT Unknown device $dev, please define it";
return "UNDEFINED FHT_$dev FHT $dev";
}
my $def = $modules{FHT}{defptr}{$dev};
my $name = $def->{NAME};
return "" if(IsIgnored($name));
my $io = $def->{IODev};
# Short message
if(length($msg) < 26) {
Log3 $name, 4, "FHT Short message. Device $name, Message: $msg";
return "";
}
if($io->{TYPE} eq "CUL") {
$confirm = 1;
} elsif(!$val || $cde eq "65" || $cde eq "66") {
# This is a confirmation message. We reformat it so that
# it looks like a real message, and let the rest parse it
Log3 $name, 4, "FHT $name confirmation: $cde";
$val = substr($msg, 22, 2);
$confirm = 1;
}
$val = hex($val);
my $cmd = $codes{$cde};
if(!$cmd) {
Log3 $name, 4, "FHT $name (Unknown: $cde => $val)";
readingsSingleUpdate($def, "unknown_$cde", $val, 1);
return $name;
}
#
# special treatment for measured-temp which is actually sent in two bytes
#
# the measured temperature comes in two bytes: measured-low and measured-high
# measured-temp= (measured-high * 256 + measured-low) / 10.
# measured-low and measured-high will only be stored as internals
if($cmd eq "measured-low") {
$def->{".measuredLow"}= $val;
return "";
} elsif($cmd eq "measured-high") {
$def->{".measuredHigh"}= $val;
if(defined($def->{".measuredLow"})) {
$val = sprintf("%.1f", ($val*256.0 + $def->{".measuredLow"})/10.0+
AttrVal($name, "tmpcorr", 0.0));
$cmd = "measured-temp";
} else {
return "";
}
}
#
# from here readings are effectively updated
#
readingsBeginUpdate($def);
# The first four are confirmation messages, so they must be converted to
# the same format as the input (for the softbuffer)
if($cmd =~ m/-from/ || $cmd =~ m/-to/) {
$val = sprintf("%02d:%02d", $val/6, ($val%6)*10);
} elsif($cmd eq "mode") {
$val = $c2m{$val} if(defined($c2m{$val}));
} elsif($cmd =~ m/.*-temp/ && $cmd ne "measured-temp") {
$val = sprintf("%.1f", $val / 2);
if($cmd eq "desired-temp") {
$val = ($val > 30 ? "on" : ($val < 6 ? "off" : $val));
}
} elsif($cmd eq "lowtemp-offset") {
$val = sprintf("%d.0", $val)
} elsif($cmd =~ m/^actuator/) {
my $sval = lc(substr($msg,24,2));
my $fv = sprintf("%d%%", int(100*$val/255+0.5));
if($sval =~ m/[ab]0/) { $val = $fv; } # sync in the summer
elsif($sval =~ m/.0/) { $val = "syncnow"; }
elsif($sval =~ m/.1/) { $val = "99%" } # FHT set to 30.5, FHT80B=="ON"
elsif($sval =~ m/.2/) { $val = "0%" } # FHT set to 5.5
elsif($sval =~ m/.6/) { $val = "$fv" }
elsif($sval =~ m/.8/) { $val = "offset: " . ($val>128?(128-$val):$val) }
elsif($sval =~ m/[23]a/) { $val = "lime-protection" }
elsif($sval =~ m/[ab]a/) { $val = $fv } # lime protection bug
elsif($sval =~ m/.c/) { $val = sprintf("synctime: %d", int($val/2)-1); }
elsif($sval =~ m/.e/) { $val = "test" }
elsif($sval =~ m/.f/) { $val = "pair" }
else { $val = "unknown_$sval: $fv" }
} elsif($cmd eq "warnings") {
my $nVal;
# initialize values for additional warnings
my $valBattery;
my $valLowTemp;
my $valWindow;
my $valSensor;
my $nBattery;
my $nLowTemp;
my $nWindow;
my $nSensor;
# parse warnings
if($val & 1) {
$nVal = "Battery low";
$nBattery = "low";
}
if($val & 2) {
$nVal .= "; " if($nVal); $nVal .= "Temperature too low";
$nLowTemp = "warn";
}
if($val &32) {
$nVal .= ", " if($nVal); $nVal .= "Window open";
$nWindow = "open";
}
if($val &16) {
$nVal .= ", " if($nVal); $nVal .= "Fault on window sensor";
$nSensor = "fault";
}
# set default values or new values if they were changed
$valBattery = $nBattery? $nBattery : "ok";
$valLowTemp = $nLowTemp? $nLowTemp : "ok";
$valWindow = $nWindow? $nWindow : "closed";
$valSensor = $nSensor? $nSensor : "ok";
$val = $nVal? $nVal : "none";
# set additional warnings and trigger notify
readingsBulkUpdate($def, "battery", $valBattery);
readingsBulkUpdate($def, "batteryState", $valBattery);
Log3 $name, 4, "FHT $name battery: $valBattery";
readingsBulkUpdate($def, "lowtemp", $valLowTemp);
Log3 $name, 4, "FHT $name lowtemp: $valLowTemp";
readingsBulkUpdate($def, "window", $valWindow);
Log3 $name, 4, "FHT $name window: $valWindow";
readingsBulkUpdate($def, "windowsensor", $valSensor);
Log3 $name, 4, "FHT $name windowsensor: $valSensor";
}
$cmd = "FHZ_$cmd" if(substr($msg,24,1) eq "7");
readingsBulkUpdate($def, $cmd, $val);
if($cmd eq "measured-temp") {
readingsBulkUpdate($def, "state", "$val C", 0);
readingsBulkUpdate($def, "temperature", $val); # For dewpoint
}
Log3 $name, 4, "FHT $name $cmd: $val";
#
# now we are done with updating readings
#
readingsEndUpdate($def, 1);
################################
# Softbuffer: delete confirmed commands
if($confirm) {
my $found;
foreach my $key (sort keys %{$io->{SOFTBUFFER}}) {
my $h = $io->{SOFTBUFFER}{$key};
my $hcmd = $h->{CMD};
my $hname = $h->{HASH}->{NAME};
Log3 $name, 4, "FHT softbuffer check: $hname / $hcmd";
if($hname eq $name && $hcmd =~ m/^$cmd $val/) {
$found = $key;
Log3 $name, 4, "FHT softbuffer found";
last;
}
}
delete($io->{SOFTBUFFER}{$found}) if($found);
}
return $name;
}
#####################################
# Check the softwarebuffer and send/resend commands
sub
doSoftBuffer($)
{
my ($io) = @_;
my $now = gettimeofday();
my $count = 0;
my $fhzbuflen = -999;
foreach my $key (keys %{ $io->{SOFTBUFFER} }) {
$count++;
my $h = $io->{SOFTBUFFER}{$key};
my $name = $h->{HASH}->{NAME};
if($h->{NSENT}) {
next if($now-$h->{SENDTIME} < $retryafter);
my $retry = AttrVal($name, "retrycount", 1);
if($h->{NSENT} > $retry) {
Log3 $name, 2, "$name set $h->{CMD}: ".
"no confirmation after $h->{NSENT} tries, giving up";
delete($io->{SOFTBUFFER}{$key});
next;
}
}
# Check if it is still in the CUL buffer.
if($io->{TYPE} eq "CUL") {
my $cul = CallFn($io->{NAME}, "GetFn", $io, (" ", "raw", "T02"));
my $arg = uc($h->{ARG});
$arg =~ s/^020183//;
$arg =~ s/(....)/,$1/g;
$arg =~ s/,(....),/$1:/;
$arg = uc($arg);
if($cul =~ m/$arg/) {
Log3 $name, 3, "fhtsoftbuffer: $name set $h->{CMD} ".
"is still in the culfw buffer, wont send it again";
$h->{SENDTIME} = $now;
$h->{NSENT}++;
next;
}
}
$fhzbuflen = getFhtBuffer($io) if($fhzbuflen == -999);
my $arglen = length($h->{ARG})/2 - 2; # Length in bytes
next if($fhzbuflen < $arglen || $fhzbuflen < getFhtMin($io));
IOWrite($h->{HASH}, "04", $h->{ARG});
Log3 $name, 2, "FHT set $name $h->{CMD}";
$fhzbuflen -= $arglen;
$h->{SENDTIME} = $now;
$h->{NSENT}++;
}
if($count && !$io->{SOFTBUFFERTIMER}) {
$io->{SOFTBUFFERTIMER} = 1;
InternalTimer(gettimeofday()+30, "softBufferTimer", $io, 0);
}
}
#####################################
# Wrapper for the InternalTimer
sub
softBufferTimer($)
{
my ($io) = @_;
delete($io->{SOFTBUFFERTIMER});
doSoftBuffer($io);
}
#####################################
sub
getFhtMin($)
{
my ($io) = @_;
my $ioname = $io->{NAME};
return $attr{$ioname}{minfhtbuffer}
if($attr{$ioname} && $attr{$ioname}{minfhtbuffer});
return $defmin;
}
#####################################
# get the FHZ hardwarebuffer without logentry as decimal value
sub
getFhtBuffer($)
{
my ($io) = @_;
my $count = 0;
return getFhtMin($io) if(IsDummy($io->{NAME}));
for(;;) {
return 0 if(!defined($io->{FD})); # Avoid crash if the CUL/FHZ is absent
my $msg = CallFn($io->{NAME}, "GetFn", $io, (" ", "fhtbuf"));
Log3 $io, 5, "getFhtBuffer: $count $msg";
return hex($1) if($msg && $msg =~ m/=> ([0-9A-F]+)$/i);
return 0 if($count++ >= 5);
}
}
#####################################
# Remap the old FHZ: readingnames to FHZ_
sub
FHT_State($$$$)
{
my ($hash, $tim, $rname, $rval) = @_;
return undef if($rname !~ m/^FHZ:/);
my $newname = $rname;
$newname =~ s/:/_/g;
setReadingsVal($hash, $newname, $rval, $tim);
return "FHT: renamed reading $rname to $newname for $hash->{NAME}";
}
1;
=pod
=item summary devices communicating via the ELV FHT protocol (FHT80b)
=item summary_DE Anbindung von ELV FHT Ger&auml;ten (FHT80b)
=begin html
<a name="FHT"></a>
<h3>FHT</h3>
<ul>
Fhem can receive FHT radio (868.35 MHz) messages either through an <a
href="#FHZ">FHZ</a> or an <a href="#CUL">CUL</a> device, so this must be
defined first.<br><br>
<a name="FHTdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; FHT &lt;fhtaddress&gt;</code>
<br><br>
<code>&lt;fhtaddress&gt;</code> is a four digit hex number,
corresponding to the address of the FHT80b device.
<br>
Examples:
<ul>
<code>define wz FHT 3232</code><br>
</ul>
<br>
See the FHT section in <a href="#set">set</a> for more.
</ul>
<br>
<a name="FHTset"></a>
<b>Set </b>
<ul>
<code>set &lt;name&gt; &lt;valuetype&gt; &lt;value&gt;</code>
<br><br>
where <code>value</code> is one of:<br>
<ul><code>
desired-temp<br>
day-temp night-temp<br>
report1 report2<br>
refreshvalues<br>
mode<br>
holiday1 holiday2 # see mode holiday_short or holiday<br>
manu-temp # No clue what it does.<br>
year month day hour minute<br>
time date<br>
lowtemp-offset # Alarm-Temp.-Differenz<br>
windowopen-temp<br>
mon-from1 mon-to1 mon-from2 mon-to2<br>
tue-from1 tue-to1 tue-from2 tue-to2<br>
wed-from1 wed-to1 wed-from2 wed-to2<br>
thu-from1 thu-to1 thu-from2 thu-to2<br>
fri-from1 fri-to1 fri-from2 fri-to2<br>
sat-from1 sat-to1 sat-from2 sat-to2<br>
sun-from1 sun-to1 sun-from2 sun-to2<br>
</code></ul>
Examples:
<ul>
<code>set wz desired-temp 22.5</code><br>
<code>set fl desired-temp 20.5 day-temp 19.0 night-temp 16.0</code><br>
</ul>
<br>
Notes:
<ul>
<li>Following events are reported (more or less regularly) by each FHT
device: <code>measured-temp actuator actuator1...actuator8
warnings</code><br>
You can use these strings for <a href="#notify">notify</a> or
<a href="#FileLog">FileLog</a> definitions.
<ul>
<li>warnings can contain following strings:
none, Battery low,Temperature too low, Window open,
Fault on window sensor
</li>
<li>actuator (without a suffix) stands for all actuators.</li>
<li>actuator or actuator1..8 can take following values:
<ul>
<li>&lt;value&gt;%<br>
This is the normal case, the actuator is instructed to
open to this value.
</li>
<li>offset &lt;value&gt;%<br>
The actuator is running with this offset.
</li>
<li>lime-protection<br>
The actuator was instructed to execute the lime-protection
procedure.
</li>
<li>synctime<br>
If you select Sond/Sync on the FHT80B, you'll see a count
down.
</li>
<li>test<br>
The actuator was instructed by the FHT80b to emit a beep.
</li>
<li>pair<br>
The the FHT80b sent a "you-belong-to-me" to this actuator.
</li>
</ul></li>
</ul></li>
<br>
<li>The FHT is very economical (or lazy), it accepts one message from the
FHZ1x00 every 115+x seconds, where x depends on the fhtaddress. Don't
be surprised if your command is only accepted 10 minutes later by the
device. FHT commands are buffered in the FHZ1x00/CUL till they are
sent to the FHT, see the related <code>fhtbuf</code> entry in the
<code><a href="#get">get</a></code> section.<br> You can send up to 8
commands in one message at once to the FHT if you specify them all as
arguments to the same set command, see the example above.
</li>
<br>
<li>time sets hour and minute to local time</li><br>
<li>date sets year, month and date to local time</li><br>
<li>refreshvalues is an alias for report1 255 report2 255</li><br>
<li>All <code>*-temp</code> values need a temperature
as argument, which will be rounded to 0.5 Celsius.<br>
Temperature values must between 5.5 and 30.5 Celsius. Value 5.5 sets
the actuator to OFF, value 30.5 set the actuator to ON</li><br>
<li><code>mode</code> is one of <code>auto, manual, holiday or
holiday_short.</code><br>
If the mode is either holiday or holiday_short, then the mode
switches back to auto at the specified day and time independent of
the current mode of the device and the desired temperature will be
set to the night or day temperature according to the defined weekly
schedule stored within the device.
In case of mode holiday
<ul>
<li>holiday1 sets the end-day of the holiday (at 00:00)</li>
<li>holiday2 sets the end-month of the holiday</li>
</ul>
For holiday_short (party mode)
<ul>
<li>holiday1 sets the absolute hour to switch back from this mode (in
10-minute steps, max 144)</li>
<li>holiday2 sets the day of month to switch back from this mode (can only be today or tomorrow, since holiday1 accepts only 24 hours).</li>
</ul>
Example:
<ul>
<li>current date is 29 Jan, time is 18:05</li>
<li>you want to switch to party mode until tomorrow 1:00</li>
<li>set holiday1 to 6 (6 x 10min = 1hour) and holiday2 to 30</li>
</ul>
The temperature for the holiday period is set by the
desired-temperature parameter.<br>
Note that you cannot set holiday mode for days earlier than the day
after tomorrow, for this you must use holiday_short.<br>
The parameters holiday1 and holiday2 must be set in one command
together with mode.<br>
Example:
<ul>
set FHT1 mode holiday holiday1 24 holiday2 12 desired-temp 14
</ul>
Please note: If the event time specified by the holiday parameters
has already past, then the device will immediately switch back to
auto mode including the selection of the corresponding day or night
temperature. This is valid at least for FHT80b model 2 and 3, Lifetec
MD12050. For those devices setting holiday_short with a holiday1
value of 0 and without the parameter holiday2 e.g.
<ul>
set FHT1 mode holiday_short holiday1 0
</ul>
will immediately switch back the device to mode auto including the
adjustment of the desired- temp parameter.
Some elderly FHT models, however, only switch the mode to auto, if
the event is within the past, but don't adjust the desired
temperature. In this case specifying appropriate values for the
parameters holiday1 and holiday2 thus defining an event in the very
near future (e.g. 10 minutes) could be the solution to force a switch
back to the correct automatic mode.
</li>
<br>
<li>The <code>*-from1/*-from2/*-to1/*-to2</code> valuetypes need a time
spec as argument in the HH:MM format. They define the periods, where
the day-temp is valid. The minute (MM) will be rounded to 10, and
24:00 means off.</li><br>
<li>To synchronize the FHT time and to "wake" muted FHTs it is adviseable
to schedule following command:<br>
<code>define fht_sync at +*3:30 set TYPE=FHT time</code>
</li>
<br>
<li><code>report1</code> with parameter 255 requests all settings for
monday till sunday to be sent. The argument is a bitfield, to request
unique values add up the following:
<ul>
<li> 1: monday</li>
<li> 2: tuesday</li>
<li> 4: thursday</li>
<li> 8: wednesday</li>
<li>16: friday</li>
<li>32: saturday</li>
<li>64: sunday</li>
</ul>
measured-temp and actuator is sent along if it is considered
appropriate
by the FHT.
<br><br>
<b>Note:</b> This command generates a lot of RF traffic, which can
lead to further problems, especially if the reception is not clear.
</li><br>
<li><code>report2</code> with parameter 255 requests the following
settings to be reported: day-temp night-temp windowopen-temp
lowtemp-offset desired-temp measured-temp mode warnings.
The argument is (more or less) a bitfield, to request unique values
add up the following:
<ul>
<li> 1: warnings</li>
<li> 2: mode</li>
<li> 4: day-temp, night-temp, windowopen-temp</li>
<li> 8: desired-temp</li>
<li>64: lowtemp-offset</li>
</ul>
measured-temp and actuator is sent along if it is considered
appropriate by the FHT.</li>
<br>
<li><code>lowtemp-offset</code> needs a temperature as argument, valid
values must be between 1.0 and 5.0 Celsius.<br> It will trigger a
warning if <code>desired-temp - measured-temp &gt;
lowtemp-offset</code> in a room for at least 1.5 hours after the last
desired-temp change.</li>
<br>
<li>FHEM optionally has an internal software buffer for FHT devices.
This buffer should prevent transmission errors. If there is no
confirmation for a given period, FHEM resends the command. You can
see the queued commands with <a href="#list">list</a>
&lt;fht-device&gt;.
See the <a href="#fhtsoftbuffer">fhtsoftbuffer</a>,
<a href="#retrycount">retrycount</a> and
<a href="#minfhtbuffer">minfhtbuffer</a> attributes for details.
</li>
<br>
<li>If a buffer is still in the softbuffer, it will be sent in the
following order:<br> <code>desired-temp,mode,report1,report2,
holiday1,holiday2,day-temp,night-temp, [all other commands]</code>
</li>
<br>
</ul>
</ul>
<br>
<b>Get</b> <ul>N/A</ul><br>
<a name="FHTattr"></a>
<b>Attributes</b>
<ul>
<li><a href="#attrdummy">dummy</a><br>
<b>Note:</b>It makes sense to define an FHT device even for an FHT8b,
else you will receive "unknown FHT device, please define one" message
for each FHT8b as the CUL is reporting the 8b valve messages. But you
should set the dummy attribute for these devices, else the internal FHT
buffer of the CUL will be filled with data for the 8b's which is never
consumed. If the buffer is full, you'll get "EOB" messages from the CUL,
and you cannot transmit any data to the 80b's</li><br>
<a name="retrycount"></a>
<li>retrycount<br>
If the <a href="#fhtsoftbuffer">fhtsoftbuffer</a> attribute is set, then
resend commands <code>retrycount</code> times if after 240 seconds
no confirmation message is received from the corresponding FHT
device.<br>
Default is 1.</li><br>
<a name="minfhtbuffer"></a>
<li>minfhtbuffer<br>
FHEM won't send commands to the FHZ if its fhtbuffer is below
this value, default is 0. If this value is low, then the ordering of
fht commands (see the note in the FHT section of <a href="#set">set</a>)
has little effect, as only commands in the softbuffer can be
prioritized. The maximum value should be 7 below the hardware maximum
(see fhtbuf).
</li><br>
<a name="lazy"></a>
<li>lazy<br>
If the lazy attribute is set, FHEM won't send commands to the FHT if
the current reading and the value to be set are already identical. This
may help avoiding conflicts with the max-1%-time-on-air rule in large
installations. Not set per default.
</li><br>
<a name="tmpcorr"></a>
<li>tmpcorr<br>
Correct the temperature reported by the FHT by the value specified.
Note: only the measured-temp value reported by FHEM (used for logging)
will be modified.
</li><br>
<li><a href="#ignore">ignore</a></li>
<li><a href="#do_not_notify">do_not_notify</a></li>
<li><a href="#model">model</a> (fht80b)</li>
<li><a href="#showtime">showtime</a></li>
<li><a href="#IODev">IODev</a></li>
<li><a href="#eventMap">eventMap</a></li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
</ul>
<br>
<a name="FHTevents"></a>
<b>Generated events:</b>
<ul>
<li>actuator</li>
<li>actuator1 actuator2 actuator3 actuator4<br>
actuator5 actuator6 actuator7 actuator8<br>
(sent if you configured an offset for the associated valve)</li>
<li>mon-from1 mon-to1 mon-from2 mon-to2</li>
<li>tue-from1 tue-to1 tue-from2 tue-to2</li>
<li>wed-from1 wed-to1 wed-from2 wed-to2</li>
<li>thu-from1 thu-to1 thu-from2 thu-to2</li>
<li>fri-from1 fri-to1 fri-from2 fri-to2</li>
<li>sat-from1 sat-to1 sat-from2 sat-to2</li>
<li>sun-from1 sun-to1 sun-from2 sun-to2</li>
<li>mode</li>
<li>holiday1 holiday2</li>
<li>desired-temp</li>
<li>measured-temp measured-low measured-high</li>
<li>warnings</li>
<li>manu-temp</li>
<li>year month day hour minute</li>
<li>day-temp night-temp lowtemp-offset windowopen-temp</li>
<li>ack can-xmit can-rcv ack2 start-xmit end-xmit
(only if the CUL is configured to transmit FHT protocol data)</li>
</ul>
<br>
</ul>
=end html
=begin html_DE
<a name="FHT"></a>
<h3>FHT</h3>
<ul>
Fhem kann FHT Funktelegramme (868.35 MHz) entweder mit einem <a
href="#FHZ">FHZ</a> oder einem <a href="#CUL">CUL</a> empfangen, daher muss
dieses zuerst definiert sein.
<br><br>
<a name="FHTdefine"></a>
<b>Define</b>
<ul>
define &lt;name&gt; FHT &lt;fhtaddress&gt;
<br><br>
&lt;fhtaddress&gt; ist eine vierstellige HEX Zahl entsprechend der
Adresse des FHT80b Ger&auml;tes.
<br>
Beispiel:
<ul>
define wz FHT 3232<br>
</ul>
<br>
Mehr dazu im FHT Abschnitt <a href="#set">set</a>.
</ul>
<br>
<a name="FHTset"></a>
<b>Set </b>
<ul>
set &lt;name&gt; &lt;valuetype&gt; &lt;value&gt;
<br><br>
Wobei value eines von folgenden ist:<br>
<ul>
desired-temp<br>
day-temp night-temp<br>
report1 report2<br>
refreshvalues<br>
mode<br>
holiday1 holiday2 # siehe mode holiday_short oder holiday<br>
manu-temp # Keine Ahnung was das bewirkt<br>
year month day hour minute<br>
time date<br>
lowtemp-offset # Alarm-Temp.-Differenz<br>
windowopen-temp<br>
mon-from1 mon-to1 mon-from2 mon-to2<br>
tue-from1 tue-to1 tue-from2 tue-to2<br>
wed-from1 wed-to1 wed-from2 wed-to2<br>
thu-from1 thu-to1 thu-from2 thu-to2<br>
fri-from1 fri-to1 fri-from2 fri-to2<br>
sat-from1 sat-to1 sat-from2 sat-to2<br>
sun-from1 sun-to1 sun-from2 sun-to2<br>
</ul>
Beispiele:
<ul>
set wz desired-temp 22.5<br>
set fl desired-temp 20.5 day-temp 19.0 night-temp 16.0<br>
</ul>
<br>
Hinweise:
<ul>
<li>Folgende Events werden (mehr oder weniger regelm&auml;&szlig;ig) von
jedem FHT Device gemeldet:
<ul>
measured-temp actuator actuator1...actuator8 warnings<br>
</ul>
Diese Strings k&ouml;nnen f&uuml;r <a href="#notify">notify</a> oder
<a href="#FileLog">FileLog</a> Definitionen verwendet werden.
<ul>
<li>Warnings k&ouml;nnen folgende Strings enthalten:
none, Battery low,Temperature too low, Window open,
Fault on window sensor
</li>
<li>actuator (ohne Suffix) steht f&uuml;r alle Aktoren.</li>
<li>actuator or actuator1..8 kann folgende Werte verarbeiten:
<ul>
<li>&lt;value&gt;%<br>
Das ist der Normalfall. Der Aktor wird angewiesen auf diesen
Wert zu &ouml;ffnen.
</li>
<li>offset &lt;value&gt;%<br>
Der Aktor l&auml;uft mit diesem Offset.
</li>
<li>lime-protection<br>
Der Aktor wird angewiesen die lime-protection (Kalkschutz)
Prozedur auszuf&uuml;hren.
</li>
<li>synctime<br>
Wenn Sond/Sync beim FHT80B gew&auml;hlt wird, wird ein
Countdown gesetzt.
</li>
<li>test<br>
Der Aktor wird vom FHT80b angewiesen zu piepsen (beep).
</li>
<li>pair<br>
Das FHT80b sendet ein "you-belong-to-me"
(Du-geh&ouml;rst-zu-mir) an diesen Aktor.
</li>
</ul></li>
</ul></li>
<br>
<li>Das FHT ist sehr sparsam (oder faul). Es akzeptiert eine Nachricht
vom FHZ1x00 alle 115+x Sekunden, wobei x von der fhtaddress
abh&auml;ngt. Nicht &uuml;berrascht sein wenn ein Befehl erst 10
Minuten sp&auml;ter vom Ger&auml;t angenommen wird. Die FHT Befehle
werden im FHZ1x00/CUL gepuffert bis sie zum FHT geschickt werden.
Siehe den zugeh&ouml;rigen fhtbuf Eintrag im der <a
href="#get">get</a> Abschnitt. Es k&ouml;nnen bis zu 8 Befehle in
einer Nachricht an ein FHT geschickt werden wenn diese alle als
Argumente im gleichen set Befehl zusammengefasst werden. Siehe
nachfolgendes Beispiel. </li><br>
<li>time setzt Stunde und Minute auf lokale Zeit</li><br>
<li>date setzt Jahr, Monat und Tag auf lokale Zeit</li><br>
<li>refreshvalues ist ein Alias f&uuml;r report1 255 report2 255</li><br>
<li>Alle *-temp Werte brauchen eine Temperatur als Argument welche auf
0.5&deg;C gerundet wird.<br> Temperatur Werte m&uuml;ssen zwischen
5.5&deg;C und 30.5&deg;C sein. Der Wert 5.5 setzt den Aktor auf OFF,
der Wert 30.5 setzt den Aktor auf ON</li><br>
<li>mode kann auto, manual, holiday or
holiday_short sein.<br>
Wenn der mode holiday ist, schaltet dieser zur&uuml;ck auf entweder
auto oder manual um 00:00 des Tages der wie folgt spezifiziert wird:
<ul>
<li>holiday1 setzt Endtag des Urlaubs</li>
<li>holiday2 setzt den Endmonat des Urlaubs</li>
</ul>
F&uuml;r holiday_short (Party Modus)
<ul>
<li> holiday1 setzt die absolute Stunde zu der von diesem Modus
zur&uuml;ck geschalten wird (in 10-Minuten Schritten, max.
144)</li>
<li> holiday2 setzt den Tag des Monats an dem von diesem Modus
zur&uuml;ck geschalten wird (kann nur heute oder morgen sein, da
holiday1 nur 24h akzeptiert.)</li>
Beispiel:
<ul>
<li>Aktuelles Datum ist der 29. Januar, Uhrzeit ist 18:05</li>
<li>Es soll bis morgen 1:00Uhr in den Party Modus geschalten
sein</li>
<li>set holiday1 to 6 (6 x 10min = Std) and holiday2 to
30</li>
</ul>
</ul>
Die Temperatur f&uuml;r den Urlaubszeitraum wird durch den
desired-temperature Parameter setzt. <br> Bitte beachten, dass der
Holiday Mode nicht fr&uuml;her als auf &Uuml;bermorgen eingestellt
werden kann. Alternativ muss hier holiday_short genutzt werden.<br>
Weiterhin bitte beachten das diese Kommandos nur in einem
"Sammelkommando" erfolgen k&ouml;nnen. Beispiel:
<br>
set FHT1 mode holiday holiday1 24 holiday2 12 desired-temp 14
</li><br>
<li>Die *-from1/*-from2/*-to1/*-to2 Wertetypen brauchen eine
Zeitspezifikation als Argument im Format HH:MM. Diese definieren den
Zeitraum in dem die day-temp g&uuml;ltig ist. Minuten (MM) werden
auf 10er gerundet, 24:00 bedeutet OFF. </li><br>
<li>Um die FHZ Zeit zu synchronisieren und um "stumme" Ger&auml;te
zu wecken, wird folgendes Kommando empfohlen:<br> define fht_sync at
+*3:30 set TYPE=FHT time </li><br>
<li>report1 mit dem Parameter 255 fordert das Senden aller Einstellungen
von Montag bis Sonntag an. Das Argument ist ein Bitfeld um einzelne
Werte wie folgt anzufordern:
<ul>
<li> 1: monday</li>
<li> 2: tuesday</li>
<li> 4: thursday</li>
<li> 8: wednesday</li>
<li>16: friday</li>
<li>32: saturday</li>
<li>64: sunday</li>
</ul>
measured-temp und actuator werden mitgesendet wenn vom FHT als
notwendig erachtet.
<br><br>
<b>Hinweis:</b> Dieser Befehl erzeugt sehr viel Funkverkehr was zu
weiteren Problemen f&uuml;hren kann, besonders wenn Empfang nicht gut
ist. </li><br>
<li>report2 mit dem Parameter 255 fordert die Ausgabe der nachfolgenden
Einstellungen an:<br> day-temp night-temp windowopen-temp
lowtemp-offset desired-temp measured-temp mode warnings.<br> Das
Argument ist ein Bitfeld, um einzelne Werte abzufragen folgendes
anh&auml;ngen:
<ul>
<li> 1: warnings</li>
<li> 2: mode</li>
<li> 4: day-temp, night-temp, windowopen-temp</li>
<li> 8: desired-temp</li>
<li>64: lowtemp-offset</li>
</ul>
measured-temp und actuator werden mitgesendet wenn vom FHT als
notwendig erachtet. <br></li>
<li>lowtemp-offset braucht eine Temperatur als Argument. G&uuml;ltige
Werte m&uuml;ssen zwischen 1.0 und 5.0&deg;C liegen.<br> Wird eine
Warnung erzeugen wenn die desired-temp - measured-temp &gt;
lowtemp-offset, jedoch fr&uuml;hestens 1,5Stunden nach der letzten
&Auml;nderung der desired-temp. </li><br>
<li>FHEM hat optional einen internen Softwarepuffer f&uuml;r FHT
Devices. Dieser Puffer soll vor &Uuml;bertragungsfehlern
sch&uuml;tzen. Wenn nach einem bestimmten Zeitraum keine
Best&auml;tigung erhalten wurde wird FHEM den Befehl erneut senden.
Die Befehle in der Warteschlagen k&ouml;nnen mit <a
href="#list">list</a> &lt;fht-device&gt; angezeigt werden. Siehe die
Attribute <a href="#fhtsoftbuffer">fhtsoftbuffer</a>, <a
href="#retrycount">retrycount</a> und <a
href="#minfhtbuffer">minfhtbuffer</a> f&uuml;r weitere Details.
</li><br>
<li>Befehle im Softwarepuffer werden in folgender Reihenfolge
gesendet:<br>
desired-temp,mode,report1,report2,holiday1,holiday2,day-temp,night-temp,
[all other commands] </li><br>
</ul>
</ul>
<br>
<b>Get</b> <ul>N/A</ul><br>
<a name="FHTattr"></a>
<b>Attribute</b>
<ul>
<li><a href="#attrdummy">dummy</a><br>
<b>Hinweis:</b> Es macht Sinn ein FHT Device auch f&uuml;r ein FHT8b zu
definieren da sonst der Fehler "unknown FHT device, please define one"
f&uuml;r jedes FHT8b generiert wird, denn das CUL meldet die 8b
Nachrichten. Das dummy Attribut sollte bei diesen Devices gesetzt werden
da sonst der interne FHT Buffer des CUL mit 8b-Daten gef&uuml;llt wird
die niemals gebraucht werden. Wenn der Puffer dann voll ist werden "EOB"
Nachrichten vom CUL erzeugt, und Senden zu den 8b ist nicht mehr
m&ouml;glich.</li><br>
<a name="retrycount"></a>
<li>retrycount<br>
Wenn das <a href="#fhtsoftbuffer">fhtsoftbuffer</a> Attribut gesetzt ist,
dann werden die Befehle entsprechend dem retrycount n-mal erneut
versendet wenn nach 240 Sekunden keine Best&auml;tigungsmeldung vom
entsprechenden FHZ Device empfangen wurde.<br> Der Default-Wert ist
1.</li><br>
<a name="minfhtbuffer"></a>
<li>minfhtbuffer<br>
FHEM sendet keine Befehle mehr zum FHZ wenn der fhtbuffer-Wert diesen
Wert unterschritten hat. Default-Wert ist 0. Wenn dieser Wert zu niedrig
ist hat die Reihenfolge von fht-Befehlen weniger Einfluss da nur Befehle
im Softbuffer priorisiert werden k&ouml;nnen. (Siehe Hinweise in der FHT
Sektion <a href="#set">set</a>) Der Maximalwert sollte 7 unter dem
Hardware Maximum sein, siehe fhtbuf. </li><br>
<a name="lazy"></a>
<li>lazy<br>
Wenn das Attribut lazy (faul) gesetzt wurde sendet FHEM keine Befehle
wenn die aktuell gelesenen Werte und der zu setzende Wert identisch sind.
Das spart Funkzeit und hilft Konflikte mit der Regelung die besagt, dass
maximal 1% der Zeit als Funkzeit verwendet werden darf, zu vermeiden.
Nicht standardm&auml;&szlig;ig aktiviert. </li><br>
<a name="tmpcorr"></a>
<li>tmpcorr<br>
Korrigiert die Werte die vom FHZ gemeldet werden um den angegebenen Wert.
Hinweis: nur die measured-temp Werte die von FHEM gemeldet (f&uuml;r
Logging genutzt) werden angepasst. </li><br>
<li><a href="#ignore">ignore</a></li>
<li><a href="#do_not_notify">do_not_notify</a></li>
<li><a href="#model">model</a> (fht80b)</li>
<li><a href="#showtime">showtime</a></li>
<li><a href="#IODev">IODev</a></li>
<li><a href="#eventMap">eventMap</a></li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
</ul>
<br>
<a name="FHTevents"></a>
<b>Erzeugte Events:</b>
<ul>
<li>actuator</li>
<li>actuator1 actuator2 actuator3 actuator4<br>
actuator5 actuator6 actuator7 actuator8<br>
(wird gesendet wenn ein Offset zum entsprechenden Ventil konfiguriert wurde)</li>
<li>mon-from1 mon-to1 mon-from2 mon-to2</li>
<li>tue-from1 tue-to1 tue-from2 tue-to2</li>
<li>wed-from1 wed-to1 wed-from2 wed-to2</li>
<li>thu-from1 thu-to1 thu-from2 thu-to2</li>
<li>fri-from1 fri-to1 fri-from2 fri-to2</li>
<li>sat-from1 sat-to1 sat-from2 sat-to2</li>
<li>sun-from1 sun-to1 sun-from2 sun-to2</li>
<li>mode</li>
<li>holiday1 holiday2</li>
<li>desired-temp</li>
<li>measured-temp measured-low measured-high</li>
<li>warnings</li>
<li>manu-temp</li>
<li>year month day hour minute</li>
<li>day-temp night-temp lowtemp-offset windowopen-temp</li>
<li>ack can-xmit can-rcv ack2 start-xmit end-xmit (Nur wenn das CUL
f&uuml;r die &Uuml;bertragung von FHT Protokoll Daten konfiguriert
ist)</li>
</ul>
<br>
</ul>
=end html_DE
=cut