# $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 . # ############################################################################## 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 = ( "minute" => 0, "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 "adjusthour") { my @t = localtime; splice(@a,$i,1,("hour",$t[2])); } if($a[$i] eq "adjustminute") { my @t = localtime; splice(@a,$i,1,("minute",$t[1])); } 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 adjusthour:noArg adjustminute: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 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}; my $val2 = ($val eq "30.5" ? "on" : $val eq "5.5" ? "off" : ""); Log3 $name, 4, "FHT softbuffer check: $hname / $hcmd / $val / $val2"; if($hname eq $name && ($hcmd =~ m/^$cmd $val/ || $hcmd =~ m/^$cmd $val2/)) { $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 ? $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äten (FHT80b) =begin html

FHT

    Fhem can receive FHT radio (868.35 MHz) messages either through an FHZ or an CUL device, so this must be defined first.

    Define
      define <name> FHT <fhtaddress>

      <fhtaddress> is a four digit hex number, corresponding to the address of the FHT80b device.
      Examples:
        define wz FHT 3232

      See the FHT section in set for more.

    Set
      set <name> <valuetype> <value>

      where value is one of:
        desired-temp
        day-temp night-temp
        report1 report2
        refreshvalues
        mode
        holiday1 holiday2 # see mode holiday_short or holiday
        manu-temp # No clue what it does.
        year month day hour minute
        time date adjusthour adjustminute
        lowtemp-offset # Alarm-Temp.-Differenz
        windowopen-temp
        mon-from1 mon-to1 mon-from2 mon-to2
        tue-from1 tue-to1 tue-from2 tue-to2
        wed-from1 wed-to1 wed-from2 wed-to2
        thu-from1 thu-to1 thu-from2 thu-to2
        fri-from1 fri-to1 fri-from2 fri-to2
        sat-from1 sat-to1 sat-from2 sat-to2
        sun-from1 sun-to1 sun-from2 sun-to2
      Examples:
        set wz desired-temp 22.5
        set fl desired-temp 20.5 day-temp 19.0 night-temp 16.0

      Notes:
      • Following events are reported (more or less regularly) by each FHT device: measured-temp actuator actuator1...actuator8 warnings
        You can use these strings for notify or FileLog definitions.
        • warnings can contain following strings: none, Battery low,Temperature too low, Window open, Fault on window sensor
        • actuator (without a suffix) stands for all actuators.
        • actuator or actuator1..8 can take following values:
          • <value>%
            This is the normal case, the actuator is instructed to open to this value.
          • offset <value>%
            The actuator is running with this offset.
          • lime-protection
            The actuator was instructed to execute the lime-protection procedure.
          • synctime
            If you select Sond/Sync on the FHT80B, you'll see a count down.
          • test
            The actuator was instructed by the FHT80b to emit a beep.
          • pair
            The the FHT80b sent a "you-belong-to-me" to this actuator.

      • 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 fhtbuf entry in the get section.
        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.

      • time sets hour and minute to local time

      • date sets year, month and date to local time

      • adjusthour and adjustminute set hour or minute to local time, respectively

      • refreshvalues is an alias for report1 255 report2 255

      • All *-temp values need a temperature as argument, which will be rounded to 0.5 Celsius.
        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

      • mode is one of auto, manual, holiday or holiday_short.
        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
        • holiday1 sets the end-day of the holiday (at 00:00)
        • holiday2 sets the end-month of the holiday
        For holiday_short (party mode)
        • holiday1 sets the absolute hour to switch back from this mode (in 10-minute steps, max 144)
        • holiday2 sets the day of month to switch back from this mode (can only be today or tomorrow, since holiday1 accepts only 24 hours).
        Example:
        • current date is 29 Jan, time is 18:05
        • you want to switch to party mode until tomorrow 1:00
        • set holiday1 to 6 (6 x 10min = 1hour) and holiday2 to 30
        The temperature for the holiday period is set by the desired-temperature parameter.
        Note that you cannot set holiday mode for days earlier than the day after tomorrow, for this you must use holiday_short.
        The parameters holiday1 and holiday2 must be set in one command together with mode.
        Example:
          set FHT1 mode holiday holiday1 24 holiday2 12 desired-temp 14
        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.
          set FHT1 mode holiday_short holiday1 0
        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.

      • The *-from1/*-from2/*-to1/*-to2 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.

      • To synchronize the FHT time and to "wake" muted FHTs it is adviseable to schedule following command:
        define fht_sync at +*3:30 set TYPE=FHT time

      • report1 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:
        • 1: monday
        • 2: tuesday
        • 4: thursday
        • 8: wednesday
        • 16: friday
        • 32: saturday
        • 64: sunday
        measured-temp and actuator is sent along if it is considered appropriate by the FHT.

        Note: This command generates a lot of RF traffic, which can lead to further problems, especially if the reception is not clear.

      • report2 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:
        • 1: warnings
        • 2: mode
        • 4: day-temp, night-temp, windowopen-temp
        • 8: desired-temp
        • 64: lowtemp-offset
        measured-temp and actuator is sent along if it is considered appropriate by the FHT.

      • lowtemp-offset needs a temperature as argument, valid values must be between 1.0 and 5.0 Celsius.
        It will trigger a warning if desired-temp - measured-temp > lowtemp-offset in a room for at least 1.5 hours after the last desired-temp change.

      • 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 list <fht-device>. See the fhtsoftbuffer, retrycount and minfhtbuffer attributes for details.

      • If a buffer is still in the softbuffer, it will be sent in the following order:
        desired-temp,mode,report1,report2, holiday1,holiday2,day-temp,night-temp, [all other commands]


    Get
      N/A

    Attributes
    • dummy
      Note: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

    • retrycount
      If the fhtsoftbuffer attribute is set, then resend commands retrycount times if after 240 seconds no confirmation message is received from the corresponding FHT device.
      Default is 1.

    • minfhtbuffer
      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 set) has little effect, as only commands in the softbuffer can be prioritized. The maximum value should be 7 below the hardware maximum (see fhtbuf).

    • lazy
      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.

    • tmpcorr
      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.

    • ignore
    • do_not_notify
    • model (fht80b)
    • showtime
    • IODev
    • eventMap
    • readingFnAttributes

    Generated events:
    • actuator
    • actuator1 actuator2 actuator3 actuator4
      actuator5 actuator6 actuator7 actuator8
      (sent if you configured an offset for the associated valve)
    • mon-from1 mon-to1 mon-from2 mon-to2
    • tue-from1 tue-to1 tue-from2 tue-to2
    • wed-from1 wed-to1 wed-from2 wed-to2
    • thu-from1 thu-to1 thu-from2 thu-to2
    • fri-from1 fri-to1 fri-from2 fri-to2
    • sat-from1 sat-to1 sat-from2 sat-to2
    • sun-from1 sun-to1 sun-from2 sun-to2
    • mode
    • holiday1 holiday2
    • desired-temp
    • measured-temp measured-low measured-high
    • warnings
    • manu-temp
    • year month day hour minute
    • day-temp night-temp lowtemp-offset windowopen-temp
    • ack can-xmit can-rcv ack2 start-xmit end-xmit (only if the CUL is configured to transmit FHT protocol data)

=end html =begin html_DE

FHT

    Fhem kann FHT Funktelegramme (868.35 MHz) entweder mit einem FHZ oder einem CUL empfangen, daher muss dieses zuerst definiert sein.

    Define
      define <name> FHT <fhtaddress>

      <fhtaddress> ist eine vierstellige HEX Zahl entsprechend der Adresse des FHT80b Gerätes.
      Beispiel:
        define wz FHT 3232

      Mehr dazu im FHT Abschnitt set.

    Set
      set <name> <valuetype> <value>

      Wobei value eines von folgenden ist:
        desired-temp
        day-temp night-temp
        report1 report2
        refreshvalues
        mode
        holiday1 holiday2 # siehe mode holiday_short oder holiday
        manu-temp # Keine Ahnung was das bewirkt
        year month day hour minute
        time date adjusthour adjustminute
        lowtemp-offset # Alarm-Temp.-Differenz
        windowopen-temp
        mon-from1 mon-to1 mon-from2 mon-to2
        tue-from1 tue-to1 tue-from2 tue-to2
        wed-from1 wed-to1 wed-from2 wed-to2
        thu-from1 thu-to1 thu-from2 thu-to2
        fri-from1 fri-to1 fri-from2 fri-to2
        sat-from1 sat-to1 sat-from2 sat-to2
        sun-from1 sun-to1 sun-from2 sun-to2
      Beispiele:
        set wz desired-temp 22.5
        set fl desired-temp 20.5 day-temp 19.0 night-temp 16.0

      Hinweise:
      • Folgende Events werden (mehr oder weniger regelmäßig) von jedem FHT Device gemeldet:
          measured-temp actuator actuator1...actuator8 warnings
        Diese Strings können für notify oder FileLog Definitionen verwendet werden.
        • Warnings können folgende Strings enthalten: none, Battery low,Temperature too low, Window open, Fault on window sensor
        • actuator (ohne Suffix) steht für alle Aktoren.
        • actuator or actuator1..8 kann folgende Werte verarbeiten:
          • <value>%
            Das ist der Normalfall. Der Aktor wird angewiesen auf diesen Wert zu öffnen.
          • offset <value>%
            Der Aktor läuft mit diesem Offset.
          • lime-protection
            Der Aktor wird angewiesen die lime-protection (Kalkschutz) Prozedur auszuführen.
          • synctime
            Wenn Sond/Sync beim FHT80B gewählt wird, wird ein Countdown gesetzt.
          • test
            Der Aktor wird vom FHT80b angewiesen zu piepsen (beep).
          • pair
            Das FHT80b sendet ein "you-belong-to-me" (Du-gehörst-zu-mir) an diesen Aktor.

      • Das FHT ist sehr sparsam (oder faul). Es akzeptiert eine Nachricht vom FHZ1x00 alle 115+x Sekunden, wobei x von der fhtaddress abhängt. Nicht überrascht sein wenn ein Befehl erst 10 Minuten später vom Gerät angenommen wird. Die FHT Befehle werden im FHZ1x00/CUL gepuffert bis sie zum FHT geschickt werden. Siehe den zugehörigen fhtbuf Eintrag im der get Abschnitt. Es kö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.

      • time setzt Stunde und Minute auf lokale Zeit

      • date setzt Jahr, Monat und Tag auf lokale Zeit

      • adjusthour und adjustminute setzen Stunde bzw. Minute auf lokale Zeit

      • refreshvalues ist ein Alias für report1 255 report2 255

      • Alle *-temp Werte brauchen eine Temperatur als Argument welche auf 0.5°C gerundet wird.
        Temperatur Werte müssen zwischen 5.5°C und 30.5°C sein. Der Wert 5.5 setzt den Aktor auf OFF, der Wert 30.5 setzt den Aktor auf ON

      • mode kann auto, manual, holiday or holiday_short sein.
        Wenn der mode holiday ist, schaltet dieser zurück auf entweder auto oder manual um 00:00 des Tages der wie folgt spezifiziert wird:
        • holiday1 setzt Endtag des Urlaubs
        • holiday2 setzt den Endmonat des Urlaubs
        Für holiday_short (Party Modus)
        • holiday1 setzt die absolute Stunde zu der von diesem Modus zurück geschalten wird (in 10-Minuten Schritten, max. 144)
        • holiday2 setzt den Tag des Monats an dem von diesem Modus zurück geschalten wird (kann nur heute oder morgen sein, da holiday1 nur 24h akzeptiert.)
        • Beispiel:
          • Aktuelles Datum ist der 29. Januar, Uhrzeit ist 18:05
          • Es soll bis morgen 1:00Uhr in den Party Modus geschalten sein
          • set holiday1 to 6 (6 x 10min = Std) and holiday2 to 30
        Die Temperatur für den Urlaubszeitraum wird durch den desired-temperature Parameter setzt.
        Bitte beachten, dass der Holiday Mode nicht früher als auf Übermorgen eingestellt werden kann. Alternativ muss hier holiday_short genutzt werden.
        Weiterhin bitte beachten das diese Kommandos nur in einem "Sammelkommando" erfolgen können. Beispiel:
        set FHT1 mode holiday holiday1 24 holiday2 12 desired-temp 14

      • 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ültig ist. Minuten (MM) werden auf 10er gerundet, 24:00 bedeutet OFF.

      • Um die FHZ Zeit zu synchronisieren und um "stumme" Geräte zu wecken, wird folgendes Kommando empfohlen:
        define fht_sync at +*3:30 set TYPE=FHT time

      • 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:
        • 1: monday
        • 2: tuesday
        • 4: thursday
        • 8: wednesday
        • 16: friday
        • 32: saturday
        • 64: sunday
        measured-temp und actuator werden mitgesendet wenn vom FHT als notwendig erachtet.

        Hinweis: Dieser Befehl erzeugt sehr viel Funkverkehr was zu weiteren Problemen führen kann, besonders wenn Empfang nicht gut ist.

      • report2 mit dem Parameter 255 fordert die Ausgabe der nachfolgenden Einstellungen an:
        day-temp night-temp windowopen-temp lowtemp-offset desired-temp measured-temp mode warnings.
        Das Argument ist ein Bitfeld, um einzelne Werte abzufragen folgendes anhängen:
        • 1: warnings
        • 2: mode
        • 4: day-temp, night-temp, windowopen-temp
        • 8: desired-temp
        • 64: lowtemp-offset
        measured-temp und actuator werden mitgesendet wenn vom FHT als notwendig erachtet.
      • lowtemp-offset braucht eine Temperatur als Argument. Gültige Werte müssen zwischen 1.0 und 5.0°C liegen.
        Wird eine Warnung erzeugen wenn die desired-temp - measured-temp > lowtemp-offset, jedoch frühestens 1,5Stunden nach der letzten Änderung der desired-temp.

      • FHEM hat optional einen internen Softwarepuffer für FHT Devices. Dieser Puffer soll vor Übertragungsfehlern schützen. Wenn nach einem bestimmten Zeitraum keine Bestätigung erhalten wurde wird FHEM den Befehl erneut senden. Die Befehle in der Warteschlagen können mit list <fht-device> angezeigt werden. Siehe die Attribute fhtsoftbuffer, retrycount und minfhtbuffer für weitere Details.

      • Befehle im Softwarepuffer werden in folgender Reihenfolge gesendet:
        desired-temp,mode,report1,report2,holiday1,holiday2,day-temp,night-temp, [all other commands]


    Get
      N/A

    Attribute
    • dummy
      Hinweis: Es macht Sinn ein FHT Device auch für ein FHT8b zu definieren da sonst der Fehler "unknown FHT device, please define one" fü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ü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öglich.

    • retrycount
      Wenn das fhtsoftbuffer Attribut gesetzt ist, dann werden die Befehle entsprechend dem retrycount n-mal erneut versendet wenn nach 240 Sekunden keine Bestätigungsmeldung vom entsprechenden FHZ Device empfangen wurde.
      Der Default-Wert ist 1.

    • minfhtbuffer
      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önnen. (Siehe Hinweise in der FHT Sektion set) Der Maximalwert sollte 7 unter dem Hardware Maximum sein, siehe fhtbuf.

    • lazy
      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äßig aktiviert.

    • tmpcorr
      Korrigiert die Werte die vom FHZ gemeldet werden um den angegebenen Wert. Hinweis: nur die measured-temp Werte die von FHEM gemeldet (für Logging genutzt) werden angepasst.

    • ignore
    • do_not_notify
    • model (fht80b)
    • showtime
    • IODev
    • eventMap
    • readingFnAttributes

    Erzeugte Events:
    • actuator
    • actuator1 actuator2 actuator3 actuator4
      actuator5 actuator6 actuator7 actuator8
      (wird gesendet wenn ein Offset zum entsprechenden Ventil konfiguriert wurde)
    • mon-from1 mon-to1 mon-from2 mon-to2
    • tue-from1 tue-to1 tue-from2 tue-to2
    • wed-from1 wed-to1 wed-from2 wed-to2
    • thu-from1 thu-to1 thu-from2 thu-to2
    • fri-from1 fri-to1 fri-from2 fri-to2
    • sat-from1 sat-to1 sat-from2 sat-to2
    • sun-from1 sun-to1 sun-from2 sun-to2
    • mode
    • holiday1 holiday2
    • desired-temp
    • measured-temp measured-low measured-high
    • warnings
    • manu-temp
    • year month day hour minute
    • day-temp night-temp lowtemp-offset windowopen-temp
    • ack can-xmit can-rcv ack2 start-xmit end-xmit (Nur wenn das CUL für die Übertragung von FHT Protokoll Daten konfiguriert ist)

=end html_DE =cut