mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +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:
parent
72b261d6aa
commit
04a95a803f
@ -348,3 +348,6 @@
|
|||||||
- feature: webpgm2 output reformatted
|
- feature: webpgm2 output reformatted
|
||||||
- feature: webpgm2 can display multiple plots.
|
- feature: webpgm2 can display multiple plots.
|
||||||
- feature: FHT lime-protection code discovered by Dirk (7.10)
|
- 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)
|
@ -68,7 +68,7 @@ FHZ_Initialize($)
|
|||||||
$hash->{SetFn} = "FHZ_Set";
|
$hash->{SetFn} = "FHZ_Set";
|
||||||
$hash->{StateFn} = "FHZ_SetState";
|
$hash->{StateFn} = "FHZ_SetState";
|
||||||
$hash->{ParseFn} = "FHZ_Parse";
|
$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";
|
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
|
sub
|
||||||
FHZ_SetState($$$$)
|
FHZ_SetState($$$$)
|
||||||
@ -346,7 +364,8 @@ FHZ_ReadAnswer($$)
|
|||||||
|
|
||||||
my $buf = $hash->{PortObj}->input();
|
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;
|
$mfhzdata .= $buf;
|
||||||
next if(length($mfhzdata) < 2);
|
next if(length($mfhzdata) < 2);
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ my %codes = (
|
|||||||
"XX0069" => "measured-temp", # sum of next. two, never "really" sent
|
"XX0069" => "measured-temp", # sum of next. two, never "really" sent
|
||||||
"420069" => "measured-low",
|
"420069" => "measured-low",
|
||||||
"430069" => "measured-high",
|
"430069" => "measured-high",
|
||||||
"440069" => "state",
|
"440069" => "warnings",
|
||||||
|
"450069" => "manu-temp", # Manuelle Temperatur keine ahnung was das bewirkt
|
||||||
"600069" => "year",
|
"600069" => "year",
|
||||||
"610069" => "month",
|
"610069" => "month",
|
||||||
"620069" => "day",
|
"620069" => "day",
|
||||||
@ -59,10 +60,9 @@ my %codes = (
|
|||||||
"650069" => "init",
|
"650069" => "init",
|
||||||
"820069" => "day-temp",
|
"820069" => "day-temp",
|
||||||
"840069" => "night-temp",
|
"840069" => "night-temp",
|
||||||
"850069" => "unknown_85",
|
"850069" => "lowtemp-offset", # Alarm-Temp.-Differenz
|
||||||
"8a0069" => "windowopen-temp",
|
"8a0069" => "windowopen-temp",
|
||||||
"00002a" => "lime-protection",
|
"00002a" => "lime-protection",
|
||||||
|
|
||||||
"0000aa" => "code_0000aa",
|
"0000aa" => "code_0000aa",
|
||||||
"0000ba" => "code_0000ba",
|
"0000ba" => "code_0000ba",
|
||||||
"430079" => "code_430079",
|
"430079" => "code_430079",
|
||||||
@ -86,7 +86,7 @@ my %cantset = (
|
|||||||
"measured-temp" => 1,
|
"measured-temp" => 1,
|
||||||
"measured-high" => 1,
|
"measured-high" => 1,
|
||||||
"measured-low" => 1,
|
"measured-low" => 1,
|
||||||
"state" => 1,
|
"warnings" => 1,
|
||||||
"init" => 1,
|
"init" => 1,
|
||||||
"lime-protection"=>1,
|
"lime-protection"=>1,
|
||||||
|
|
||||||
@ -104,12 +104,25 @@ my %nosetarg = (
|
|||||||
"refreshvalues" => 1,
|
"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 %c2m = (0 => "auto", 1 => "manual", 2 => "holiday", 3 => "holiday_short");
|
||||||
my %m2c; # Reverse c2m
|
my %m2c; # Reverse c2m
|
||||||
my %c2b; # command->button hash (reverse of codes)
|
my %c2b; # command->button hash (reverse of codes)
|
||||||
my %c2bset; # Setteable values
|
my %c2bset; # Setteable values
|
||||||
my %defptr;
|
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
|
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";
|
$hash->{AttrList} = "do_not_notify:0,1 model;fht80b dummy:0,1 showtime:0,1 loglevel:0,1,2,3,4,5,6";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Parse the incomming commands and send them via sendCommand to the FHZ
|
||||||
#####################################
|
# or via toSendbuffer in the Softwarebuffer (queue)
|
||||||
sub
|
#
|
||||||
FHT_Set($@)
|
sub FHT_Set($@)
|
||||||
{
|
{
|
||||||
my ($hash, @a) = @_;
|
my ($hash, @a) = @_;
|
||||||
my $ret = undef;
|
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 "\"set $a[0]\" needs two parameters" if(@a < 2);
|
||||||
return "Unknown argument $a[1], choose one of " .
|
return "Unknown argument $a[1], choose one of " .
|
||||||
join(" ", sort {$c2bset{$a} cmp $c2bset{$b} } keys %c2bset)
|
join(" ", sort {$c2bset{$a} cmp $c2bset{$b} } keys %c2bset)
|
||||||
if(!defined($c2bset{$a[1]}));
|
if(!defined($c2bset{$a[1]}));
|
||||||
return "\"set $a[0]\" needs two parameters"
|
return "\"set $a[0]\" needs two parameters"
|
||||||
if(@a != 3 && !(@a == 2 && $nosetarg{$a[1]}));
|
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[1] eq "refreshvalues") {
|
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
|
# This is special. Without the sleep the next FHT won't send its data
|
||||||
if(!IsDummy($a[0])) {
|
if(!IsDummy($name)) {
|
||||||
my $havefhz;
|
my $havefhz;
|
||||||
$havefhz = 1 if($hash->{IODev} && defined($hash->{IODev}->{FD}));
|
$havefhz = 1 if($hash->{IODev} && defined($hash->{IODev}->{FD}));
|
||||||
|
|
||||||
@ -174,36 +273,40 @@ FHT_Set($@)
|
|||||||
IOWrite($hash, "04", "c90185"); # Check the fht buffer
|
IOWrite($hash, "04", "c90185"); # Check the fht buffer
|
||||||
sleep(1) if($havefhz);
|
sleep(1) if($havefhz);
|
||||||
}
|
}
|
||||||
return $ret;
|
} else {
|
||||||
|
IOWrite($hash, "04", $arg) if(!IsDummy($name));
|
||||||
} 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]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IOWrite($hash, "04", $arg) if(!IsDummy($a[0]));
|
Log GetLogLevel($name,2), "FHT set $name $type $val";
|
||||||
return $ret;
|
|
||||||
|
# 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
|
sub
|
||||||
FHT_SetState($$$$)
|
FHT_SetState($$$$)
|
||||||
@ -249,27 +352,27 @@ FHT_Undef($$)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub
|
sub
|
||||||
FHT_Parse($$)
|
FHT_Parse($$)
|
||||||
{
|
{
|
||||||
my ($hash,$msg) = @_;
|
my ($hash, $msg) = @_;
|
||||||
|
|
||||||
my $dev = substr($msg, 16, 4);
|
my $dev = substr($msg, 16, 4);
|
||||||
my $cde = substr($msg, 20, 6);
|
my $cde = substr($msg, 20, 6);
|
||||||
my $val = substr($msg, 26, 2) if(length($msg) > 26);
|
my $val = substr($msg, 26, 2) if(length($msg) > 26);
|
||||||
|
my $confirm = 0;
|
||||||
|
|
||||||
|
$fhzHardwareBufferSpace = getFhzBuffer () if ($fhzHardwareBufferSpace == 0);
|
||||||
|
|
||||||
if(!defined($defptr{$dev})) {
|
if(!defined($defptr{$dev})) {
|
||||||
Log 3, "FHT Unknown device $dev, please define it";
|
Log 3, "FHT Unknown device $dev, please define it";
|
||||||
return "UNDEFINED FHT $dev";
|
return "UNDEFINED FHT $dev";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my $def = $defptr{$dev};
|
my $def = $defptr{$dev};
|
||||||
|
|
||||||
# Unknown, but don't want report it. Should come with c409c401
|
# Unknown, but don't want report it. Should come with c409c401
|
||||||
if($cde eq "00") {
|
return "" if($cde eq "00");
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(length($cde) < 6) {
|
if(length($cde) < 6) {
|
||||||
my $name = $def->{NAME};
|
my $name = $def->{NAME};
|
||||||
@ -284,7 +387,18 @@ FHT_Parse($$)
|
|||||||
# it looks like a real message, and let the rest parse it
|
# it looks like a real message, and let the rest parse it
|
||||||
Log 4, "FHT $def->{NAME} confirmation: $cde)";
|
Log 4, "FHT $def->{NAME} confirmation: $cde)";
|
||||||
$val = substr($cde, 2, 2);
|
$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";
|
$cde = substr($cde, 0, 2) . "0069";
|
||||||
|
|
||||||
|
# set help var to remember this is a confirmation
|
||||||
|
$confirm = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $type;
|
my $type;
|
||||||
@ -303,7 +417,6 @@ FHT_Parse($$)
|
|||||||
return $def->{NAME};
|
return $def->{NAME};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my $tn = TimeNow();
|
my $tn = TimeNow();
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
@ -348,13 +461,26 @@ FHT_Parse($$)
|
|||||||
} elsif($type =~ m/.*-temp/) {
|
} elsif($type =~ m/.*-temp/) {
|
||||||
$val = sprintf("%.1f (Celsius)", $val / 2)
|
$val = sprintf("%.1f (Celsius)", $val / 2)
|
||||||
|
|
||||||
} elsif($type eq "state") {
|
} elsif($type eq "warnings") {
|
||||||
|
|
||||||
my $nval;
|
my @nVal;
|
||||||
$nval = "Bat: " . (($val & 1) ? "empty" : "ok");
|
$nVal[0] = "Battery low" if ($val & 1);
|
||||||
$nval .= ", Window: " . (($val & 32) ? "open" : "closed");
|
$nVal[1] = "Window open" if ($val & 32);
|
||||||
$nval .= ", Fault: " . (($val & 16) ? "yes" : "no");
|
$nVal[2] = "Fault on window sensor" if ($val & 16);
|
||||||
$val = $nval;
|
$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
|
} elsif($type =~ m/echo_/) { # Ignore these messages
|
||||||
return "";
|
return "";
|
||||||
@ -365,9 +491,192 @@ FHT_Parse($$)
|
|||||||
$def->{READINGS}{$type}{VAL} = $val;
|
$def->{READINGS}{$type}{VAL} = $val;
|
||||||
|
|
||||||
Log 4, "FHT $def->{NAME} ($type: $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->{CHANGED}[0] = "$type: $val";
|
||||||
$def->{STATE} = "$type: $val" if($type eq "measured-temp");
|
$def->{STATE} = "$type: $val" if($type eq "measured-temp");
|
||||||
return $def->{NAME};
|
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;
|
1;
|
||||||
|
10
fhem/HISTORY
10
fhem/HISTORY
@ -147,3 +147,13 @@
|
|||||||
- weblinks added. Used by webpgm2 to display more than one plot at once
|
- 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
|
- webpgm2 output reformatted. Using CSS to divide the screen area in 3
|
||||||
parts: command line, room-list and rest
|
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
@ -1,255 +1,261 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Home of FHEM</title>
|
<title>Home of FHEM</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="background-color: white">
|
<body style="background-color: white">
|
||||||
|
|
||||||
|
|
||||||
<h1>FHEM</h1>
|
<h1>FHEM</h1>
|
||||||
GPL'd server to access devices like FHZ1000/FHZ1300,EM1010PC,WS300,SCIVT.
|
GPL'd server to access devices like FHZ1000/FHZ1300,EM1010PC,WS300,SCIVT.
|
||||||
Formerly known as fhz1000.pl
|
Formerly known as fhz1000.pl
|
||||||
|
|
||||||
<h2>News (as of =DATE=, Version =VERS=)</h2>
|
<h2>News (as of =DATE=, Version =VERS=)</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li> doc: linux.html (private udev-rules, not 50-..., ATTRS)
|
<li> doc: linux.html (private udev-rules, not 50-..., ATTRS)
|
||||||
<li> bugfix: setting devices with "-" in their name did not work
|
<li> bugfix: setting devices with "-" in their name did not work
|
||||||
<li> doc: fhem.pl and commandref.html (notifyon -> notify, correction
|
<li> doc: fhem.pl and commandref.html (notifyon -> notify, correction
|
||||||
of examples)
|
of examples)
|
||||||
<li> feature: modify command added
|
<li> feature: modify command added
|
||||||
<li> feature: The "-" in the name is not allowed any more
|
<li> feature: The "-" in the name is not allowed any more
|
||||||
<li> bugfix: disabled notify causes "uninitialized value" (STefan, 1.5)
|
<li> bugfix: disabled notify causes "uninitialized value" (STefan, 1.5)
|
||||||
<li> bugfix: deleted FS20 items are still logging (zombie) (Gerhard, 16.5)
|
<li> bugfix: deleted FS20 items are still logging (zombie) (Gerhard, 16.5)
|
||||||
<li> bugfix: added FS20S8, removed stty_parmrk (Martin, 24.5)
|
<li> bugfix: added FS20S8, removed stty_parmrk (Martin, 24.5)
|
||||||
<li> feature: added archivedir/archivecmd to the FileLog
|
<li> feature: added archivedir/archivecmd to the FileLog
|
||||||
<li> feature: added EM1010PC/EM1000WZ/EM1000EM support
|
<li> feature: added EM1010PC/EM1000WZ/EM1000EM support
|
||||||
<li> bugfix: undefined messages for unknown HMS devs (Peter, 8.6)
|
<li> bugfix: undefined messages for unknown HMS devs (Peter, 8.6)
|
||||||
<li> bugfix: em1010 and %oldvalue bugs (Peter, 9.6)
|
<li> bugfix: em1010 and %oldvalue bugs (Peter, 9.6)
|
||||||
<li> bugfix: SCIVT solar controller (peterp, 1.7)
|
<li> bugfix: SCIVT solar controller (peterp, 1.7)
|
||||||
<li> bugfix: WS300 loglevel change (from 2 to 5 or device specific loglevel)
|
<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: First steps for a Fritz!Box port. See the fritzbox.html
|
||||||
</ul>
|
<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)
|
||||||
</ul>
|
<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)
|
||||||
<h2>Description</h2>
|
</ul>
|
||||||
<ul>
|
|
||||||
This program makes the FHZ1000/FHZ1300/WS300 USB devices sold by ELV, Conrad and
|
</ul>
|
||||||
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
|
<h2>Description</h2>
|
||||||
hardware as a serial device.<br>
|
<ul>
|
||||||
The program runs as a server, you can control it via telnet, command line
|
This program makes the FHZ1000/FHZ1300/WS300 USB devices sold by ELV, Conrad and
|
||||||
program or TCP/IP directly, like the supplied web frontends do.<br> <br>
|
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
|
||||||
Currently implemented features:<br>
|
hardware as a serial device.<br>
|
||||||
<ul>
|
The program runs as a server, you can control it via telnet, command line
|
||||||
<li>Via the FHZ module (with access to one or more FHZ1000/FHZ1300 device):
|
program or TCP/IP directly, like the supplied web frontends do.<br> <br>
|
||||||
<ul>
|
|
||||||
<li>reading and sending FS20 events (on/off/dimming, timer commands)<br>
|
Currently implemented features:<br>
|
||||||
<li>support of FS20 address features function group, local and global master
|
<ul>
|
||||||
<li>reading and changing FHT80b parameters (temp, actuator, etc).<br>
|
<li>Via the FHZ module (with access to one or more FHZ1000/FHZ1300 device):
|
||||||
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.</li>
|
<ul>
|
||||||
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)</li>
|
<li>reading and sending FS20 events (on/off/dimming, timer commands)<br>
|
||||||
<li>reading KS300 data</li>
|
<li>support of FS20 address features function group, local and global master
|
||||||
</ul>
|
<li>reading and changing FHT80b parameters (temp, actuator, etc).<br>
|
||||||
</li>
|
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.<br />
|
||||||
<li>reading WS300 data, and up to 9 attached devices</li>
|
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>reading EM1000WZ/EM1000EM data via an attached EM1010PC</li>
|
</li>
|
||||||
<li>reading an attached SCIVT device</li>
|
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)</li>
|
||||||
<li>logging events to files (or database), with regexp filters</li>
|
<li>reading KS300 data</li>
|
||||||
<li>notifying external programs or internal modules when receiving certain
|
</ul>
|
||||||
events</li>
|
</li>
|
||||||
<li>timed commands (e.g. switching a lamp on from sunset till midnight)</li>
|
<li>reading WS300 data, and up to 9 attached devices</li>
|
||||||
<li>modular architecture</li>
|
<li>reading EM1000WZ/EM1000EM data via an attached EM1010PC</li>
|
||||||
<li>a lot of web frontends, choose your favorite</li>
|
<li>reading an attached SCIVT device</li>
|
||||||
<br>
|
<li>logging events to files (or database), with regexp filters</li>
|
||||||
</ul>
|
<li>notifying external programs or internal modules when receiving certain
|
||||||
See <a href="commandref.html">commandref.html</a> for a detailed command
|
events</li>
|
||||||
description and <a href="faq.html">faq.html</a> for the F.A.Q.
|
<li>timed commands (e.g. switching a lamp on from sunset till midnight)</li>
|
||||||
</ul>
|
<li>modular architecture</li>
|
||||||
|
<li>a lot of web frontends, choose your favorite</li>
|
||||||
<h2>Links:</h2>
|
<br>
|
||||||
<ul>
|
</ul>
|
||||||
Homepage: <a href="http://www.koeniglich.de/fhem/fhem.html">
|
See <a href="commandref.html">commandref.html</a> for a detailed command
|
||||||
http://www.koeniglich.de/fhem/fhem.html</a><br>
|
description and <a href="faq.html">faq.html</a> for the F.A.Q.
|
||||||
Download: <a href="http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz">
|
</ul>
|
||||||
http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz</a><br>
|
|
||||||
FAQ: <a href="http://www.koeniglich.de/fhem/faq.html">
|
<h2>Links:</h2>
|
||||||
http://www.koeniglich.de/fhem/faq.html</a><br>
|
<ul>
|
||||||
Google-Group: <a href="http://groups.google.com/group/FHZ1000-users-on-unix">
|
Homepage: <a href="http://www.koeniglich.de/fhem/fhem.html">
|
||||||
http://groups.google.com/group/FHZ1000-users-on-unix</a><br>
|
http://www.koeniglich.de/fhem/fhem.html</a><br>
|
||||||
Martins Web frontend (webpgm3): <a href="http://www.martin-haas.de/fhz">
|
Download: <a href="http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz">
|
||||||
http://www.martin-haas.de/fhz</a><br>
|
http://www.koeniglich.de/fhem/fhem-=VERS=.tar.gz</a><br>
|
||||||
CVS@berlios: <a href="http://developer.berlios.de/projects/fhem">
|
FAQ: <a href="http://www.koeniglich.de/fhem/faq.html">
|
||||||
http://developer.berlios.de/projects/fhem</a><br>
|
http://www.koeniglich.de/fhem/faq.html</a><br>
|
||||||
LinViex (home automation frontend):
|
Google-Group: <a href="http://groups.google.com/group/FHZ1000-users-on-unix">
|
||||||
<a href="http://sourceforge.net/projects/linviex">
|
http://groups.google.com/group/FHZ1000-users-on-unix</a><br>
|
||||||
|
Martins Web frontend (webpgm3): <a href="http://www.martin-haas.de/fhz">
|
||||||
http://sourceforge.net/projects/linviex</a><br><br>
|
http://www.martin-haas.de/fhz</a><br>
|
||||||
Device/OS Specific installation guides:<br>
|
CVS@berlios: <a href="http://developer.berlios.de/projects/fhem">
|
||||||
<ul>
|
http://developer.berlios.de/projects/fhem</a><br>
|
||||||
Linux driver installation:
|
LinViex (home automation frontend):
|
||||||
<a href="http://www.koeniglich.de/fhem/linux.html">
|
<a href="http://sourceforge.net/projects/linviex">
|
||||||
http://www.koeniglich.de/fhem/linux.html</a><br>
|
|
||||||
Instructions for Nas/Routers (NSLU2):
|
http://sourceforge.net/projects/linviex</a><br><br>
|
||||||
<a href="http://www.martin-haas.de/fhz/nslu2fhz">
|
Device/OS Specific installation guides:<br>
|
||||||
http://www.martin-haas.de/fhz/nslu2fhz</a><br>
|
<ul>
|
||||||
Instructions for the Fritz!Box:
|
Linux driver installation:
|
||||||
<a href="fritzbox.html">
|
<a href="http://www.koeniglich.de/fhem/linux.html">
|
||||||
http://www.koeniglich.de/fhem/fritzbox.html</a><br>
|
http://www.koeniglich.de/fhem/linux.html</a><br>
|
||||||
Instructions for the Allnet all6250:
|
Instructions for Nas/Routers (NSLU2):
|
||||||
<a href="http://wiki.dungeon.de/all6250_opennas_mit_fhem">
|
<a href="http://www.martin-haas.de/fhz/nslu2fhz">
|
||||||
http://wiki.dungeon.de/all6250_opennas_mit_fhem</a><br>
|
http://www.martin-haas.de/fhz/nslu2fhz</a><br>
|
||||||
</ul>
|
Instructions for the Fritz!Box:
|
||||||
|
<a href="fritzbox.html">
|
||||||
</ul>
|
http://www.koeniglich.de/fhem/fritzbox.html</a><br>
|
||||||
<h2>Related projects:</h2>
|
Instructions for the Allnet all6250:
|
||||||
<ul>
|
<a href="http://wiki.dungeon.de/all6250_opennas_mit_fhem">
|
||||||
<a href="http://fhz4linux.info/">http://fhz4linux.info/</a><br>
|
http://wiki.dungeon.de/all6250_opennas_mit_fhem</a><br>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Installation</h2>
|
</ul>
|
||||||
<ul>
|
<h2>Related projects:</h2>
|
||||||
|
<ul>
|
||||||
<h3>Linux driver</h3>
|
<a href="http://fhz4linux.info/">http://fhz4linux.info/</a><br>
|
||||||
See <a href="http://www.koeniglich.de/fhem/linux.html">
|
</ul>
|
||||||
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
|
<h2>Installation</h2>
|
||||||
kernel, recompile it and reboot or load/reload the ftdi_sio module.
|
<ul>
|
||||||
</ul>
|
|
||||||
|
<h3>Linux driver</h3>
|
||||||
<h3>Perl modules</h3>
|
See <a href="http://www.koeniglich.de/fhem/linux.html">
|
||||||
<ul>
|
http://www.koeniglich.de/fhem/linux.html</a><br>
|
||||||
You need perl with the Device::SerialPort (<a
|
For kernels older then 2.6.x apply the patch from the doc directory to your
|
||||||
href="http://search.cpan.org/dist/Device-SerialPort/">
|
kernel, recompile it and reboot or load/reload the ftdi_sio module.
|
||||||
http://search.cpan.org/dist/Device-SerialPort/</a>)
|
</ul>
|
||||||
module. All other needed modules were present in my installation.
|
|
||||||
If this module reports <code>Can't call method "opened" on an undefined
|
<h3>Perl modules</h3>
|
||||||
value...</code> when starting the server, then you either may ignore
|
<ul>
|
||||||
this message, or replace the mentioned line with:<pre>
|
You need perl with the Device::SerialPort (<a
|
||||||
$self->{HANDLE}->close if (defined($self->{HANDLE}) &&
|
href="http://search.cpan.org/dist/Device-SerialPort/">
|
||||||
$self->{HANDLE}->opened);</pre>
|
http://search.cpan.org/dist/Device-SerialPort/</a>)
|
||||||
</ul>
|
module. All other needed modules were present in my installation.
|
||||||
|
If this module reports <code>Can't call method "opened" on an undefined
|
||||||
<h3>Server installation</h3>
|
value...</code> when starting the server, then you either may ignore
|
||||||
<ul>
|
this message, or replace the mentioned line with:<pre>
|
||||||
<li>Copy the file <code>fhem.pl</code> into your path (e.g.
|
$self->{HANDLE}->close if (defined($self->{HANDLE}) &&
|
||||||
<code>/usr/local/bin</code>), and the FHEM directory e.g. to
|
$self->{HANDLE}->opened);</pre>
|
||||||
<code>/usr/local/lib</code>. </li>
|
</ul>
|
||||||
<li>Make sure that you can access the serial USB
|
|
||||||
device (e.g. <code>/dev/tts/USB0</code>).</li>
|
<h3>Server installation</h3>
|
||||||
<li>Create a configuration file (see the examples directory and
|
<ul>
|
||||||
docs/commandref.html), and change at least the modpath
|
<li>Copy the file <code>fhem.pl</code> into your path (e.g.
|
||||||
(<code>/usr/local/lib</code>) and define FHZ FHZ (<code>/dev/tts/USB0</code>)
|
<code>/usr/local/bin</code>), and the FHEM directory e.g. to
|
||||||
parameters.</li>
|
<code>/usr/local/lib</code>. </li>
|
||||||
<li>Delete the savefile if you are upgrading from an older version.</li>
|
<li>Make sure that you can access the serial USB
|
||||||
<li>Start the server with <code>fhem.pl <configfile></code></li>
|
device (e.g. <code>/dev/tts/USB0</code>).</li>
|
||||||
</ul>
|
<li>Create a configuration file (see the examples directory and
|
||||||
|
docs/commandref.html), and change at least the modpath
|
||||||
<h3>General Notes for Webfrontends:</h3>
|
(<code>/usr/local/lib</code>) and define FHZ FHZ (<code>/dev/tts/USB0</code>)
|
||||||
<ul>
|
parameters.</li>
|
||||||
<li>You don't have to install all of them, one is probably more than
|
<li>Delete the savefile if you are upgrading from an older version.</li>
|
||||||
enough :-)</li>
|
<li>Start the server with <code>fhem.pl <configfile></code></li>
|
||||||
<li>The web server and the fhem server must be on the same host</li>
|
</ul>
|
||||||
<li><b>Important:</b> Make sure you add some protection (.htaccess, etc)
|
|
||||||
else everybody will be able to set your devices</li>
|
<h3>General Notes for Webfrontends:</h3>
|
||||||
</ul>
|
<ul>
|
||||||
|
<li>You don't have to install all of them, one is probably more than
|
||||||
<h3>Web frontend 2 (webfrontend/pgm2, the simple one)</h3>
|
enough :-)</li>
|
||||||
<ul>
|
<li>The web server and the fhem server must be on the same host</li>
|
||||||
This frontend is CGI/CSS based. It has support for rooms, and FHT/KS300 logs.<br>
|
<li><b>Important:</b> Make sure you add some protection (.htaccess, etc)
|
||||||
Screenshots: <a href="pgm2-1.gif">overview</a>, <a href="pgm2-2.gif">details
|
else everybody will be able to set your devices</li>
|
||||||
</a> and KS300 temperature <a href="pgm2-3.gif">logs</a><br><br>
|
</ul>
|
||||||
|
|
||||||
<ul>
|
<h3>Web frontend 2 (webfrontend/pgm2, the simple one)</h3>
|
||||||
<li>Copy the file fhemweb.pl and *.gplot to your cgi-bin directory
|
<ul>
|
||||||
(/home/httpd/cgi-bin), the icons (*.gif) to your httpd icons
|
This frontend is CGI/CSS based. It has support for rooms, and FHT/KS300 logs.<br>
|
||||||
(/home/httpd/icons), and commandref.html to the html directory
|
Screenshots: <a href="pgm2-1.gif">overview</a>, <a href="pgm2-2.gif">details
|
||||||
(/home/httpd/html).<br>
|
</a> and KS300 temperature <a href="pgm2-3.gif">logs</a><br><br>
|
||||||
Note: The program looks for icons in the following order:
|
|
||||||
<device-name>.<state>, <device-name>,
|
<ul>
|
||||||
<device-type>.<state>, <device-type><br>
|
<li>Copy the file fhemweb.pl and *.gplot to your cgi-bin directory
|
||||||
</li>
|
(/home/httpd/cgi-bin), the icons (*.gif) to your httpd icons
|
||||||
<li>Edit <code>fhemweb.pl</code>, and check the "Config" section.</li>
|
(/home/httpd/icons), and commandref.html to the html directory
|
||||||
<li>If you want to have access to plotted logs, then make sure that
|
(/home/httpd/html).<br>
|
||||||
gnuplot is installed and set the logtype for the FileLog device
|
Note: The program looks for icons in the following order:
|
||||||
(see commandref.html and example/04_log).
|
<device-name>.<state>, <device-name>,
|
||||||
</li>
|
<device-type>.<state>, <device-type><br>
|
||||||
<li>Call <your-site>/cgi-bin/fhemweb.pl
|
</li>
|
||||||
</ul>
|
<li>Edit <code>fhemweb.pl</code>, and check the "Config" section.</li>
|
||||||
For special features like assigning devices to rooms see the README file.
|
<li>If you want to have access to plotted logs, then make sure that
|
||||||
</ul>
|
gnuplot is installed and set the logtype for the FileLog device
|
||||||
|
(see commandref.html and example/04_log).
|
||||||
<h3>Web frontend 3 (webfrontend/pgm3, the professional one)</h3>
|
</li>
|
||||||
<ul>
|
<li>Call <your-site>/cgi-bin/fhemweb.pl
|
||||||
This frontend is PHP based and was contributed by Martin Haas.
|
</ul>
|
||||||
Look at the webfrontends/pgm3/docs for more documentation or at
|
For special features like assigning devices to rooms see the README file.
|
||||||
<a href="pgm3-0.5.1.png">this screenshot</a>. A lot more details can be
|
</ul>
|
||||||
found on Martins page: <a href="http://www.martin-haas.de/fhz">
|
|
||||||
http://www.martin-haas.de/fhz</a>
|
<h3>Web frontend 3 (webfrontend/pgm3, the professional one)</h3>
|
||||||
<br><br>
|
<ul>
|
||||||
|
This frontend is PHP based and was contributed by Martin Haas.
|
||||||
<ul>
|
Look at the webfrontends/pgm3/docs for more documentation or at
|
||||||
<li>Install PHP and enable it by commenting in the "LoadModule
|
<a href="pgm3-0.5.1.png">this screenshot</a>. A lot more details can be
|
||||||
phpX_module ..." directive in httpd.conf (perhaps it is already
|
found on Martins page: <a href="http://www.martin-haas.de/fhz">
|
||||||
done by your distro). Restart/reload httpd.</li>
|
http://www.martin-haas.de/fhz</a>
|
||||||
|
<br><br>
|
||||||
<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
|
<ul>
|
||||||
directory is writeable by the webserver!</li>
|
<li>Install PHP and enable it by commenting in the "LoadModule
|
||||||
|
phpX_module ..." directive in httpd.conf (perhaps it is already
|
||||||
<li>Edit index.php (/home/httpd/html/pgm3/index.php), and check the
|
done by your distro). Restart/reload httpd.</li>
|
||||||
required settings section</li>
|
|
||||||
|
<li>Create a directory (e.g.: /home/httpd/html/pgm3) and copy all the
|
||||||
<li>If you want to have access to the FHT temperature logs, then:
|
files from the webfrontend/pgm3 to this directory.<br>Make sure that this
|
||||||
<ul>
|
directory is writeable by the webserver!</li>
|
||||||
<li>Make sure gnuplot is installed</li>
|
|
||||||
<li>check the showgnuplot section in index.php</li>
|
<li>Edit index.php (/home/httpd/html/pgm3/index.php), and check the
|
||||||
<li>For each FHT device copy the file docs/gnuplot/gnuplot.wz to
|
required settings section</li>
|
||||||
gnuplot.fhtdevicename (to the /home/httpd/html/pgm3 directory) and
|
|
||||||
replace fht.log in this file with the absolute name of the current
|
<li>If you want to have access to the FHT temperature logs, then:
|
||||||
logfile.</li>
|
<ul>
|
||||||
</ul>
|
<li>Make sure gnuplot is installed</li>
|
||||||
<li>Call <your-site>/pgm3/index.php</li>
|
<li>check the showgnuplot section in index.php</li>
|
||||||
</ul>
|
<li>For each FHT device copy the file docs/gnuplot/gnuplot.wz to
|
||||||
</ul>
|
gnuplot.fhtdevicename (to the /home/httpd/html/pgm3 directory) and
|
||||||
|
replace fht.log in this file with the absolute name of the current
|
||||||
<h3>Web frontend 4 (webfrontend/pgm4, the template)</h3>
|
logfile.</li>
|
||||||
<ul>
|
</ul>
|
||||||
This frontend is PHP based and was contributed by Stefan Mayer. It won't work
|
<li>Call <your-site>/pgm3/index.php</li>
|
||||||
for you without modification, it is meant as a template or as an example. See
|
</ul>
|
||||||
the <a href="pgm4.gif">screenshot</a>. To install:
|
</ul>
|
||||||
<ul>
|
|
||||||
<li>Copy the directory webfrontend/pgm4 to your html directory.</li>
|
<h3>Web frontend 4 (webfrontend/pgm4, the template)</h3>
|
||||||
<li>Install/enable PHP (see the description for frontend3)</li>
|
<ul>
|
||||||
<li>Call the program with http://webserver/pgm4/fs20.php</li>
|
This frontend is PHP based and was contributed by Stefan Mayer. It won't work
|
||||||
</ul>
|
for you without modification, it is meant as a template or as an example. See
|
||||||
Now you can go on, and modify it to suit your needs :-)
|
the <a href="pgm4.gif">screenshot</a>. To install:
|
||||||
</ul>
|
<ul>
|
||||||
|
<li>Copy the directory webfrontend/pgm4 to your html directory.</li>
|
||||||
</ul>
|
<li>Install/enable PHP (see the description for frontend3)</li>
|
||||||
|
<li>Call the program with http://webserver/pgm4/fs20.php</li>
|
||||||
<h2>License:</h2>
|
</ul>
|
||||||
<ul>
|
Now you can go on, and modify it to suit your needs :-)
|
||||||
Copyright:<br>
|
</ul>
|
||||||
<ul>
|
|
||||||
<li>Rudolf Koenig (r dot koenig at koeniglich dot de)</li>
|
</ul>
|
||||||
<li>Raoul Matthiessen (webfrontends/pgm1)</li>
|
|
||||||
<li>Martin Haas (webfrontends/pgm3)</li>
|
<h2>License:</h2>
|
||||||
</ul>
|
<ul>
|
||||||
License: GPL (v2)
|
Copyright:<br>
|
||||||
</ul>
|
<ul>
|
||||||
|
<li>Rudolf Koenig (r dot koenig at koeniglich dot de)</li>
|
||||||
</ul>
|
<li>Raoul Matthiessen (webfrontends/pgm1)</li>
|
||||||
|
<li>Martin Haas (webfrontends/pgm3)</li>
|
||||||
<h2>Misc:</h2>
|
</ul>
|
||||||
<ul>
|
License: GPL (v2)
|
||||||
Thanks for Tosti for inspiration and numerous other people for help. <br>
|
</ul>
|
||||||
</ul>
|
|
||||||
|
</ul>
|
||||||
</body>
|
|
||||||
|
<h2>Misc:</h2>
|
||||||
</html>
|
<ul>
|
||||||
|
Thanks for Tosti for inspiration and numerous other people for help. <br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
52
fhem/fhem.pl
52
fhem/fhem.pl
@ -134,7 +134,7 @@ my %intAt; # Internal at timer hash.
|
|||||||
my $intAtCnt=0;
|
my $intAtCnt=0;
|
||||||
my $reread_active = 0;
|
my $reread_active = 0;
|
||||||
my $AttrList = "room comment";
|
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;
|
$init_done = 0;
|
||||||
|
|
||||||
@ -1044,10 +1044,58 @@ CommandList($$)
|
|||||||
if($r) {
|
if($r) {
|
||||||
$str .= "Readings:\n";
|
$str .= "Readings:\n";
|
||||||
foreach my $c (sort keys %{$r}) {
|
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;
|
return $str;
|
||||||
|
Loading…
Reference in New Issue
Block a user