2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

- Softwarebuffer for FHT devices with queuing unsent commands and repeating commands by transmission failure

- FHT low temperatur warning and setting for lowtemp-offset
- Change naming for state into warnings


git-svn-id: https://svn.fhem.de/fhem/trunk@101 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
dirkh 2007-10-19 09:29:00 +00:00
parent 72b261d6aa
commit 04a95a803f
7 changed files with 2360 additions and 1931 deletions

View File

@ -348,3 +348,6 @@
- feature: webpgm2 output reformatted
- feature: webpgm2 can display multiple plots.
- feature: FHT lime-protection code discovered by Dirk (7.10)
- feature: Softwarebuffer for FHT devices with queuing unsent commands and repeating commands by transmission failure (Dirk 17.10)
- feature: FHT low temperatur warning and setting for lowtemp-offset (Dirk 17.10)
- change: Change naming for state into warnings (Dirk 17.10)

View File

@ -68,7 +68,7 @@ FHZ_Initialize($)
$hash->{SetFn} = "FHZ_Set";
$hash->{StateFn} = "FHZ_SetState";
$hash->{ParseFn} = "FHZ_Parse";
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 filtertimeout repeater:1,0 showtime:1,0 model:fhz1000,fhz1300 loglevel:0,1,2,3,4,5,6";
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 filtertimeout repeater:1,0 showtime:1,0 model:fhz1000,fhz1300 loglevel:0,1,2,3,4,5,6 softbuffer softrepeat softmaxretry";
}
#####################################
@ -160,6 +160,24 @@ FHZ_Get($@)
return "$a[0] $a[1] => $v";
}
#####################################
# get the FHZ hardwarebuffer without logentry
# and as decimal value
sub getFhzBuffer()
{
my $msg = "Timeout";
while (index($msg,"Timeout") >= 0) { # try getting FHZ buffer until no Timeout occurs
FHZ_Write($defs{FHZ}, "04", "c90185") if(!IsDummy("FHZ"));
$msg = FHZ_ReadAnswer($defs{FHZ}, "fhtbuf");
}
my $v = substr($msg, 16, 2);
$v = hex $v;
return "$v";
}
#####################################
sub
FHZ_SetState($$$$)
@ -346,7 +364,8 @@ FHZ_ReadAnswer($$)
my $buf = $hash->{PortObj}->input();
Log 5, "FHZ/RAW: " . unpack('H*',$buf);
# Log 5, "FHZ/RAW: " . unpack('H*',$buf);
Log 4, "FHZ/RAW: " . unpack('H*',$buf);
$mfhzdata .= $buf;
next if(length($mfhzdata) < 2);

View File

@ -50,7 +50,8 @@ my %codes = (
"XX0069" => "measured-temp", # sum of next. two, never "really" sent
"420069" => "measured-low",
"430069" => "measured-high",
"440069" => "state",
"440069" => "warnings",
"450069" => "manu-temp", # Manuelle Temperatur keine ahnung was das bewirkt
"600069" => "year",
"610069" => "month",
"620069" => "day",
@ -59,10 +60,9 @@ my %codes = (
"650069" => "init",
"820069" => "day-temp",
"840069" => "night-temp",
"850069" => "unknown_85",
"850069" => "lowtemp-offset", # Alarm-Temp.-Differenz
"8a0069" => "windowopen-temp",
"00002a" => "lime-protection",
"0000aa" => "code_0000aa",
"0000ba" => "code_0000ba",
"430079" => "code_430079",
@ -86,7 +86,7 @@ my %cantset = (
"measured-temp" => 1,
"measured-high" => 1,
"measured-low" => 1,
"state" => 1,
"warnings" => 1,
"init" => 1,
"lime-protection"=>1,
@ -104,12 +104,25 @@ my %nosetarg = (
"refreshvalues" => 1,
);
my %priority = (
"desired-temp" => 1,
"mode" => 2,
"refreshvalues" => 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; # Setteable values
my %m2c; # Reverse c2m
my %c2b; # command->button hash (reverse of codes)
my %c2bset; # Setteable values
my %defptr;
my $timerCheckBufferIsRunning = 0; # set to 1 if the timer is running
my $minFhzHardwareBufferSpace = 10; # min. bytes free in hardware buffer before sending commands
my $fhzHardwareBufferSpace = 0; # actual hardware buffer space in fhz
#####################################
sub
@ -143,29 +156,115 @@ FHT_Initialize($)
$hash->{AttrList} = "do_not_notify:0,1 model;fht80b dummy:0,1 showtime:0,1 loglevel:0,1,2,3,4,5,6";
}
#####################################
sub
FHT_Set($@)
# Parse the incomming commands and send them via sendCommand to the FHZ
# or via toSendbuffer in the Softwarebuffer (queue)
#
sub FHT_Set($@)
{
my ($hash, @a) = @_;
my $ret = undef;
my ($hash, @a) = @_;
my $ret = undef;
my $arg = "020183" . $hash->{CODE} . $c2bset{$a[1]};
my $val = $a[2];
return "\"set $a[0]\" needs two parameters" if(@a < 2);
return "Unknown argument $a[1], choose one of " .
join(" ", sort {$c2bset{$a} cmp $c2bset{$b} } keys %c2bset)
if(!defined($c2bset{$a[1]}));
return "\"set $a[0]\" needs two parameters"
if(@a != 3 && !(@a == 2 && $nosetarg{$a[1]}));
Log GetLogLevel($a[0],2), "FHT set " . join(" ", @a);
my $arg = "020183" . $hash->{CODE} . $c2bset{$a[1]};
if(@a != 3 && !(@a == 2 && $nosetarg{$a[1]}));
if($a[1] eq "refreshvalues") {
} elsif ($a[1] =~ m/-temp/) {
return "Invalid temperature, use NN.N" if($val !~ m/^\d*\.?\d+$/);
# additional check for temperature
return "Invalid temperature, must between 5.5 and 30.5" if($val < 5.5 || $val > 30.5);
my $a = int($val*2);
$arg .= sprintf("%02x", $a);
$ret = sprintf("Rounded temperature to %.1f", $a/2) if($a/2 != $val);
$val = sprintf("%.1f", $a/2) if($a/2 != $val);
$val = sprintf("%.1f", $val);
} elsif($a[1] =~ m/-from/ || $a[1] =~ 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, ($2/10)*10);
$val = $nt if($nt ne $val);
$ret = "Rounded time to $nt" if($nt ne $val);
} elsif($a[1] eq "mode") {
return "Invalid mode, use one of " . join(" ", sort keys %m2c)
if(!defined($m2c{$val}));
$arg .= sprintf("%02x", $m2c{$val});
} elsif ($a[1] eq "lowtemp-offset") {
return "Invalid lowtemperature-offset, use N" if($val !~ m/^\d*\.?\d+$/);
# additional check for temperature
return "Invalid lowtemperature-offset, must between 1 and 5" if($val < 1 || $val > 5);
my $a = int($val);
$arg .= sprintf("%02x", $a);
$ret = sprintf("Rounded temperature to %d.0", $a) if($a != $val);
$val = "$a.0";
} else { # Holiday1, Holiday2
$arg .= sprintf("%02x", $val);
}
my $dev = $hash->{CODE};
my $def = $defptr{$dev};
my $name = $def->{NAME};
my $type = $a[1];
my $sbCount = keys(%{$def->{SENDBUFFER}}); # Count of sendbuffer
# get firsttime hardware buffer of FHZ if $fhzHardwareBufferSpace not set
$fhzHardwareBufferSpace = getFhzBuffer () if ($fhzHardwareBufferSpace == 0);
# set default values for config value attr FHZ softbuffer
$attr{FHZ}{softbuffer} = 1 if (!defined($attr{FHZ}{softbuffer}));
$val = "" if (!defined($val));
if ( ($sbCount == 0 && $fhzHardwareBufferSpace >= $minFhzHardwareBufferSpace) || $attr{FHZ}{softbuffer} == 0) {
sendCommand ($hash, $arg, $name, $type, $val); # send command direct to FHZ
} else {
Log GetLogLevel($name,2), "FHT set $name $type $val (Enqueue to buffer)" if ($fhzHardwareBufferSpace >= $minFhzHardwareBufferSpace);
Log GetLogLevel($name,2), "Can't send command set $name $type $val. " .
"No space left in FHZ hardware buffer." if($fhzHardwareBufferSpace < $minFhzHardwareBufferSpace);
}
# only if softbuffer not disabled via config
if ($attr{FHZ}{softbuffer} == 1) {
toSendbuffer ($hash, $type, $val, $arg, "", 0); # send command also to buffer
if ($timerCheckBufferIsRunning == 0 && $init_done) {
$timerCheckBufferIsRunning = 1; # set $timerCheckBufferIsRunning to 1 to remeber a timer is running
InternalTimer(gettimeofday()+70, "timerCheckBuffer", $hash); # start internal Timer to periodical check the buffer
}
}
return $ret;
}
# Send command to FHZ
#
sub sendCommand ($$$$$)
{
my ($hash, $arg, $name, $type, $val) = @_;
if($type eq "refreshvalues") {
# This is special. Without the sleep the next FHT won't send its data
if(!IsDummy($a[0])) {
if(!IsDummy($name)) {
my $havefhz;
$havefhz = 1 if($hash->{IODev} && defined($hash->{IODev}->{FD}));
@ -174,36 +273,40 @@ FHT_Set($@)
IOWrite($hash, "04", "c90185"); # Check the fht buffer
sleep(1) if($havefhz);
}
return $ret;
} elsif($a[1] =~ m/-temp/) {
return "Invalid temperature, use NN.N" if($a[2] !~ m/^\d*\.?\d+$/);
my $a = int($a[2]*2);
$arg .= sprintf("%02x", $a);
$ret = "Rounded temperature to " . $a/2 if($a/2 != $a[2]);
} elsif($a[1] =~ m/-from/ || $a[1] =~ m/-to/) {
return "Invalid timeformat, use HH:MM" if($a[2] !~ m/^([0-2]\d):([0-5]\d)/);
my $a = ($1*6) + ($2/10);
$arg .= sprintf("%02x", $a);
my $nt = sprintf("%02d:%02d", $1, ($2/10)*10);
$ret = "Rounded time to $nt" if($nt ne $a[2]);
} elsif($a[1] eq "mode") {
return "Invalid mode, use one of " . join(" ", sort keys %m2c)
if(!defined($m2c{$a[2]}));
$arg .= sprintf("%02x", $m2c{$a[2]});
} else { # Holiday1, Holiday2
$arg .= sprintf("%02x", $a[2]);
} else {
IOWrite($hash, "04", $arg) if(!IsDummy($name));
}
IOWrite($hash, "04", $arg) if(!IsDummy($a[0]));
return $ret;
Log GetLogLevel($name,2), "FHT set $name $type $val";
# decrease $fhzHardwareBufferSpace for each command sending to the FHZ
$fhzHardwareBufferSpace = $fhzHardwareBufferSpace -5 if(!IsDummy($name));
}
sub resendCommand ($)
{
my ($buffer) = @_;
my $hash = $buffer->{HASH};
my $dev = $hash->{CODE};
my $def = $defptr{$dev};
my $nRetry = $buffer->{RETRY} + 1;
if ($fhzHardwareBufferSpace > $minFhzHardwareBufferSpace) {
Log GetLogLevel($def->{NAME},2), "Resending command to FHT set " . $def->{NAME} . " " . $buffer->{TYPE} . " " . $buffer->{VAL} .
" (Retry $nRetry / ". $attr{FHZ}{softmaxretry} . ")";
sendCommand ($buffer->{HASH}, $buffer->{ARG}, $buffer->{NAME}, $buffer->{TYPE}, $buffer->{VAL});
toSendbuffer ($buffer->{HASH}, $buffer->{TYPE}, $buffer->{VAL}, $buffer->{ARG}, $buffer->{KEY}, $nRetry); # send command also to buffer
} else {
Log GetLogLevel($def->{NAME},2), "Can't send command \"set " . $def->{NAME} . " " . $buffer->{TYPE} . " " . $buffer->{VAL} .
"\". No space in FHZ hardware buffer left. Resending next time if free bufferspace available.";
}
}
#####################################
sub
FHT_SetState($$$$)
@ -249,27 +352,27 @@ FHT_Undef($$)
}
#####################################
sub
sub
FHT_Parse($$)
{
my ($hash,$msg) = @_;
my ($hash, $msg) = @_;
my $dev = substr($msg, 16, 4);
my $cde = substr($msg, 20, 6);
my $val = substr($msg, 26, 2) if(length($msg) > 26);
my $confirm = 0;
$fhzHardwareBufferSpace = getFhzBuffer () if ($fhzHardwareBufferSpace == 0);
if(!defined($defptr{$dev})) {
Log 3, "FHT Unknown device $dev, please define it";
return "UNDEFINED FHT $dev";
}
my $def = $defptr{$dev};
# Unknown, but don't want report it. Should come with c409c401
if($cde eq "00") {
return "";
}
return "" if($cde eq "00");
if(length($cde) < 6) {
my $name = $def->{NAME};
@ -284,7 +387,18 @@ FHT_Parse($$)
# it looks like a real message, and let the rest parse it
Log 4, "FHT $def->{NAME} confirmation: $cde)";
$val = substr($cde, 2, 2);
# get the free hardware buffer space in the FHZ after each confirmation message
$fhzHardwareBufferSpace = hex substr($cde, 4, 2);
# increase $fhzHardwareBufferSpace at 5 because the confirmed command is deleted in the FHZ after confirmation
$fhzHardwareBufferSpace = $fhzHardwareBufferSpace + 5;
Log 4, "FHZ new FHT Buffer: $fhzHardwareBufferSpace";
$cde = substr($cde, 0, 2) . "0069";
# set help var to remember this is a confirmation
$confirm = 1;
}
my $type;
@ -303,7 +417,6 @@ FHT_Parse($$)
return $def->{NAME};
}
my $tn = TimeNow();
###########################
@ -348,13 +461,26 @@ FHT_Parse($$)
} elsif($type =~ m/.*-temp/) {
$val = sprintf("%.1f (Celsius)", $val / 2)
} elsif($type eq "state") {
} elsif($type eq "warnings") {
my $nval;
$nval = "Bat: " . (($val & 1) ? "empty" : "ok");
$nval .= ", Window: " . (($val & 32) ? "open" : "closed");
$nval .= ", Fault: " . (($val & 16) ? "yes" : "no");
$val = $nval;
my @nVal;
$nVal[0] = "Battery low" if ($val & 1);
$nVal[1] = "Window open" if ($val & 32);
$nVal[2] = "Fault on window sensor" if ($val & 16);
$nVal[3] = "Temperature to low" if ($val & 2);
if ($val > 0) {
$val = "";
foreach (@nVal) {
$val .= "$_; " if (defined($_));
}
$val = substr($val, 0, length($val)-2);
} else {
$val = "none";
}
} elsif($type eq "lowtemp-offset") {
$val = sprintf("%d.0 (Celsius)", $val)
} elsif($type =~ m/echo_/) { # Ignore these messages
return "";
@ -365,9 +491,192 @@ FHT_Parse($$)
$def->{READINGS}{$type}{VAL} = $val;
Log 4, "FHT $def->{NAME} ($type: $val)";
###########################################################################
# here starts the processing the confirmation to control the softwarebuffer
#
$attr{FHZ}{softbuffer} = 1 if (!defined($attr{FHZ}{softbuffer})); # set default values for config value attr FHZ softbuffer
my $sbCount = keys(%{$def->{SENDBUFFER}}); # count the existing sendbuffer
my $nsCount = keys(%{$def->{NOTSEND}}); # count the existing failbuffer
if ($confirm && ($sbCount > 0 || $nsCount > 0) && $attr{FHZ}{softbuffer} == 1) {
$type = "refreshvalues" if ($type eq "init");
my ($sbPr, $sbTs);
my $sbType = "";
my $sbVal;
my $dKey;
my ($val2) = split (/\s/, $val);
# if the confirmation message for a command recive to late
# (the command moved to the notsend list yet)
# found the specific command ond delete them from the notsend list
foreach my $c (sort keys %{$def->{NOTSEND}}) { # go through the notsend list
($sbPr, $sbTs, $sbType) = split (/:/, $c);
$sbVal = $def->{NOTSEND}->{$c}{VAL};
$dKey = $c;
$sbVal = $val2 if ($type eq "refreshvalues"); # refreshvalues have no value
if ($sbType eq $type && $sbVal eq $val2) {
Log GetLogLevel($def->{NAME},2), "FHT $def->{NAME} late - confirmation ".
"($sbType: $sbVal) (delete from NOTSEND)";
delete($def->{NOTSEND}{$dKey}); # delete command from notsend list
last; # we can leave the loop because the command was deleted from the list
}
}
# get the next entry from the buffer queue
foreach my $c (sort keys %{$def->{SENDBUFFER}}) {
($sbPr, $sbTs, $sbType) = split (/:/, $c);
$sbVal = $def->{SENDBUFFER}->{$c}{VAL};
$dKey = $c;
last; # exit foreach because we need the first entry only
}
$sbVal = $val2 if ($type eq "refreshvalues"); # refreshvalues have no value
# if the actual confirmation message part of the first command in the queue
if ($sbType eq $type && $sbVal eq $val2) {
delete($def->{SENDBUFFER}{$dKey}); # this buffer entry can deleted
foreach my $c (sort keys %{$def->{SENDBUFFER}}) { # get the next buffer entry
my $nType = $def->{SENDBUFFER}->{$c}{TYPE};
my $nArg = $def->{SENDBUFFER}->{$c}{ARG};
my $nName = $def->{SENDBUFFER}->{$c}{NAME};
my $nHash = $def->{SENDBUFFER}->{$c}{HASH};
my $nVal = $def->{SENDBUFFER}->{$c}{VAL};
my $nKey = $def->{SENDBUFFER}->{$c}{KEY};
sendCommand ($nHash, $nArg, $nName, $nType, $nVal); # nächsten Buffereintrag senden
toSendbuffer ($nHash, $nType, $nVal, $nArg, $nKey, 0); # send command also to buffer
last; # exit foreach because we need the next entry only
}
}
}
#
# end processing confirmation to control the softwarebuffer
###########################################################################
$def->{CHANGED}[0] = "$type: $val";
$def->{STATE} = "$type: $val" if($type eq "measured-temp");
return $def->{NAME};
}
# check are commands in softwarebuffer
# ans send the next command to the FHZ
sub timerCheckBuffer ($)
{
Log 4, "Timer (Checking for unsend FHT commands)";
my ($hash) = @_;
my $bufCount = 0; # help counter
my $now = gettimeofday();
my $ts = time;
# set default values for config value attr FHZ softbuffer
$attr{FHZ}{softrepeat} = 240 if (!defined($attr{FHZ}{softrepeat}));
$attr{FHZ}{softmaxretry} = 3 if (!defined($attr{FHZ}{softmaxretry}));
# loop to process all FHT devices
foreach my $d (keys %defptr) {
my $def = $defptr{$d}; # the actual FHT device
# process all buffer entries
foreach my $c (sort keys %{$def->{SENDBUFFER}}) {
my ($rPr, undef, $rType) = split (/:/, $c); # priority and type
my $rVal = $def->{SENDBUFFER}{$c}{VAL}; # value
my $rTs = $def->{SENDBUFFER}{$c}{SENDTIME}; # the time of the sending moment to the FHT
my $rRetry = $def->{SENDBUFFER}{$c}{RETRY}; # retry counter
$rRetry ++ if ($fhzHardwareBufferSpace > $minFhzHardwareBufferSpace); # increase retrycounter if enough hardwarebuffer available
my $rKey = $c; # the bufferkey
$rVal = "" if (!defined($rVal)); # set value to "" if value not defined (e.g. "refreshvalues" have no value)
$bufCount ++; # increase $bufCount
my $buffer = $def->{SENDBUFFER}{$c}; # actual buffer entry
# if the forst command in buffer to old, resend them again to the FHZ
if ($ts-$rTs > $attr{FHZ}{softrepeat}) {
if ($rRetry <= $attr{FHZ}{softmaxretry}) { # resend the command only if the max resend amount not reached
resendCommand ($buffer); # resend the actual command
} else {
# command resend fail after "softmaxretry" attempt to send
Log GetLogLevel($def->{NAME},2), $def->{NAME} . " $rType $rVal no confirmation after $rRetry retry";
$def->{NOTSEND}{$rKey} = $def->{SENDBUFFER}{$rKey}; # put the buffer entry to the notsend list
$def->{NOTSEND}{$rKey}{RETRY} = $rRetry;
delete($def->{SENDBUFFER}{$rKey}); # delete command from buffer queue
}
}
last # exit foreach because we need only the first buffer value
}
}
if ($bufCount > 0) {
Log 4, "Refresh FHT resend timer";
InternalTimer(gettimeofday()+70, "timerCheckBuffer", $hash); # restart the internal Timer if any buffer contains commands
} else {
$timerCheckBufferIsRunning = 0; # remember timer is not running anymore
}
}
# set given command tothe internal software buffer
# each command queued until the previous command become a confirmation
#
sub toSendbuffer ($$$$)
{
my ($hash, $type, $val, $arg, $nBufferKey, $retry) = @_;
if (!$init_done || $attr{FHZ}{softbuffer} == 0) {
return
}
my $dev = $hash->{CODE};
my $def = $defptr{$dev};
my $tn = TimeNow(); # Readable time
my $ts = time; # Unix timestamp
my $pr = 9; # Default priority for command
my $sendTime = 0; # Timestamp for last sending command
my $sbCount = keys(%{$def->{SENDBUFFER}}); # Count of sendbuffer
$pr = $priority{$type} if (defined($priority{$type})); # get priority for specific command type
$val = "" if (!defined($val));
if ($sbCount == 0) {
$pr = 0; # First command in buffer have always priority 0 (highest)
$sendTime = $ts;
}
my $bufferKey = "$pr:$ts:$type"; #Default bufferkey
# if bufferkey existing. delete the entry and save the entry with a new buffer
if ($nBufferKey ne "") {
$sendTime = $ts;
$bufferKey = $nBufferKey;
($pr, $ts, $type) = split (/:/, $bufferKey);
delete($def->{SENDBUFFER}{$bufferKey}); # delete "old" bufferentry
$bufferKey = "0:$ts:$type"; # new bufferkey für new bufferentry
}
$def->{SENDBUFFER}{$bufferKey}{TIME} = $tn;
$def->{SENDBUFFER}{$bufferKey}{VAL} = $val;
$def->{SENDBUFFER}{$bufferKey}{NAME} = $def->{NAME};
$def->{SENDBUFFER}{$bufferKey}{TYPE} = $type;
$def->{SENDBUFFER}{$bufferKey}{ARG} = $arg;
$def->{SENDBUFFER}{$bufferKey}{SENDTIME} = $sendTime;
$def->{SENDBUFFER}{$bufferKey}{RETRY} = $retry;
$def->{SENDBUFFER}{$bufferKey}{KEY} = $bufferKey;
$def->{SENDBUFFER}{$bufferKey}{HASH} = $hash;
}
1;

View File

@ -147,3 +147,13 @@
- weblinks added. Used by webpgm2 to display more than one plot at once
- webpgm2 output reformatted. Using CSS to divide the screen area in 3
parts: command line, room-list and rest
- Dirk Wed Oct 7 12:45:09 MEST 2007
- FHT lime-protection code discovered
- Dirk Wed Oct 18 23:28:00 MEST 2007
- Softwarebuffer for FHT devices with queuing unsent commands and
repeating commands by transmission failure
- FHT low temperatur warning and setting for lowtemp-offset
- Change naming for state into warnings
Tagged as dirkh_20071019_0

File diff suppressed because it is too large Load Diff

View File

@ -1,255 +1,261 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Home of FHEM</title>
</head>
<body style="background-color: white">
<h1>FHEM</h1>
GPL'd server to access devices like FHZ1000/FHZ1300,EM1010PC,WS300,SCIVT.
Formerly known as fhz1000.pl
<h2>News (as of =DATE=, Version =VERS=)</h2>
<ul>
<li> doc: linux.html (private udev-rules, not 50-..., ATTRS)
<li> bugfix: setting devices with "-" in their name did not work
<li> doc: fhem.pl and commandref.html (notifyon -> notify, correction
of examples)
<li> feature: modify command added
<li> feature: The "-" in the name is not allowed any more
<li> bugfix: disabled notify causes "uninitialized value" (STefan, 1.5)
<li> bugfix: deleted FS20 items are still logging (zombie) (Gerhard, 16.5)
<li> bugfix: added FS20S8, removed stty_parmrk (Martin, 24.5)
<li> feature: added archivedir/archivecmd to the FileLog
<li> feature: added EM1010PC/EM1000WZ/EM1000EM support
<li> bugfix: undefined messages for unknown HMS devs (Peter, 8.6)
<li> bugfix: em1010 and %oldvalue bugs (Peter, 9.6)
<li> bugfix: SCIVT solar controller (peterp, 1.7)
<li> bugfix: WS300 loglevel change (from 2 to 5 or device specific loglevel)
<li> feature: First steps for a Fritz!Box port. See the fritzbox.html
</ul>
</ul>
<h2>Description</h2>
<ul>
This program makes the FHZ1000/FHZ1300/WS300 USB devices sold by ELV, Conrad and
others useable with Linux. In fact, there is nothing Linux special in it, you
should be able to use it on other platforms as long as you can access the
hardware as a serial device.<br>
The program runs as a server, you can control it via telnet, command line
program or TCP/IP directly, like the supplied web frontends do.<br> <br>
Currently implemented features:<br>
<ul>
<li>Via the FHZ module (with access to one or more FHZ1000/FHZ1300 device):
<ul>
<li>reading and sending FS20 events (on/off/dimming, timer commands)<br>
<li>support of FS20 address features function group, local and global master
<li>reading and changing FHT80b parameters (temp, actuator, etc).<br>
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.</li>
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)</li>
<li>reading KS300 data</li>
</ul>
</li>
<li>reading WS300 data, and up to 9 attached devices</li>
<li>reading EM1000WZ/EM1000EM data via an attached EM1010PC</li>
<li>reading an attached SCIVT device</li>
<li>logging events to files (or database), with regexp filters</li>
<li>notifying external programs or internal modules when receiving certain
events</li>
<li>timed commands (e.g. switching a lamp on from sunset till midnight)</li>
<li>modular architecture</li>
<li>a lot of web frontends, choose your favorite</li>
<br>
</ul>
See <a href="commandref.html">commandref.html</a> for a detailed command
description and <a href="faq.html">faq.html</a> for the F.A.Q.
</ul>
<h2>Links:</h2>
<ul>
Homepage: <a href="http://www.koeniglich.de/fhem/fhem.html">
http://www.koeniglich.de/fhem/fhem.html</a><br>
Download: <a href="http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz">
http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz</a><br>
FAQ: <a href="http://www.koeniglich.de/fhem/faq.html">
http://www.koeniglich.de/fhem/faq.html</a><br>
Google-Group: <a href="http://groups.google.com/group/FHZ1000-users-on-unix">
http://groups.google.com/group/FHZ1000-users-on-unix</a><br>
Martins Web frontend (webpgm3): <a href="http://www.martin-haas.de/fhz">
http://www.martin-haas.de/fhz</a><br>
CVS@berlios: <a href="http://developer.berlios.de/projects/fhem">
http://developer.berlios.de/projects/fhem</a><br>
LinViex (home automation frontend):
<a href="http://sourceforge.net/projects/linviex">
http://sourceforge.net/projects/linviex</a><br><br>
Device/OS Specific installation guides:<br>
<ul>
Linux driver installation:
<a href="http://www.koeniglich.de/fhem/linux.html">
http://www.koeniglich.de/fhem/linux.html</a><br>
Instructions for Nas/Routers (NSLU2):
<a href="http://www.martin-haas.de/fhz/nslu2fhz">
http://www.martin-haas.de/fhz/nslu2fhz</a><br>
Instructions for the Fritz!Box:
<a href="fritzbox.html">
http://www.koeniglich.de/fhem/fritzbox.html</a><br>
Instructions for the Allnet all6250:
<a href="http://wiki.dungeon.de/all6250_opennas_mit_fhem">
http://wiki.dungeon.de/all6250_opennas_mit_fhem</a><br>
</ul>
</ul>
<h2>Related projects:</h2>
<ul>
<a href="http://fhz4linux.info/">http://fhz4linux.info/</a><br>
</ul>
<h2>Installation</h2>
<ul>
<h3>Linux driver</h3>
See <a href="http://www.koeniglich.de/fhem/linux.html">
http://www.koeniglich.de/fhem/linux.html</a><br>
For kernels older then 2.6.x apply the patch from the doc directory to your
kernel, recompile it and reboot or load/reload the ftdi_sio module.
</ul>
<h3>Perl modules</h3>
<ul>
You need perl with the Device::SerialPort (<a
href="http://search.cpan.org/dist/Device-SerialPort/">
http://search.cpan.org/dist/Device-SerialPort/</a>)
module. All other needed modules were present in my installation.
If this module reports <code>Can't call method "opened" on an undefined
value...</code> when starting the server, then you either may ignore
this message, or replace the mentioned line with:<pre>
$self->{HANDLE}->close if (defined($self->{HANDLE}) &&
$self->{HANDLE}->opened);</pre>
</ul>
<h3>Server installation</h3>
<ul>
<li>Copy the file <code>fhem.pl</code> into your path (e.g.
<code>/usr/local/bin</code>), and the FHEM directory e.g. to
<code>/usr/local/lib</code>. </li>
<li>Make sure that you can access the serial USB
device (e.g. <code>/dev/tts/USB0</code>).</li>
<li>Create a configuration file (see the examples directory and
docs/commandref.html), and change at least the modpath
(<code>/usr/local/lib</code>) and define FHZ FHZ (<code>/dev/tts/USB0</code>)
parameters.</li>
<li>Delete the savefile if you are upgrading from an older version.</li>
<li>Start the server with <code>fhem.pl &lt;configfile&gt;</code></li>
</ul>
<h3>General Notes for Webfrontends:</h3>
<ul>
<li>You don't have to install all of them, one is probably more than
enough :-)</li>
<li>The web server and the fhem server must be on the same host</li>
<li><b>Important:</b> Make sure you add some protection (.htaccess, etc)
else everybody will be able to set your devices</li>
</ul>
<h3>Web frontend 2 (webfrontend/pgm2, the simple one)</h3>
<ul>
This frontend is CGI/CSS based. It has support for rooms, and FHT/KS300 logs.<br>
Screenshots: <a href="pgm2-1.gif">overview</a>, <a href="pgm2-2.gif">details
</a> and KS300 temperature <a href="pgm2-3.gif">logs</a><br><br>
<ul>
<li>Copy the file fhemweb.pl and *.gplot to your cgi-bin directory
(/home/httpd/cgi-bin), the icons (*.gif) to your httpd icons
(/home/httpd/icons), and commandref.html to the html directory
(/home/httpd/html).<br>
Note: The program looks for icons in the following order:
&lt;device-name&gt;.&lt;state&gt;, &lt;device-name&gt;,
&lt;device-type&gt;.&lt;state&gt;, &lt;device-type&gt;<br>
</li>
<li>Edit <code>fhemweb.pl</code>, and check the "Config" section.</li>
<li>If you want to have access to plotted logs, then make sure that
gnuplot is installed and set the logtype for the FileLog device
(see commandref.html and example/04_log).
</li>
<li>Call &lt;your-site&gt;/cgi-bin/fhemweb.pl
</ul>
For special features like assigning devices to rooms see the README file.
</ul>
<h3>Web frontend 3 (webfrontend/pgm3, the professional one)</h3>
<ul>
This frontend is PHP based and was contributed by Martin Haas.
Look at the webfrontends/pgm3/docs for more documentation or at
<a href="pgm3-0.5.1.png">this screenshot</a>. A lot more details can be
found on Martins page: <a href="http://www.martin-haas.de/fhz">
http://www.martin-haas.de/fhz</a>
<br><br>
<ul>
<li>Install PHP and enable it by commenting in the "LoadModule
phpX_module ..." directive in httpd.conf (perhaps it is already
done by your distro). Restart/reload httpd.</li>
<li>Create a directory (e.g.: /home/httpd/html/pgm3) and copy all the
files from the webfrontend/pgm3 to this directory.<br>Make sure that this
directory is writeable by the webserver!</li>
<li>Edit index.php (/home/httpd/html/pgm3/index.php), and check the
required settings section</li>
<li>If you want to have access to the FHT temperature logs, then:
<ul>
<li>Make sure gnuplot is installed</li>
<li>check the showgnuplot section in index.php</li>
<li>For each FHT device copy the file docs/gnuplot/gnuplot.wz to
gnuplot.fhtdevicename (to the /home/httpd/html/pgm3 directory) and
replace fht.log in this file with the absolute name of the current
logfile.</li>
</ul>
<li>Call &lt;your-site&gt;/pgm3/index.php</li>
</ul>
</ul>
<h3>Web frontend 4 (webfrontend/pgm4, the template)</h3>
<ul>
This frontend is PHP based and was contributed by Stefan Mayer. It won't work
for you without modification, it is meant as a template or as an example. See
the <a href="pgm4.gif">screenshot</a>. To install:
<ul>
<li>Copy the directory webfrontend/pgm4 to your html directory.</li>
<li>Install/enable PHP (see the description for frontend3)</li>
<li>Call the program with http://webserver/pgm4/fs20.php</li>
</ul>
Now you can go on, and modify it to suit your needs :-)
</ul>
</ul>
<h2>License:</h2>
<ul>
Copyright:<br>
<ul>
<li>Rudolf Koenig (r dot koenig at koeniglich dot de)</li>
<li>Raoul Matthiessen (webfrontends/pgm1)</li>
<li>Martin Haas (webfrontends/pgm3)</li>
</ul>
License: GPL (v2)
</ul>
</ul>
<h2>Misc:</h2>
<ul>
Thanks for Tosti for inspiration and numerous other people for help. <br>
</ul>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Home of FHEM</title>
</head>
<body style="background-color: white">
<h1>FHEM</h1>
GPL'd server to access devices like FHZ1000/FHZ1300,EM1010PC,WS300,SCIVT.
Formerly known as fhz1000.pl
<h2>News (as of =DATE=, Version =VERS=)</h2>
<ul>
<li> doc: linux.html (private udev-rules, not 50-..., ATTRS)
<li> bugfix: setting devices with "-" in their name did not work
<li> doc: fhem.pl and commandref.html (notifyon -> notify, correction
of examples)
<li> feature: modify command added
<li> feature: The "-" in the name is not allowed any more
<li> bugfix: disabled notify causes "uninitialized value" (STefan, 1.5)
<li> bugfix: deleted FS20 items are still logging (zombie) (Gerhard, 16.5)
<li> bugfix: added FS20S8, removed stty_parmrk (Martin, 24.5)
<li> feature: added archivedir/archivecmd to the FileLog
<li> feature: added EM1010PC/EM1000WZ/EM1000EM support
<li> bugfix: undefined messages for unknown HMS devs (Peter, 8.6)
<li> bugfix: em1010 and %oldvalue bugs (Peter, 9.6)
<li> bugfix: SCIVT solar controller (peterp, 1.7)
<li> bugfix: WS300 loglevel change (from 2 to 5 or device specific loglevel)
<li> feature: First steps for a Fritz!Box port. See the fritzbox.html
<li>feature: FHT lime-protection code discovered by Dirk (7.10)
<li>feature: Softwarebuffer for FHT devices with queuing unsent commands and repeating commands by transmission failure (Dirk 17.10)
<li> feature: FHT low temperatur warning and setting for lowtemp-offset (Dirk 17.10)
<li>change: Change naming for state into warnings (Dirk 17.10)
</ul>
</ul>
<h2>Description</h2>
<ul>
This program makes the FHZ1000/FHZ1300/WS300 USB devices sold by ELV, Conrad and
others useable with Linux. In fact, there is nothing Linux special in it, you
should be able to use it on other platforms as long as you can access the
hardware as a serial device.<br>
The program runs as a server, you can control it via telnet, command line
program or TCP/IP directly, like the supplied web frontends do.<br> <br>
Currently implemented features:<br>
<ul>
<li>Via the FHZ module (with access to one or more FHZ1000/FHZ1300 device):
<ul>
<li>reading and sending FS20 events (on/off/dimming, timer commands)<br>
<li>support of FS20 address features function group, local and global master
<li>reading and changing FHT80b parameters (temp, actuator, etc).<br>
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.<br />
For FHT8b devices, FHEM have an internal software buffer for sending commands step by step. This buffer should prevent lost commands. In case of transmission failures FHEM tries to resend commands. <br />
</li>
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)</li>
<li>reading KS300 data</li>
</ul>
</li>
<li>reading WS300 data, and up to 9 attached devices</li>
<li>reading EM1000WZ/EM1000EM data via an attached EM1010PC</li>
<li>reading an attached SCIVT device</li>
<li>logging events to files (or database), with regexp filters</li>
<li>notifying external programs or internal modules when receiving certain
events</li>
<li>timed commands (e.g. switching a lamp on from sunset till midnight)</li>
<li>modular architecture</li>
<li>a lot of web frontends, choose your favorite</li>
<br>
</ul>
See <a href="commandref.html">commandref.html</a> for a detailed command
description and <a href="faq.html">faq.html</a> for the F.A.Q.
</ul>
<h2>Links:</h2>
<ul>
Homepage: <a href="http://www.koeniglich.de/fhem/fhem.html">
http://www.koeniglich.de/fhem/fhem.html</a><br>
Download: <a href="http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz">
http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz</a><br>
FAQ: <a href="http://www.koeniglich.de/fhem/faq.html">
http://www.koeniglich.de/fhem/faq.html</a><br>
Google-Group: <a href="http://groups.google.com/group/FHZ1000-users-on-unix">
http://groups.google.com/group/FHZ1000-users-on-unix</a><br>
Martins Web frontend (webpgm3): <a href="http://www.martin-haas.de/fhz">
http://www.martin-haas.de/fhz</a><br>
CVS@berlios: <a href="http://developer.berlios.de/projects/fhem">
http://developer.berlios.de/projects/fhem</a><br>
LinViex (home automation frontend):
<a href="http://sourceforge.net/projects/linviex">
http://sourceforge.net/projects/linviex</a><br><br>
Device/OS Specific installation guides:<br>
<ul>
Linux driver installation:
<a href="http://www.koeniglich.de/fhem/linux.html">
http://www.koeniglich.de/fhem/linux.html</a><br>
Instructions for Nas/Routers (NSLU2):
<a href="http://www.martin-haas.de/fhz/nslu2fhz">
http://www.martin-haas.de/fhz/nslu2fhz</a><br>
Instructions for the Fritz!Box:
<a href="fritzbox.html">
http://www.koeniglich.de/fhem/fritzbox.html</a><br>
Instructions for the Allnet all6250:
<a href="http://wiki.dungeon.de/all6250_opennas_mit_fhem">
http://wiki.dungeon.de/all6250_opennas_mit_fhem</a><br>
</ul>
</ul>
<h2>Related projects:</h2>
<ul>
<a href="http://fhz4linux.info/">http://fhz4linux.info/</a><br>
</ul>
<h2>Installation</h2>
<ul>
<h3>Linux driver</h3>
See <a href="http://www.koeniglich.de/fhem/linux.html">
http://www.koeniglich.de/fhem/linux.html</a><br>
For kernels older then 2.6.x apply the patch from the doc directory to your
kernel, recompile it and reboot or load/reload the ftdi_sio module.
</ul>
<h3>Perl modules</h3>
<ul>
You need perl with the Device::SerialPort (<a
href="http://search.cpan.org/dist/Device-SerialPort/">
http://search.cpan.org/dist/Device-SerialPort/</a>)
module. All other needed modules were present in my installation.
If this module reports <code>Can't call method "opened" on an undefined
value...</code> when starting the server, then you either may ignore
this message, or replace the mentioned line with:<pre>
$self->{HANDLE}->close if (defined($self->{HANDLE}) &&
$self->{HANDLE}->opened);</pre>
</ul>
<h3>Server installation</h3>
<ul>
<li>Copy the file <code>fhem.pl</code> into your path (e.g.
<code>/usr/local/bin</code>), and the FHEM directory e.g. to
<code>/usr/local/lib</code>. </li>
<li>Make sure that you can access the serial USB
device (e.g. <code>/dev/tts/USB0</code>).</li>
<li>Create a configuration file (see the examples directory and
docs/commandref.html), and change at least the modpath
(<code>/usr/local/lib</code>) and define FHZ FHZ (<code>/dev/tts/USB0</code>)
parameters.</li>
<li>Delete the savefile if you are upgrading from an older version.</li>
<li>Start the server with <code>fhem.pl &lt;configfile&gt;</code></li>
</ul>
<h3>General Notes for Webfrontends:</h3>
<ul>
<li>You don't have to install all of them, one is probably more than
enough :-)</li>
<li>The web server and the fhem server must be on the same host</li>
<li><b>Important:</b> Make sure you add some protection (.htaccess, etc)
else everybody will be able to set your devices</li>
</ul>
<h3>Web frontend 2 (webfrontend/pgm2, the simple one)</h3>
<ul>
This frontend is CGI/CSS based. It has support for rooms, and FHT/KS300 logs.<br>
Screenshots: <a href="pgm2-1.gif">overview</a>, <a href="pgm2-2.gif">details
</a> and KS300 temperature <a href="pgm2-3.gif">logs</a><br><br>
<ul>
<li>Copy the file fhemweb.pl and *.gplot to your cgi-bin directory
(/home/httpd/cgi-bin), the icons (*.gif) to your httpd icons
(/home/httpd/icons), and commandref.html to the html directory
(/home/httpd/html).<br>
Note: The program looks for icons in the following order:
&lt;device-name&gt;.&lt;state&gt;, &lt;device-name&gt;,
&lt;device-type&gt;.&lt;state&gt;, &lt;device-type&gt;<br>
</li>
<li>Edit <code>fhemweb.pl</code>, and check the "Config" section.</li>
<li>If you want to have access to plotted logs, then make sure that
gnuplot is installed and set the logtype for the FileLog device
(see commandref.html and example/04_log).
</li>
<li>Call &lt;your-site&gt;/cgi-bin/fhemweb.pl
</ul>
For special features like assigning devices to rooms see the README file.
</ul>
<h3>Web frontend 3 (webfrontend/pgm3, the professional one)</h3>
<ul>
This frontend is PHP based and was contributed by Martin Haas.
Look at the webfrontends/pgm3/docs for more documentation or at
<a href="pgm3-0.5.1.png">this screenshot</a>. A lot more details can be
found on Martins page: <a href="http://www.martin-haas.de/fhz">
http://www.martin-haas.de/fhz</a>
<br><br>
<ul>
<li>Install PHP and enable it by commenting in the "LoadModule
phpX_module ..." directive in httpd.conf (perhaps it is already
done by your distro). Restart/reload httpd.</li>
<li>Create a directory (e.g.: /home/httpd/html/pgm3) and copy all the
files from the webfrontend/pgm3 to this directory.<br>Make sure that this
directory is writeable by the webserver!</li>
<li>Edit index.php (/home/httpd/html/pgm3/index.php), and check the
required settings section</li>
<li>If you want to have access to the FHT temperature logs, then:
<ul>
<li>Make sure gnuplot is installed</li>
<li>check the showgnuplot section in index.php</li>
<li>For each FHT device copy the file docs/gnuplot/gnuplot.wz to
gnuplot.fhtdevicename (to the /home/httpd/html/pgm3 directory) and
replace fht.log in this file with the absolute name of the current
logfile.</li>
</ul>
<li>Call &lt;your-site&gt;/pgm3/index.php</li>
</ul>
</ul>
<h3>Web frontend 4 (webfrontend/pgm4, the template)</h3>
<ul>
This frontend is PHP based and was contributed by Stefan Mayer. It won't work
for you without modification, it is meant as a template or as an example. See
the <a href="pgm4.gif">screenshot</a>. To install:
<ul>
<li>Copy the directory webfrontend/pgm4 to your html directory.</li>
<li>Install/enable PHP (see the description for frontend3)</li>
<li>Call the program with http://webserver/pgm4/fs20.php</li>
</ul>
Now you can go on, and modify it to suit your needs :-)
</ul>
</ul>
<h2>License:</h2>
<ul>
Copyright:<br>
<ul>
<li>Rudolf Koenig (r dot koenig at koeniglich dot de)</li>
<li>Raoul Matthiessen (webfrontends/pgm1)</li>
<li>Martin Haas (webfrontends/pgm3)</li>
</ul>
License: GPL (v2)
</ul>
</ul>
<h2>Misc:</h2>
<ul>
Thanks for Tosti for inspiration and numerous other people for help. <br>
</ul>
</body>
</html>

View File

@ -134,7 +134,7 @@ my %intAt; # Internal at timer hash.
my $intAtCnt=0;
my $reread_active = 0;
my $AttrList = "room comment";
my $cvsid = '$Id: fhem.pl,v 1.26 2007-09-24 07:09:17 rudolfkoenig Exp $';
my $cvsid = '$Id: fhem.pl,v 1.27 2007-10-19 09:29:00 dirkh Exp $';
$init_done = 0;
@ -1044,10 +1044,58 @@ CommandList($$)
if($r) {
$str .= "Readings:\n";
foreach my $c (sort keys %{$r}) {
$str .= sprintf(" %-19s %-15s %s\n",$r->{$c}{TIME},$c,$r->{$c}{VAL});
my $val = "";
if (defined($r->{$c}{VAL})) {
$val = $r->{$c}{VAL};
}
$str .= sprintf(" %-19s %-15s %s\n",$r->{$c}{TIME},$c,$val);
}
}
$attr{FHZ}{softbuffer} = 1 if (!defined($attr{FHZ}{softbuffer}));
if ($attr{FHZ}{softbuffer} == 1) {
my %lists = (
"SENDBUFFER" => "Send buffer",
"NOTSEND" => "Send fail list",
);
foreach my $list (keys %lists) {
my $l = $d->{$list};
if(keys (%{$l}) > 0) {
$str .= $lists{$list} .":\n";
foreach my $c (sort keys %{$l}) {
my (undef, undef, $vC) = split (/:/, $c);
# $str .= sprintf(" %-19s %-15s %-10s %s\n",$l->{$c}{TIME},$c,$l->{$c}{VAL},$l->{$c}{SENDTIME});
$str .= sprintf(" %-19s %-15s %s\n",$l->{$c}{TIME},$vC,$l->{$c}{VAL});
}
}
if ($defs{$param}->{NAME} eq "FHZ") {
$str .= $lists{$list} .":\n";
foreach my $d (sort keys %defs) {
my $p = $defs{$d};
my $t = $p->{TYPE};
if ($t eq "FHT") {
$l = $p->{$list};
if(keys (%{$l}) > 0) {
foreach my $c (sort keys %{$l}) {
my (undef, undef, $vC) = split (/:/, $c);
my $val = "";
if (defined($l->{$c}{VAL})) {
$val = $l->{$c}{VAL};
}
$str .= sprintf(" %-19s %-15s %-15s %s\n",$l->{$c}{TIME},$p->{NAME},$vC,$val);
}
}
}
}
}
}
}
}
return $str;