Major rewrite. See the HISTORY

git-svn-id: https://svn.fhem.de/fhem/trunk@30 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2007-03-19 14:59:37 +00:00
parent 154ba72193
commit 1af4b93426
24 changed files with 1292 additions and 2372 deletions

View File

@ -305,5 +305,16 @@
- feature: attribute showtime in web-pgm2 (show time instead of state)
- feature: defattr (default attribute for following defines)
- feature: added em1010.pl to the contrib directory
- TODO: bugfix: more thorough serial line initialization
- doc: added linux.html (multiple devices, udev-links)
- REORGANIZATION:
- at/notify "renamed" to "define <name> at/notify"
- logfile/modpath/pidfile/port/verbose "renamed" to "attr global xxx"
- savefile renamed to "attr global statefile"
- save command added, it writes the configfile and the statefile
- delattr added
- list/xmllist format changed
- disable attribute for at/notify/filelog
See HISTORY for details and reasoning
- TODO: bugfix: more thorough serial line initialization
- RENAME

View File

@ -44,7 +44,6 @@ my %codes = (
"^8501..\$" => "fhtbuf",
);
my %readings;
my $def;
my %msghist; # Used when more than one FHZ is attached
my $msgcount = 0;
@ -57,8 +56,6 @@ FHZ_Initialize($)
my ($hash) = @_;
$hash->{Category}= "DEV";
# Provider
$hash->{ReadFn} = "FHZ_Read";
$hash->{WriteFn} = "FHZ_Write";
@ -71,8 +68,8 @@ FHZ_Initialize($)
$hash->{GetFn} = "FHZ_Get";
$hash->{SetFn} = "FHZ_Set";
$hash->{StateFn} = "FHZ_SetState";
$hash->{ListFn} = "FHZ_List";
$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";
}
#####################################
@ -81,16 +78,18 @@ FHZ_Set($@)
{
my ($hash, @a) = @_;
return "Need one to three parameter" if(@a > 4);
return "invalid parameter, use one of:\n " . join("\n ", sort keys %sets)
return "Need one to three parameter" if(@a < 2);
return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
if(!defined($sets{$a[1]}));
return "Need one to three parameter" if(@a > 4);
return "Wrong number of parameters for $a[1], need " . ($setnrparam{$a[1]}+2)
if(@a != ($setnrparam{$a[1]} + 2));
my ($fn, $arg) = split(" ", $sets{$a[1]});
my $v = join(" ", @a);
Log GetLogLevel("FHZ"), "FHZ set $v";
my $name = $hash->{NAME};
Log GetLogLevel($name,2), "FHZ set $name $v";
if($a[1] eq "activefor") {
@ -98,7 +97,7 @@ FHZ_Set($@)
return "device $a[2] unknown" if(!defined($dhash));
return "Cannot handle $dhash->{TYPE} devices"
if($devmods{FHZ}->{Clients} !~ m/:$dhash->{TYPE}:/);
if($modules{FHZ}->{Clients} !~ m/:$dhash->{TYPE}:/);
$dhash->{IODev} = $hash;
return undef;
@ -133,15 +132,14 @@ FHZ_Get($@)
my ($hash, @a) = @_;
return "\"get FHZ\" needs only one parameter" if(@a != 2);
if(!defined($gets{$a[1]})) {
return "Unknown set value $a[1], please specify one of: " .
join(" ", sort(keys %gets));
}
return "Unknown argument $a[1], choose one of " . join(",", sort keys %gets)
if(!defined($gets{$a[1]}));
my ($fn, $arg) = split(" ", $gets{$a[1]});
my $v = join(" ", @a);
Log GetLogLevel("FHZ"), "FHZ get $v";
my $name = $hash->{NAME};
Log GetLogLevel($name,2), "FHZ get $name $v";
FHZ_Write($hash, $fn, $arg) if(!IsDummy("FHZ"));
@ -157,26 +155,12 @@ FHZ_Get($@)
} else {
$v = substr($msg, 12);
}
$readings{$a[1]}{VAL} = $v;
$readings{$a[1]}{TIM} = TimeNow();
$hash->{READINGS}{$a[1]}{VAL} = $v;
$hash->{READINGS}{$a[1]}{TIME} = TimeNow();
return "$a[0] $a[1] => $v";
}
#####################################
sub
FHZ_List($)
{
my ($hash) = @_;
my $str = "";
foreach my $m (sort keys %readings) {
$str .= sprintf("%-19s %-15s %s\n",
$readings{$m}{TIM},$m,$readings{$m}{VAL});
}
return $str;
}
#####################################
sub
FHZ_SetState($$$$)
@ -184,11 +168,6 @@ FHZ_SetState($$$$)
my ($hash, $tim, $vt, $val) = @_;
return "Undefined value $vt" if(!defined($gets{$vt}));
if(!$readings{$vt} || $readings{$vt}{TIM} lt $tim) {
$readings{$vt}{TIM} = $tim;
$readings{$vt}{VAL} = $val;
}
return undef;
}
@ -216,7 +195,8 @@ DoInit($)
sub
FHZ_Define($$)
{
my ($hash, @a) = @_;
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
$hash->{STATE} = "Initialized";
@ -224,6 +204,8 @@ FHZ_Define($$)
delete $hash->{FD};
my $dev = $a[2];
$attr{$a[0]}{savefirst} = 1;
if($dev eq "none") {
Log 1, "FHZ device is none, commands will be echoed only";
return undef;
@ -252,12 +234,14 @@ sub
FHZ_Undef($$)
{
my ($hash, $arg) = @_;
my $name = $hash->{NAME};
foreach my $d (keys %defs) {
if(defined($defs{$d}) &&
defined($defs{$d}{IODev}) &&
$defs{$d}{IODev} == $hash)
{
Log 4, "deleting port for $d";
Log GetLogLevel($name,2), "deleting port for $d";
delete $defs{$d}{IODev};
}
}
@ -275,6 +259,7 @@ FHZ_Parse($$)
$msg = substr($msg, 12); # The first 12 bytes are not really interesting
my $type = "";
my $name = $hash->{NAME};
foreach my $c (keys %codes) {
if($msg =~ m/$c/) {
$type = $codes{$c};
@ -283,7 +268,7 @@ FHZ_Parse($$)
}
if(!$type) {
Log 4, "FHZ unknown: $omsg";
Log 4, "FHZ $name unknown: $omsg";
$def->{CHANGED}[0] = "$msg";
return $hash->{NAME};
}
@ -293,7 +278,7 @@ FHZ_Parse($$)
$msg = substr($msg, 4, 2);
}
Log 4, "FHZ $type: $msg)";
Log 4, "FHZ $name $type: $msg)";
$def->{CHANGED}[0] = "$type: $msg";
return $hash->{NAME};
}
@ -355,7 +340,7 @@ FHZ_ReadAnswer($$)
my $len = ord(substr($mfhzdata,1,1)) + 2;
if($len>20) {
Log 1, "Oversized message (" . unpack('H*',$mfhzdata) .
Log 4, "Oversized message (" . unpack('H*',$mfhzdata) .
"), dropping it ...";
return undef;
}
@ -438,7 +423,7 @@ FHZ_Read($)
my ($hash) = @_;
my $buf = $hash->{PortObj}->input();
my $iohash = $devmods{$hash->{TYPE}};
my $iohash = $modules{$hash->{TYPE}};
my $name = $hash->{NAME};
###########
@ -531,12 +516,12 @@ FHZ_Read($)
my @found;
foreach my $m (sort { $devmods{$a}{ORDER} cmp $devmods{$b}{ORDER} }
keys %devmods) {
foreach my $m (sort { $modules{$a}{ORDER} cmp $modules{$b}{ORDER} }
keys %modules) {
next if($iohash->{Clients} !~ m/:$m:/);
next if($dmsg !~ m/$devmods{$m}{Match}/i);
next if($dmsg !~ m/$modules{$m}{Match}/i);
no strict "refs";
@found = &{$devmods{$m}{ParseFn}}($hash,$dmsg);
@found = &{$modules{$m}{ParseFn}}($hash,$dmsg);
use strict "refs";
last if(int(@found));
}

View File

@ -45,8 +45,44 @@ my %readonly = (
use vars qw(%fs20_c2b); # Peter would like to access it from outside
my %defptr;
my %readings;
my %follow;
my $fs20_simple ="off off-for-timer on on-for-timer on-till reset timer toggle";
my %models = (
fs20hgs => 'sender',
fs20hgs => 'sender',
fs20pira => 'sender',
fs20piri => 'sender',
fs20s20 => 'sender',
fs20s4 => 'sender',
fs20s4a => 'sender',
fs20s4m => 'sender',
fs20s4u => 'sender',
fs20s4ub => 'sender',
fs20sd => 'sender',
fs20sn => 'sender',
fs20sr => 'sender',
fs20ss => 'sender',
fs20str => 'sender',
fs20tfk => 'sender',
fs20tfk => 'sender',
fs20tk => 'sender',
fs20uts => 'sender',
fs20ze => 'sender',
fs20as1 => 'simple',
fs20as4 => 'simple',
fs20di => 'dimmer',
fs20du => 'dimmer',
fs20ms2 => 'simple',
fs20rst => 'simple',
fs20sa => 'simple',
fs20sig => 'simple',
fs20st => 'simple',
fs20sv => 'simple',
fs20sv => 'simple',
fs20usr => 'simple',
);
sub
FS20_Initialize($)
@ -58,38 +94,14 @@ FS20_Initialize($)
}
$fs20_c2b{"on-till"} = 99;
$hash->{Category} = "DEV";
$hash->{Match} = "^81..(04|0c)..0101a001";
$hash->{SetFn} = "FS20_Set";
$hash->{GetFn} = "FS20_Get";
$hash->{ListFn} = "FS20_List";
$hash->{StateFn} = "FS20_SetState";
$hash->{DefFn} = "FS20_Define";
$hash->{UndefFn} = "FS20_Undef";
$hash->{ParseFn} = "FS20_Parse";
}
$hash->{AttrList} = "follow-on-for-timer:1,0 do_not_notify:1,0 dummy:1,0 showtime:1,0 model;fs20hgs,fs20hgs,fs20pira,fs20piri,fs20s20,fs20s4,fs20s4a,fs20s4m,fs20s4u,fs20s4ub,fs20sd,fs20sn,fs20sr,fs20ss,fs20str,fs20tfk,fs20tfk,fs20tk,fs20uts,fs20ze,fs20as1,fs20as4,fs20di,fs20du,fs20ms2,fs20rst,fs20sa,fs20sig,fs20st,fs20sv,fs20sv,fs20usr loglevel:0,1,2,3,4,5,6";
###################################
sub
FS20_Get($@)
{
my ($hash, @a) = @_;
return "No get function implemented";
}
###################################
sub
FS20_List($)
{
my ($hash) = @_;
my $n = $hash->{NAME};
if(!defined($readings{$n})) {
return "No information about $n\n";
} else {
return sprintf("%-19s %s\n", $readings{$n}{TIM}, $readings{$n}{VAL});
}
}
#####################################
@ -98,13 +110,8 @@ FS20_SetState($$$$)
{
my ($hash, $tim, $vt, $val) = @_;
return "Undefined value $vt" if(!defined($fs20_c2b{$vt}));
my $name = $hash->{NAME};
if(!$readings{$name} || $readings{$name}{TIM} lt $tim) {
$readings{$name}{TIM} = $tim;
$readings{$name}{VAL} = $vt;
}
$val = $1 if($val =~ m/^\(.*\) \d+$/);
return "Undefined value $val" if(!defined($fs20_c2b{$val}));
return undef;
}
@ -128,7 +135,8 @@ Do_On_Till($@)
my @b = ($a[0], "on");
FS20_Set($hash, @b);
CommandAt(undef, "$hms_till set $a[0] off");
CommandDefine(undef, $hash->{NAME} . "_till at $hms_till set $a[0] off");
}
@ -145,8 +153,18 @@ FS20_Set($@)
my $c = $fs20_c2b{$a[1]};
if(!defined($c)) {
return "Unknown set value $a[1], please specify one of:\n " .
join("\n ", sort(keys %fs20_c2b));
# Model specific set arguments
if(defined($attr{$a[0]}) && defined($attr{$a[0]}{"model"})) {
my $mt = $models{$attr{$a[0]}{"model"}};
return "Unknown argument $a[1], choose one of "
if($mt && $mt eq "sender");
return "Unknown argument $a[1], choose one of $fs20_simple"
if($mt && $mt eq "simple");
}
return "Unknown argument $a[1], choose one of " .
join(" ", sort keys %fs20_c2b);
}
return Do_On_Till($hash, @a) if($a[1] eq "on-till");
@ -154,7 +172,7 @@ FS20_Set($@)
return "Bad time spec" if($na == 3 && $a[2] !~ m/^\d*\.?\d+$/);
my $v = join(" ", @a);
Log GetLogLevel($a[0]), "FS20 set $v";
Log GetLogLevel($a[0],2), "FS20 set $v";
(undef, $v) = split(" ", $v, 2); # Not interested in the name...
my $val;
@ -175,7 +193,7 @@ FS20_Set($@)
if($val >= $a[2]) {
if($val != $a[2]) {
$ret = "FS20 Setting timeout to $val from $a[2]";
Log GetLogLevel($a[0]), $ret;
Log GetLogLevel($a[0],2), $ret;
}
$c .= sprintf("%x%x", $i, $j);
last LOOP;
@ -200,7 +218,7 @@ FS20_Set($@)
my $to = sprintf("%02d:%02d:%02d", $val/3600, ($val%3600)/60, $val%60);
$follow{$a[0]} = $to;
Log 4, "Follow: +$to setstate $a[0] off";
CommandAt(undef, "+$to setstate $a[0] off");
CommandDefine(undef, $a[0] . "_timer at +$to setstate $a[0] off");
}
##########################
@ -208,23 +226,25 @@ FS20_Set($@)
my $code = "$hash->{XMIT} $hash->{BTN}";
my $tn = TimeNow();
foreach my $n (keys %{ $defptr{$code} }) {
$defptr{$code}{$n}->{CHANGED}[0] = $v;
$defptr{$code}{$n}->{STATE} = $v;
$readings{$n}{TIM} = $tn;
$readings{$n}{VAL} = $v;
}
my $lh = $defptr{$code}{$n};
$lh->{CHANGED}[0] = $v;
$lh->{STATE} = $v;
$lh->{READINGS}{state}{TIME} = $tn;
$lh->{READINGS}{state}{VAL} = $v;
}
return $ret;
}
#############################
sub
FS20_Define($@)
FS20_Define($$)
{
my ($hash, @a) = @_;
my $u =
"wrong syntax: define <name> FS20 housecode addr [fg addr] [lm addr] [gm FF]";
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
my $u = "wrong syntax: define <name> FS20 housecode " .
"addr [fg addr] [lm addr] [gm FF]";
return $u if(int(@a) < 4);
return "Define $a[0]: wrong housecode format: specify a 4 digit hex value"
@ -287,7 +307,6 @@ FS20_Parse($)
my $btn = substr($msg, 20, 2);
my $cde = substr($msg, 24, 2);
my $def = $defptr{"$dev $btn"};
my $dur = 0;
my $cx = hex($cde);
@ -302,15 +321,17 @@ FS20_Parse($)
my $v = $codes{$cde};
$v = "unknown:$cde" if(!defined($v));
$v .= " $dur" if($dur);
if($def) {
my $def = $defptr{"$dev $btn"};
if($def) {
my @list;
foreach my $n (keys %{ $def }) {
$readings{$n}{TIM} = TimeNow();
$readings{$n}{VAL} = $v;
$def->{$n}->{CHANGED}[0] = $v;
$def->{$n}->{STATE} = $v;
Log GetLogLevel($n), "FS20 $n $v";
my $lh = $def->{$n};
$lh->{CHANGED}[0] = $v;
$lh->{STATE} = $v;
$lh->{READINGS}{state}{TIME} = TimeNow();
$lh->{READINGS}{state}{VAL} = $v;
Log GetLogLevel($n,2), "FS20 $n $v";
push(@list, $n);
}
return @list;

View File

@ -1,404 +0,0 @@
##############################################
package main;
use strict;
use warnings;
my %codes = (
"0000.6" => "actuator",
"00002c" => "synctime", # Not verified
"0100.6" => "actuator1", # Not verified (1-8)
"0200.6" => "actuator2",
"0300.6" => "actuator3",
"0400.6" => "actuator4",
"0500.6" => "actuator5",
"0600.6" => "actuator6",
"0700.6" => "actuator7",
"0800.6" => "actuator8",
"140069" => "mon-from1",
"150069" => "mon-to1",
"160069" => "mon-from2",
"170069" => "mon-to2",
"180069" => "tue-from1",
"190069" => "tue-to1",
"1a0069" => "tue-from2",
"1b0069" => "tue-to2",
"1c0069" => "wed-from1",
"1d0069" => "wed-to1",
"1e0069" => "wed-from2",
"1f0069" => "wed-to2",
"200069" => "thu-from1",
"210069" => "thu-to1",
"220069" => "thu-from2",
"230069" => "thu-to2",
"240069" => "fri-from1",
"250069" => "fri-to1",
"260069" => "fri-from2",
"270069" => "fri-to2",
"280069" => "sat-from1",
"290069" => "sat-to1",
"2a0069" => "sat-from2",
"2b0069" => "sat-to2",
"2c0069" => "sun-from1",
"2d0069" => "sun-to1",
"2e0069" => "sun-from2",
"2f0069" => "sun-to2",
"3e0069" => "mode",
"3f0069" => "holiday1", # Not verified
"400069" => "holiday2", # Not verified
"410069" => "desired-temp",
"XX0069" => "measured-temp", # sum of next. two, never "really" sent
"420069" => "measured-low",
"430069" => "measured-high",
"440069" => "state",
"600069" => "year",
"610069" => "month",
"620069" => "day",
"630069" => "hour",
"640069" => "minute",
"650069" => "init",
"820069" => "day-temp",
"840069" => "night-temp",
"850069" => "unknown_85",
"8a0069" => "windowopen-temp",
"0000aa" => "code_0000aa",
"0000ba" => "code_0000ba",
"430079" => "code_430079",
"440079" => "code_440079",
"4b0067" => "code_4b004b",
"4b0077" => "code_4b0077",
"7e0067" => "code_7e0067",
);
my %cantset = (
"actuator" => 1,
"actuator1" => 1,
"actuator2" => 1,
"actuator3" => 1,
"actuator4" => 1,
"actuator5" => 1,
"actuator6" => 1,
"actuator7" => 1,
"actuator8" => 1,
"synctime" => 1,
"measured-temp" => 1,
"measured-high" => 1,
"measured-low" => 1,
"state" => 1,
"init" => 1,
"code_0000aa" => 1,
"code_0000ba" => 1,
"code_430079" => 1,
"code_440079" => 1,
"code_4b004b" => 1,
"code_4b0077" => 1,
"code_7e0067" => 1,
);
my %nosetarg = (
"help" => 1,
"refreshvalues" => 1,
);
my %c2m = (0 => "auto", 1 => "manual", 2 => "holiday");
my %m2c = ("auto" => 0, "manual" => 1, "holiday" => 2);
my %readings;
my %defptr;
my %c2b; # command->button hash (reverse of codes)
my %c2bset; # Setteable values
#####################################
sub
FHT_Initialize($)
{
my ($hash) = @_;
foreach my $k (keys %codes) {
my $v = $codes{$k};
$c2b{$v} = $k;
$c2bset{$v} = substr($k, 0, 2) if(!defined($cantset{$v}));
}
$c2bset{refreshvalues} = "65ff66ff";
$hash->{Category} = "DEV";
# 810c0426 0909a001 1111 1600
# 810c04b3 0909a001 1111 44006900
# 810b0402 83098301 1111 41301d
# 81090421 c409c401 1111 00
# 810c0d20 0909a001 3232 7e006724 (NYI)
$hash->{Match} = "^81..(04|09|0d)..(0909a001|83098301|c409c401)..";
$hash->{SetFn} = "FHT_Set";
$hash->{GetFn} = "FHT_Get";
$hash->{StateFn} = "FHT_SetState";
$hash->{ListFn} = "FHT_List";
$hash->{DefFn} = "FHT_Define";
$hash->{UndefFn} = "FHT_Undef";
$hash->{ParseFn} = "FHT_Parse";
}
#####################################
sub
FHT_Set($@)
{
my ($hash, @a) = @_;
my $ret = undef;
return "\"set $a[0]\" needs two parameters"
if(@a != 3 && !(@a == 2 && $nosetarg{$a[1]}));
return "invalid parameter, use one of:\n " .
join("\n ", sort {$c2bset{$a} cmp $c2bset{$b} } keys %c2bset)
if(!defined($c2bset{$a[1]}));
Log GetLogLevel($a[0]), "FHT set " . join(" ", @a);
my $arg = "020183" . $hash->{CODE} . $c2bset{$a[1]};
if($a[1] eq "refreshvalues") {
# This is special. Without the sleep the next FHT won't send its data
if(!IsDummy($a[0])) {
my $havefhz;
$havefhz = 1 if($hash->{IODev} && defined($hash->{IODev}->{FD}));
IOWrite($hash, "04", $arg);
sleep(1) if($havefhz);
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]);
}
IOWrite($hash, "04", $arg) if(!IsDummy($a[0]));
return $ret;
}
#####################################
sub
FHT_Get($@)
{
my ($hash,@a) = @_;
return "NYI";
}
#####################################
sub
FHT_List($)
{
my ($hash) = @_;
my $n = $hash->{CODE};
if(!defined($readings{$n})) {
return "No information about " . $hash->{NAME} . "\n";
} else {
my $str = "";
foreach my $m (sort { $c2b{$a} cmp $c2b{$b} } keys %{ $readings{$n} }) {
$str .= sprintf("%-19s %-15s %s\n",
$readings{$n}{$m}{TIM}, $m, $readings{$n}{$m}{VAL});
}
return $str;
}
}
#####################################
sub
FHT_SetState($$$$)
{
my ($hash, $tim, $vt, $val) = @_;
return "Undefined type $vt" if(!defined($c2b{$vt}));
my $n = $hash->{CODE};
if(!$readings{$n}{$vt} || $readings{$n}{$vt}{TIM} lt $tim) {
$readings{$n}{$vt}{TIM} = $tim;
$readings{$n}{$vt}{VAL} = $val;
}
return undef;
}
#####################################
sub
FHT_Define($@)
{
my ($hash, @a) = @_;
return "wrong syntax: define <name> FHT CODE" if(int(@a) != 3);
$a[2] = lc($a[2]);
return "Define $a[0]: wrong CODE format: specify a 4 digit hex value"
if($a[2] !~ m/^[a-f0-9][a-f0-9][a-f0-9][a-f0-9]$/i);
$hash->{CODE} = $a[2];
$defptr{$a[2]} = $hash;
AssignIoPort($hash);
Log 1, "Asking the FHT device $a[0]/$a[2] to send its data";
FHT_Set($hash, ($a[0], "refreshvalues"));
return undef;
}
#####################################
sub
FHT_Undef($$)
{
my ($hash, $name) = @_;
delete($defptr{$hash->{CODE}});
return undef;
}
#####################################
sub
FHT_Parse($$)
{
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);
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 "";
}
if(length($cde) < 6) {
Log 4, "FHT Unknown code from $def->{NAME} : $cde";
$def->{CHANGED}[0] = "unknown code $cde";
return $def->{NAME};
}
if(!$val) {
# This is a confirmation message. We reformat it so that
# it looks like a real message, and let the rest parse it
Log 4, "FHT $def->{NAME} confirmation: $cde)";
$val = substr($cde, 2, 2);
$cde = substr($cde, 0, 2) . "0069";
}
my $type;
foreach my $c (keys %codes) {
if($cde =~ m/$c/) {
$type = $codes{$c};
last;
}
}
$val = hex($val);
if(!$type) {
Log 4, "FHT $def->{NAME} (Unknown: $cde => $val)";
$def->{CHANGED}[0] = "unknown $cde: $val";
return $def->{NAME};
}
my $tn = TimeNow();
###########################
# Reformat the values so they are readable
if($type eq "actuator") {
$val = sprintf("%02d%%", int(100*$val/255 + 0.5));
} elsif($cde ge "140069" && $cde le "2f0069") { # Time specs
Log 5, "FHT $def->{NAME} ($type: $val)";
return "" if($val == 144); # Empty, forget it
my $hour = $val / 6;
my $min = ($val % 6) * 10;
$val = sprintf("%02d:%02d", $hour, $min);
} elsif($type eq "mode") {
$val = $c2m{$val} if(defined($c2m{$val}));
} elsif($type eq "measured-low") {
$readings{$dev}{$type}{TIM} = $tn;
$readings{$dev}{$type}{VAL} = $val;
return "";
} elsif($type eq "measured-high") {
$readings{$dev}{$type}{TIM} = $tn;
$readings{$dev}{$type}{VAL} = $val;
if(defined($readings{$dev}{"measured-low"}{VAL})) {
$val = $val*256 + $readings{$dev}{"measured-low"}{VAL};
$val /= 10;
$val = sprintf("%.1f (Celsius)", $val);
$type = "measured-temp"
} else {
return "";
}
} elsif($type =~ m/.*-temp/) {
$val = sprintf("%.1f (Celsius)", $val / 2)
} elsif($type eq "state") {
my $nval;
$nval = "Bat: " . (($val & 1) ? "empty" : "ok");
$nval .= ", Window: " . (($val & 32) ? "open" : "closed");
$nval .= ", Fault: " . (($val & 16) ? "yes" : "no");
$val = $nval;
} elsif($type =~ m/echo_/) { # Ignore these messages
return "";
}
$readings{$dev}{$type}{TIM} = $tn;
$readings{$dev}{$type}{VAL} = $val;
Log 4, "FHT $def->{NAME} ($type: $val)";
$def->{CHANGED}[0] = "$type: $val";
$def->{STATE} = "$type: $val" if($type eq "measured-temp");
return $def->{NAME};
}
1;

View File

@ -1,262 +0,0 @@
##############################################
package main;
use strict;
use warnings;
my %codes = (
"0" => "HMS100TF",
"1" => "HMS100T",
"2" => "HMS100WD",
"3" => "RM100-2",
"4" => "HMS100TFK", # Depending on the onboard jumper it is 4 or 5
"5" => "HMS100TFK",
"6" => "HMS100MG",
);
my %readings;
my %defptr;
#####################################
sub
HMS_Initialize($)
{
my ($hash) = @_;
$hash->{Category} = "DEV";
# 810e047e0510a001473a000000120233 HMS100TF
# 810e04b90511a0018e63000001100000 HMS100T
# 810e04e80212a001ec46000001000000 HMS100WD
# 810e04d70213a001b16d000003000000 RM100-2
# 810e047f0214a001a81f000001000000 HMS100TFK
# 810e048f0295a0010155000001000000 HMS100TFK (jumper)
# 810e04330216a001b4c5000001000000 HMS100MG
$hash->{Match} = "^810e04....(1|5|9)[0-6]a001";
$hash->{SetFn} = "HMS_Set";
$hash->{GetFn} = "HMS_Get";
$hash->{StateFn} = "HMS_SetState";
$hash->{ListFn} = "HMS_List";
$hash->{DefFn} = "HMS_Define";
$hash->{UndefFn} = "HMS_Undef";
$hash->{ParseFn} = "HMS_Parse";
}
###################################
sub
HMS_Set($@)
{
my ($hash, @a) = @_;
return "No set function implemented";
}
###################################
sub
HMS_Get($@)
{
my ($hash,@a) = @_;
return "No get function implemented";
}
#####################################
sub
HMS_SetState($$$$)
{
my ($hash, $tim, $vt, $val) = @_;
my $n = $hash->{CODE};
if(!$readings{$n}{$vt} || $readings{$n}{$vt}{TIM} lt $tim) {
$readings{$n}{$vt}{TIM} = $tim;
$readings{$n}{$vt}{VAL} = $val;
}
return undef;
}
#####################################
sub
HMS_List($)
{
my ($hash) = @_;
my $n = $hash->{CODE};
if(!defined($readings{$n})) {
return "No information about " . $hash->{NAME} . "\n";
} else {
my $str = "";
foreach my $m (keys %{ $readings{$n} }) {
$str .= sprintf("%-19s %-15s %s\n",
$readings{$n}{$m}{TIM}, $m, $readings{$n}{$m}{VAL});
}
return $str;
}
}
#####################################
sub
HMS_Define($@)
{
my ($hash, @a) = @_;
return "wrong syntax: define <name> HMS CODE" if(int(@a) != 3);
$a[2] = lc($a[2]);
return "Define $a[0]: wrong CODE format: specify a 4 digit hex value"
if($a[2] !~ m/^[a-f0-9][a-f0-9][a-f0-9][a-f0-9]$/);
$hash->{CODE} = $a[2];
$defptr{$a[2]} = $hash;
return undef;
}
#####################################
sub
HMS_Undef($$)
{
my ($hash, $name) = @_;
delete($defptr{$hash->{CODE}});
return undef;
}
#####################################
sub
HMS_Parse($$)
{
my ($hash, $msg) = @_;
my $dev = substr($msg, 16, 4);
my $cde = substr($msg, 11, 1);
my $val = substr($msg, 24, 8) if(length($msg) == 32);
my $type = "";
foreach my $c (keys %codes) {
if($cde =~ m/$c/) {
$type = $codes{$c};
last;
}
}
# As the HMS devices change their id on each battery change, we offer
# a wildcard too for each type: 100<device-code>,
my $odev = $dev;
if(!defined($defptr{$dev})) {
Log 4, "HMS device $dev not defined, using the wildcard device 100$cde";
$dev = "100$cde";
}
if(!defined($defptr{$dev})) {
Log 3, "Unknown HMS device $dev/$odev, please define it";
$type = "HMS" if(!$type);
return "UNDEFINED $type $odev";
}
my $def = $defptr{$dev};
my (@v, @txt, @sfx);
if($type eq "HMS100TF") {
@txt = ( "temperature", "humidity", "battery");
@sfx = ( "(Celsius)", "(%)", "");
# Codierung <s1><s0><t1><t0><f0><t2><f2><f1>
my $status = hex(substr($val, 0, 1));
$v[0] = int(substr($val, 5, 1) . substr($val, 2, 2))/10;
$v[1] = int(substr($val, 6, 2) . substr($val, 4, 1))/10;
$v[2] = "ok";
if ( $status & 2 ) { $v[2] = "empty"; }
if ( $status & 4 ) { $v[2] = "replaced"; }
if ( $status & 8 ) { $v[0] = -$v[0]; }
$val = "T: $v[0] H: $v[1] Bat: $v[2]";
} elsif ($type eq "HMS100T") {
@txt = ( "temperature", "battery");
@sfx = ( "(Celsius)", "");
my $status = hex(substr($val, 0, 1));
$v[0] = int(substr($val, 5, 1) . substr($val, 2, 2))/10;
$v[1] = "ok";
if ( $status & 2 ) { $v[1] = "empty"; }
if ( $status & 4 ) { $v[1] = "replaced"; }
if ( $status & 8 ) { $v[0] = -$v[0]; }
$val = "T: $v[0] Bat: $v[1]";
} elsif ($type eq "HMS100WD") {
@txt = ( "water_detect", "battery");
@sfx = ( "", "");
# Battery-low condition detect is not yet properly
# implemented. As soon as my WD's batteries get low
# I am willing to supply a patch ;-) SEP7-RIPE, 2006/05/13
my $status = hex(substr($val, 1, 1));
$v[1] = "ok";
$v[0] = "off";
if ( $status & 1 ) { $v[0] = "on"; }
$val = "Water Detect: $v[0]";
} elsif ($type eq "HMS100TFK") { # By Peter P.
@txt = ( "switch_detect", "battery");
@sfx = ( "", "");
# Battery-low condition detect is not yet properly implemented.
my $status = hex(substr($val, 1, 1));
$v[0] = ($status ? "on" : "off");
$v[1] = "off";
$val = "Switch Detect: $v[0]";
} elsif($type eq "RM100-2") {
@txt = ( "smoke_detect", "battery");
@sfx = ( "", "");
$v[0] = ( hex(substr($val, 1, 1)) != "0" ) ? "on" : "off";
$v[1] = "unknown"; # Battery-low detect is _NOT_ implemented.
$val = "smoke_detect: $v[0]";
} elsif ($type eq "HMS100MG") { # By Peter Stark
@txt = ( "gas_detect", "battery");
@sfx = ( "", "");
# Battery-low condition detect is not yet properly
# implemented.
my $status = hex(substr($val, 1, 1));
$v[0] = ($status != "0") ? "on" : "off";
$v[1] = "off";
if ($status & 1) { $v[0] = "on"; }
$val = "Gas Detect: $v[0]";
} else {
Log 4, "HMS Device $dev (Unknown type: $type)";
return "";
}
my $now = TimeNow();
Log 4, "HMS Device $dev ($type: $val)";
my $max = int(@txt);
for( my $i = 0; $i < $max; $i++) {
$readings{$dev}{$txt[$i]}{TIM} = $now;
my $v = "$v[$i] $sfx[$i]";
$readings{$dev}{$txt[$i]}{VAL} = $v;
$def->{CHANGED}[$i] = "$txt[$i]: $v";
}
$readings{$dev}{type}{TIM} = $now;
$readings{$dev}{type}{VAL} = $type;
$def->{STATE} = $val;
$def->{CHANGED}[$max] = $val;
return $def->{NAME};
}
1;

View File

@ -1,308 +0,0 @@
##############################################
package main;
use strict;
use warnings;
my %readings;
my %defptr;
my $negcount = 0;
######################
# Note: this is just an empty hull.
#####################################
sub
KS300_Initialize($)
{
my ($hash) = @_;
# Message is like
# 810d04f94027a00171212730000008
# 81 0d 04 f9 4027a00171 212730000008
$hash->{Category} = "DEV";
$hash->{Match} = "^810.04..402.a001";
$hash->{SetFn} = "KS300_Set";
$hash->{GetFn} = "KS300_Get";
$hash->{StateFn} = "KS300_SetState";
$hash->{ListFn} = "KS300_List";
$hash->{DefFn} = "KS300_Define";
$hash->{UndefFn} = "KS300_Undef";
$hash->{ParseFn} = "KS300_Parse";
}
###################################
sub
KS300_Set($@)
{
my ($hash, @a) = @_;
return "No set function implemented";
}
###################################
sub
KS300_Get($@)
{
my ($hash,@a) = @_;
return "No get function implemented";
}
#####################################
sub
KS300_SetState($$$$)
{
my ($hash, $tim, $vt, $val) = @_;
my $n = $hash->{CODE};
if(!$readings{$n}{$vt} || $readings{$n}{$vt}{TIM} lt $tim) {
$readings{$n}{$vt}{TIM} = $tim;
$readings{$n}{$vt}{VAL} = $val;
}
return undef;
}
#####################################
sub
KS300_List($)
{
my ($hash) = @_;
my $str = "";
my $n = $hash->{CODE};
if(!defined($readings{$n})) {
$str .= "No information about " . $hash->{NAME} . "\n";
} else {
foreach my $m (keys %{ $readings{$n} }) {
$str .= sprintf("%-19s %-15s %s\n",
$readings{$n}{$m}{TIM}, $m, $readings{$n}{$m}{VAL});
}
}
return $str;
}
#####################################
sub
KS300_Define($@)
{
my ($hash, @a) = @_;
return "wrong syntax: define <name> KS300 <code> " .
"[ml/raincounter] [wind-factor]" if(int(@a) < 3 || int(@a) > 5);
$a[2] = lc($a[2]);
return "Define $a[0]: wrong CODE format: specify a 4 digit hex value"
if($a[2] !~ m/^[a-f0-9][a-f0-9][a-f0-9][a-f0-9]$/);
$hash->{CODE} = $a[2];
my $rainunit = ((int(@a) > 3) ? $a[3] : 255);
my $windunit = ((int(@a) > 4) ? $a[4] : 1.0);
$hash->{CODE} = $a[2];
$hash->{RAINUNIT} = $rainunit;
$hash->{WINDUNIT} = $windunit;
$defptr{$a[2]} = $hash;
return undef;
}
#####################################
sub
KS300_Undef($$)
{
my ($hash, $name) = @_;
delete($defptr{$hash->{CODE}});
return undef;
}
#####################################
sub
KS300_Parse($)
{
my ($hash,$msg) = @_;
if($msg !~ m/^810d04..4027a001/) {
Log 4, "KS300 unknown message $msg";
return "";
}
###############################
# 1 2
#0123456789012345 67890123456789
#
#810d04f94027a001 71212730000008
###############################
my @a = split("", $msg);
##########################
# I've seldom (1 out of 700) seen messages of length 10 and 11 with correct
# CRC, they seem to contain partial data (e.g. temp/wind/hum but not rain)
# They are suppressed as of now.
if(hex($a[3]) != 13) {
Log 4, "Strange KS400 message received, wont decode ($msg)";
return "";
}
if(int(keys %defptr)) {
my @arr = keys(%defptr); # No code is known yet
my $dev = shift(@arr);
my $def = $defptr{$dev};
my $haverain = 0;
my @v;
my @txt = ( "rain_raw", "rain", "wind", "humidity", "temperature",
"israining", "unknown1", "unknown2", "unknown3");
my @sfx = ( "(counter)", "(l/m2)", "(km/h)", "(%)", "(Celsius)",
"(yes/no)", "","","");
# The next instr wont work for empty hashes, so we init it now
$readings{$dev}{$txt[0]}{VAL} = 0 if(!$readings{$dev});
my $r = $readings{$dev};
$v[0] = hex("$a[28]$a[27]$a[26]");
#############################
# My KS300 sends a (quite huge) "negative" rain, when the rain begins,
# then the value is "normal" again. So we have to filter neg. rain out.
# But if the KS300 is sending this value more than once, then accept it,
# as the KS300 was probably reset
if($r->{rain_raw}{VAL}) {
my ($rrv, undef) = split(" ", $r->{rain_raw}{VAL});
$haverain = 1 if($v[0] != $rrv);
if($v[0] < $rrv) {
if($negcount++ < 3) {
Log 3, "KS300 negative rain, ignoring it";
$v[0] = $rrv;
} else {
Log 1, "KS300 was probably reset, accepting new rain value";
}
} else {
$negcount = 0;
}
}
$v[1] = sprintf("%0.1f", $v[0] * $def->{RAINUNIT} / 1000);
$v[2] = sprintf("%0.1f", ("$a[25]$a[24].$a[23]"+0) * $def->{WINDUNIT});
$v[3] = "$a[22]$a[21]" + 0;
$v[4] = "$a[20]$a[19].$a[18]" + 0; $v[4] = "-$v[4]" if($a[17] eq "7");
$v[4] = sprintf("%0.1f", $v[4]);
$v[5] = ((hex($a[17]) & 0x2) || $haverain) ? "yes" : "no";
$v[6] = $a[29];
$v[7] = $a[16];
$v[8] = $a[17];
# Negative temp
$v[4] = -$v[4] if($v[8] & 8);
my $tm = TimeNow();
Log 4, "KS300 $dev: $msg";
my $max = int(@v);
for(my $i = 0; $i < $max; $i++) {
$r->{$txt[$i]}{TIM} = $tm;
my $val = "$v[$i] $sfx[$i]";
$r->{$txt[$i]}{VAL} = $val;
$def->{CHANGED}[$i] = "$txt[$i]: $val";
}
# For logging/summary
my $val = "T: $v[4] H: $v[3] W: $v[2] R: $v[1] IR: $v[5]";
$def->{STATE} = $val;
$def->{CHANGED}[$max++] = $val;
###################################
# AVG computing
if(!$r->{cum_day}) {
$r->{cum_day}{VAL} = "$tm T: 0 H: 0 W: 0 R: $v[1]";
$r->{avg_day}{VAL} = "T: $v[4] H: $v[3] W: $v[2] R: $v[1]";
} else {
my @cv = split(" ", $r->{cum_day}{VAL});
my @cd = split("[ :-]", $r->{cum_day}{TIM});
my $csec = 3600*$cd[3] + 60*$cd[4] + $cd[5]; # Sec of last reading
my @d = split("[ :-]", $tm);
my $sec = 3600*$d[3] + 60*$d[4] + $d[5]; # Sec now
my @sd = split("[ :-]", "$cv[0] $cv[1]");
my $ssec = 3600*$sd[3] + 60*$sd[4] + $sd[5]; # Sec at start of day
my $difft = $sec - $csec;
$difft += 86400 if($d[2] != $cd[2]); # Sec since last reading
my $t = $cv[3] + $difft * $v[4];
my $h = $cv[5] + $difft * $v[3];
my $w = $cv[7] + $difft * $v[2];
my $e = $cv[9];
$r->{cum_day}{VAL} = "$cv[0] $cv[1] T: $t H: $h W: $w R: $e";
$difft = $sec - $ssec;
$difft += 86400 if($d[2] != $sd[2]); # Sec since last reading
$t /= $difft; $h /= $difft; $w /= $difft; $e = $v[1] - $cv[9];
$r->{avg_day}{VAL} =
sprintf("T: %.1f H: %d W: %.1f R: %.1f", $t, $h, $w, $e);
if($d[2] != $sd[2]) { # Day changed, report it
$def->{CHANGED}[$max++] = "avg_day $r->{avg_day}{VAL}";
$r->{cum_day}{VAL} = "$tm T: 0 H: 0 W: 0 R: $v[1]";
if(!$r->{cum_month}) { # Check the month
$r->{cum_month}{VAL} = "1 $r->{avg_day}{VAL}";
$r->{avg_month}{VAL} = $r->{avg_day}{VAL};
} else {
my @cmv = split(" ", $r->{cum_month}{VAL});
$t += $cmv[2]; $w += $cmv[4]; $h += $cmv[6];
$cmv[0]++;
$r->{cum_month}{VAL} =
sprintf("%d T: %.1f H: %d W: %.1f R: %.1f",
$cmv[0], $t, $h, $w, $cmv[8]+$e);
$r->{avg_month}{VAL} =
sprintf("T: %.1f H: %d W: %.1f R: %.1f",
$t/$cmv[0], $h/$cmv[0], $w/$cmv[0], $cmv[8]+$e);
if($d[1] != $sd[1]) { # Month changed, report it
$def->{CHANGED}[$max++] = "avg_month $r->{avg_month}{VAL}";
$r->{cum_month}{VAL} = "0 T: 0 H: 0 W: 0 R: 0";
}
}
$r->{cum_month}{TIM} = $r->{avg_month}{TIM} = $tm;
}
}
$r->{cum_day}{TIM} = $r->{avg_day}{TIM} = $tm;
# AVG computing
###################################
return $def->{NAME};
} else {
Log 4, "KS300 detected: $msg";
}
return "";
}
1;

View File

@ -39,7 +39,6 @@ package main;
use strict;
use warnings;
my %readings;
my %defptr;
my $DeviceName="";
my $inbuf="";
@ -64,8 +63,6 @@ WS300_Initialize($)
{
my ($hash) = @_;
$hash->{Category} = "DEV";
# Provider
$hash->{Clients} = ":WS300:";
$hash->{ReadFn} = "WS300_Read";
@ -74,12 +71,11 @@ WS300_Initialize($)
$hash->{Match} = "^WS300.*";
$hash->{SetFn} = "WS300_Set";
$hash->{GetFn} = "WS300_Get";
$hash->{StateFn} = "WS300_SetState";
$hash->{ListFn} = "WS300_List";
$hash->{DefFn} = "WS300_Define";
$hash->{UndefFn} = "WS300_Undef";
$hash->{ParseFn} = "WS300_Parse";
$hash->{ReadFn} = "WS300_Read";
$hash->{AttrList} = "do_not_notify:0,1 showtime:0,1 model:ws300 loglevel:0,1,2,3,4,5,6";
}
###################################
@ -101,7 +97,7 @@ WS300_Set($@)
###################################
sub
WS300_Get(@)
{
{
my ($hash, @a) = @_;
if($hash->{NAME} eq "WS300Device")
{
@ -114,64 +110,27 @@ WS300_Get(@)
#####################################
sub
WS300_SetState($$$$)
WS300_Define($$)
{
my ($hash, $tim, $vt, $val) = @_;
return undef if(!defined($hash->{SENSOR}));
my $n = $hash->{SENSOR};
if(!$readings{$n}{$vt} || $readings{$n}{$vt}{TIM} lt $tim) {
$readings{$n}{$vt}{TIM} = $tim;
$readings{$n}{$vt}{VAL} = $val;
}
return undef;
}
#####################################
sub
WS300_List($)
{
my ($hash) = @_;
my $str = "";
return "No information about $hash->{NAME}" if(!defined($hash->{SENSOR}));
my $n = $hash->{SENSOR};
if(!defined($readings{$n}))
{
$str .= "No information about " . $hash->{NAME} . "\n";
}
else
{
foreach my $m (keys %{ $readings{$n} })
{
$str .= sprintf("%-19s %-15s %s\n",$readings{$n}{$m}{TIM}, $m, $readings{$n}{$m}{VAL});
}
}
return $str;
}
#####################################
sub
WS300_Define($@)
{
my ($hash, @a) = @_;
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
if($a[0] eq "WS300Device")
{
$defptr{10} = $hash;
return "wrong syntax: define WS300Device WS300 <DeviceName>" if(int(@a) < 3);
$DeviceName = $a[2];
$hash->{STATE} = "Initializing";
$hash->{SENSOR} = 10;
$readings{10}{WS300Device}{VAL} = "Initializing";
$readings{10}{WS300Device}{TIM} = TimeNow;
$hash->{READINGS}{WS300Device}{VAL} = "Initializing";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
my $po = new Device::SerialPort ($a[2]);
if(!$po)
{
$hash->{STATE} = "error opening device";
$readings{10}{WS300Device}{VAL} = "error opening device";
$readings{10}{WS300Device}{TIM} = TimeNow;
$hash->{READINGS}{WS300Device}{VAL} = "error opening device";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
Log 1,"Error opening WS300 Device $a[2]";
return "Can't open $a[2]: $!\n";
}
@ -188,15 +147,15 @@ WS300_Define($@)
$hash->{PortObj} = $po;
$hash->{DeviceName} = $a[2];
$hash->{STATE} = "opened";
$readings{10}{WS300Device}{VAL} = "opened";
$readings{10}{WS300Device}{TIM} = TimeNow;
CommandAt($hash,"+*00:00:05 get WS300Device data");
$hash->{READINGS}{WS300Device}{VAL} = "opened";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
CommandDefine(undef,"WS300Device_timer at +*00:00:05 get WS300Device data");
Log 1,"WS300 Device $a[2] opened";
$attr{$a[0]}{savefirst} = 1;
return undef;
}
return "wrong syntax: define <name> WS300 <sensor (0-9)>\n0-7=ASH2200\n8=KS300\n9=WS300" if(int(@a) < 3);
return "no device: define WS300Device WS300 <DeviceName> first" if($DeviceName eq "");
$a[2] = lc($a[2]);
return "Define $a[0]: wrong sensor number." if($a[2] !~ m/^[0-9]$/);
$hash->{SENSOR} = $a[2];
$defptr{$a[2]} = $hash;
@ -294,9 +253,10 @@ WS300_Parse($)
}
else
{
$readings{$s}{$txt[0]}{VAL} = 0 if(!$readings{$s});
$ref = $readings{$s};
$def = $defptr{$s};
$def->{READINGS}{$txt[0]}{VAL} = 0 if(!$def->{READINGS});
$ref = $def->{READINGS};
$t = hex($a[$p].$a[$p+1].$a[$p+2].$a[$p+3]);
$t -= 65535 if( $t > 32767 );
$t /= 10.0;
@ -318,25 +278,25 @@ WS300_Parse($)
$def->{CHANGED}[0] = $val;
$def->{CHANGETIME}[0] = $tm;
# temperatur
$ref->{$txt[0]}{TIM} = $tm;
$ref->{$txt[0]}{TIME} = $tm;
$value = "$t $sfx[0]";
$ref->{$txt[0]}{VAL} = $value;
$def->{CHANGED}[1] = "$txt[0]: $value";
$def->{CHANGETIME}[1] = $tm;
# humidity
$ref->{$txt[1]}{TIM} = $tm;
$ref->{$txt[1]}{TIME} = $tm;
$value = "$h $sfx[1]";
$ref->{$txt[1]}{VAL} = $value;
$def->{CHANGED}[2] = "$txt[1]: $value";
$def->{CHANGETIME}[2] = $tm;
# battery
$ref->{$txt[5]}{TIM} = $tm;
$ref->{$txt[5]}{TIME} = $tm;
$value = "$b $sfx[5]";
$ref->{$txt[5]}{VAL} = $value;
$def->{CHANGED}[3] = "$txt[5]: $value";
$def->{CHANGETIME}[3] = $tm;
# lost receives
$ref->{$txt[6]}{TIM} = $tm;
$ref->{$txt[6]}{TIME} = $tm;
$value = "$l $sfx[6]";
$ref->{$txt[6]}{VAL} = $value;
$def->{CHANGED}[4] = "$txt[6]: $value";
@ -353,49 +313,49 @@ WS300_Parse($)
$def->{CHANGED}[0] = $val;
$def->{CHANGETIME}[0] = $tm;
# temperature
$ref->{$txt[0]}{TIM} = $tm;
$ref->{$txt[0]}{TIME} = $tm;
$value = "$t $sfx[0]";
$ref->{$txt[0]}{VAL} = $value;
$def->{CHANGED}[1] = "$txt[0]: $value";
$def->{CHANGETIME}[1] = $tm;
# humidity
$ref->{$txt[1]}{TIM} = $tm;
$ref->{$txt[1]}{TIME} = $tm;
$value = "$h $sfx[1]";
$ref->{$txt[1]}{VAL} = $value;
$def->{CHANGED}[2] = "$txt[1]: $value";
$def->{CHANGETIME}[2] = $tm;
# wind
$ref->{$txt[2]}{TIM} = $tm;
$ref->{$txt[2]}{TIME} = $tm;
$value = "$wind $sfx[2]";
$ref->{$txt[2]}{VAL} = $value;
$def->{CHANGED}[3] = "$txt[2]: $value";
$def->{CHANGETIME}[3] = $tm;
#rain counter
$ref->{$txt[3]}{TIM} = $tm;
$ref->{$txt[3]}{TIME} = $tm;
$value = "$rainc $sfx[3]";
$ref->{$txt[3]}{VAL} = $value;
$def->{CHANGED}[4] = "$txt[3]: $value";
$def->{CHANGETIME}[4] = $tm;
# is raining
$ref->{$txt[4]}{TIM} = $tm;
$ref->{$txt[4]}{TIME} = $tm;
$value = "$ir $sfx[4]";
$ref->{$txt[4]}{VAL} = $value;
$def->{CHANGED}[5] = "$txt[4]: $value";
$def->{CHANGETIME}[5] = $tm;
# battery
$ref->{$txt[5]}{TIM} = $tm;
$ref->{$txt[5]}{TIME} = $tm;
$value = "$b $sfx[5]";
$ref->{$txt[5]}{VAL} = $value;
$def->{CHANGED}[6] = "$txt[5]: $value";
$def->{CHANGETIME}[6] = $tm;
# lost receives
$ref->{$txt[6]}{TIM} = $tm;
$ref->{$txt[6]}{TIME} = $tm;
$value = "$l $sfx[6]";
$ref->{$txt[6]}{VAL} = $value;
$def->{CHANGED}[7] = "$txt[6]: $value";
$def->{CHANGETIME}[7] = $tm;
# rain cumulative
$ref->{$txt[8]}{TIM} = $tm;
$ref->{$txt[8]}{TIME} = $tm;
$value = "$rain $sfx[8]";
$ref->{$txt[8]}{VAL} = $value;
$def->{CHANGED}[8] = "$txt[8]: $value";
@ -417,17 +377,17 @@ WS300_Parse($)
$rain_hour = sprintf("%.1f",$rain_hour);
$rain_day = sprintf("%.1f",$rain_day);
$rain_month = sprintf("%.1f",$rain_month);
$ref->{acthour}{TIM} = $tm;
$ref->{acthour}{TIME} = $tm;
$ref->{acthour}{VAL} = "$acthour";
$ref->{$txt[9]}{TIM} = $tm;
$ref->{$txt[9]}{TIME} = $tm;
$ref->{$txt[9]}{VAL} = $rain_hour;
$def->{CHANGED}[9] = "$txt[9]: $rain_hour $sfx[9]";
$def->{CHANGETIME}[9] = $tm;
$ref->{$txt[10]}{TIM} = $tm;
$ref->{$txt[10]}{TIME} = $tm;
$ref->{$txt[10]}{VAL} = $rain_day;
$def->{CHANGED}[10] = "$txt[10]: $rain_day $sfx[10]";
$def->{CHANGETIME}[10] = $tm;
$ref->{$txt[11]}{TIM} = $tm;
$ref->{$txt[11]}{TIME} = $tm;
$ref->{$txt[11]}{VAL} = $rain_month;
$def->{CHANGED}[11] = "$txt[11]: $rain_month $sfx[11]";
$def->{CHANGETIME}[11] = $tm;
@ -436,14 +396,14 @@ WS300_Parse($)
if($actday != $lt[3])
{
$actday = $lt[3];
$ref->{actday}{TIM} = $tm;
$ref->{actday}{TIME} = $tm;
$ref->{actday}{VAL} = "$actday";
$rain_day=0;
}
if($actmonth != $lt[4]+1)
{
$actmonth = $lt[4]+1;
$ref->{actmonth}{TIM} = $tm;
$ref->{actmonth}{TIME} = $tm;
$ref->{actmonth}{VAL} = "$actmonth";
$rain_month=0;
}
@ -457,17 +417,17 @@ WS300_Parse($)
$rain_month = sprintf("%.1f",$rain_month);
$oldrain = $rain;
$ref->{acthour}{TIM} = $tm;
$ref->{acthour}{TIME} = $tm;
$ref->{acthour}{VAL} = "$acthour";
$ref->{$txt[9]}{TIM} = $tm;
$ref->{$txt[9]}{TIME} = $tm;
$ref->{$txt[9]}{VAL} = $rain_hour;
$def->{CHANGED}[9] = "$txt[9]: $rain_hour $sfx[9]";
$def->{CHANGETIME}[9] = $tm;
$ref->{$txt[10]}{TIM} = $tm;
$ref->{$txt[10]}{TIME} = $tm;
$ref->{$txt[10]}{VAL} = $rain_day;
$def->{CHANGED}[10] = "$txt[10]: $rain_day $sfx[10]";
$def->{CHANGETIME}[10] = $tm;
$ref->{$txt[11]}{TIM} = $tm;
$ref->{$txt[11]}{TIME} = $tm;
$ref->{$txt[11]}{VAL} = $rain_month;
$def->{CHANGED}[11] = "$txt[11]: $rain_month $sfx[11]";
$def->{CHANGETIME}[11] = $tm;
@ -484,9 +444,10 @@ WS300_Parse($)
}
else
{
$readings{9}{$txt[0]}{VAL} = 0 if(!$readings{9});
$ref = $readings{9};
$def = $defptr{9};
$def->{READINGS}{$txt[0]}{VAL} = 0 if(!$def->{READINGS});
$ref = $def->{READINGS};
$t = hex($a[62+$offs].$a[63+$offs].$a[64+$offs].$a[65+$offs]);
$t -= 65535 if( $t > 32767 );
$t /= 10.0;
@ -497,25 +458,25 @@ WS300_Parse($)
$def->{CHANGED}[0] = $val;
$def->{CHANGETIME}[0] = $tm;
# temperature
$ref->{$txt[0]}{TIM} = $tm;
$ref->{$txt[0]}{TIME} = $tm;
$value = "$t $sfx[0]";
$ref->{$txt[0]}{VAL} = $value;
$def->{CHANGED}[1] = "$txt[0]: $value";
$def->{CHANGETIME}[1] = $tm;
# humidity
$ref->{$txt[1]}{TIM} = $tm;
$ref->{$txt[1]}{TIME} = $tm;
$value = "$h $sfx[1]";
$ref->{$txt[1]}{VAL} = $value;
$def->{CHANGED}[2] = "$txt[1]: $value";
$def->{CHANGETIME}[2] = $tm;
# pressure
$ref->{$txt[7]}{TIM} = $tm;
$ref->{$txt[7]}{TIME} = $tm;
$value = "$press $sfx[7]";
$ref->{$txt[7]}{VAL} = $value;
$def->{CHANGED}[3] = "$txt[7]: $value";
$def->{CHANGETIME}[3] = $tm;
# willi
$ref->{willi}{TIM} = $tm;
$ref->{willi}{TIME} = $tm;
$value = "$willi";
$ref->{willi}{VAL} = $value;
$def->{CHANGED}[4] = "willi: $value";
@ -569,8 +530,8 @@ NEXTPOLL:
Log 1, "USB device $devname disconnected, waiting to reappear";
$hash->{PortObj}->close();
$hash->{STATE} = "disconnected";
$readings{10}{WS300Device}{VAL} = "disconnected";
$readings{10}{WS300Device}{TIM} = TimeNow;
$hash->{READINGS}{WS300Device}{VAL} = "disconnected";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
sleep(1);
my $po = new Device::SerialPort($devname);
if($po)
@ -588,8 +549,8 @@ NEXTPOLL:
Log 1, "USB device $devname reappeared";
$hash->{PortObj} = $po;
$hash->{STATE} = "opened";
$readings{10}{WS300Device}{VAL} = "opened";
$readings{10}{WS300Device}{TIM} = TimeNow;
$hash->{READINGS}{WS300Device}{VAL} = "opened";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
$polling=0;
return;
}
@ -651,8 +612,8 @@ NEXTPOLL:
if($errcount == 10)
{
$hash->{STATE} = "timeout";
$readings{10}{WS300Device}{VAL} = "timeout";
$readings{10}{WS300Device}{TIM} = TimeNow;
$hash->{READINGS}{WS300Device}{VAL} = "timeout";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
$errcount++;
}
Log 1,"WS300: no data" if($rcount == 0);
@ -663,8 +624,8 @@ NEXTPOLL:
if($hash->{STATE} ne "connected" && $errcount > 10)
{
$hash->{STATE} = "connected";
$readings{10}{WS300Device}{VAL} = "connected";
$readings{10}{WS300Device}{TIM} = TimeNow;
$hash->{READINGS}{WS300Device}{VAL} = "connected";
$hash->{READINGS}{WS300Device}{TIME} = TimeNow;
}
$errcount = 0;
$ic = ord(substr($inbuf,0,1));

View File

@ -1,97 +0,0 @@
##############################################
package main;
use strict;
use warnings;
use IO::File;
#####################################
sub
FileLog_Initialize($)
{
my ($hash) = @_;
$hash->{Category}= "LOG";
$hash->{DefFn} = "FileLog_Define";
$hash->{UndefFn} = "FileLog_Undef";
$hash->{LogFn} = "FileLog_Log";
}
#####################################
sub
FileLog_Define($@)
{
my ($hash, @a) = @_;
my $fh;
return "wrong syntax: define <name> FileLog filename regexp" if(int(@a) != 4);
eval { "Hallo" =~ m/^$a[3]$/ };
return "Bad regexp: $@" if($@);
my @t = localtime;
my $f = ResolveDateWildcards($a[2], @t);
$fh = new IO::File ">>$f";
return "Can't open $f" if(!defined($fh));
$hash->{FH} = $fh;
$hash->{REGEXP} = $a[3];
$hash->{FILENAME} = $a[2];
$hash->{CURRENT} = $f;
return undef;
}
#####################################
sub
FileLog_Undef($$)
{
my ($hash, $name) = @_;
close($hash->{FH});
return undef;
}
#####################################
sub
FileLog_Log($$)
{
my ($log, $dev) = @_;
my $n = $dev->{NAME};
my $re = $log->{REGEXP};
my $max = int(@{$dev->{CHANGED}});
for (my $i = 0; $i < $max; $i++) {
my $s = $dev->{CHANGED}[$i];
$s = "" if(!defined($s));
if($n =~ m/^$re$/ || "$n:$s" =~ m/^$re$/) {
my $t = TimeNow();
$t = $dev->{CHANGETIME}[$i] if(defined($dev->{CHANGETIME}[$i]));
$t =~ s/ /_/;
my $fh = $log->{FH};
my @t = localtime;
my $cn = ResolveDateWildcards($log->{FILENAME}, @t);
if($cn ne $log->{CURRENT}) { # New logfile
$fh->close();
$fh = new IO::File ">>$cn";
if(!defined($fh)) {
Log(0, "Can't open $cn");
return;
}
$log->{CURRENT} = $cn;
$log->{FH} = $fh;
}
print $fh "$t $n $s\n";
$fh->flush;
$fh->sync;
}
}
}
1;

View File

@ -15,6 +15,40 @@
- Added doc/linux.html (multiple USDB devices, udev links)
- Linked fhem.html and commandref.html to linux.html
- rudi, Sun Mar 4 11:18:10 MET 2007
Reorganization. Goal: making attribute adding/deleting more uniform
("at/notify" and other device differences), and making web-configuration
possible (i.e. saving the configfile, list of possible devices etc).
Internal changes:
- %logmods,%devmods moved to %modules. Makes things more uniform
- %logs merged into %defs
- local state info (%readings) changed to global ($defs{$d}{READINGS})
-> No need for the listfn function in each module
-> User written scripts can more easily analyze device states
User visible changes:
- at/notify "renamed" to "define <name> at/notify", both moved to external
modules. Now it is possible
- to have a further "at" or "notify" modules
(notify & filelog use the same interface)
- to have more than one notify for the same event
- to delete at commands without strange escapes.
The delete syntax changed (no more def/at/ntfy needed)
- at/notify can have attributes
Drawback: each at and notify must have a name, which is strange first.
- logfile/modpath/pidfile/port/verbose "renamed" to "attr global xxx"
Dumping and extending these attributes is easier, no special handling
required in the web-frontend.
- savefile renamed to "attr global statefile"
- configfile global attribute added.
- save command added, it writes the statefile and then the configfile.
- delattr added to delete single attributes
- list/xmllist format changed, they contain more information.
- "define/set/get/attr name ?" returns a list of possible arguments
in the same format. This data is contained in the xmllist.
- disable attribute for at/notify/filelog
- Martin Haas, Fri Feb 23 10:18 MET 2007
- ARM-Section (NSLU2) added to doc/linux.html

View File

@ -32,8 +32,6 @@ DbLog_Initialize($)
{
my ($hash) = @_;
$hash->{Category} = "none";
# Lets connect here, so we see the error at startup
DbConnect();
}

View File

@ -31,8 +31,7 @@ use warnings;
sub
ALARM_Initialize($$)
{
my ($hash, $init) = @_;
$hash->{Type} = "none";
my ($hash) = @_;
}

View File

@ -30,8 +30,6 @@ sub
SUNRISE_Initialize($)
{
my ($hash) = @_;
$hash->{Category} = "none";
}

View File

@ -246,9 +246,10 @@ getDevStatus()
printf(" Nr devs (off 05): %d\n", b($d,6));
printf(" puls/5min (off 13): %d\n", w($d,13));
printf(" Startblk (off 18): %d\n", b($d,18)+13);
printf(" Alarm, PA (off 45): %d W\n", w($d,45));
printf(" PRICE, CF (off 47): %0.2f (EUR/KWH)\n", w($d,47)/10000);
printf(" R/KW, EC (off 49): %d\n", w($d,49)/10);
printf(" cur.power (off 33): %.3f kW\n", w($d,33) * 2 / 300);
printf(" Alarm PA (off 45): %d W\n", w($d,45));
printf(" Price CF (off 47): %0.2f (EUR/KWH)\n", w($d,47)/10000);
printf(" R/KW EC (off 49): %d\n", w($d,49)/10);
hexdump($d);
}
@ -268,6 +269,8 @@ getDevPage()
sub
getDevData()
{
my $smooth = 1; # Set this to 0 to get the "real" values
die "Usage: getDevData devicenumber (1-12)\n" if(@ARGV != 3);
my $d = getData(sprintf("7a%02x",$ARGV[2]-1));
@ -284,23 +287,39 @@ getDevData()
my $step = b($d,6);
my $start = b($d,18)+13;
my $end = $start + int(($nrreadings-1)/64)*$step;
my $offset = ($nrreadings%64)*4+4;
my $div = w($d,49)/10;
$div = 1 if($div == 0);
#printf("Total $nrreadings, $start - $end, Nr $step, Off: $offset\n");
#printf("Total $nrreadings, $start - $end, Nr $step\n");
my $now = time();
for(my $p = $end; $p >= $start; $p -= $step) {
my $tm = time()-(($nrreadings-1)*300);
my $backlog = 0;
for(my $p = $start; $p <= $end; $p += $step) {
#printf("Get page $p\n");
$d = getData(sprintf("52%02x%02x00000801", $p%256, int($p/256)));
#hexdump($d);
$offset = 260 if($p != $end);
while($offset >= 8) {
printf("%s %0.3f kWh (%d)\n",
maketime($now), w($d,$offset)*12/$div, w($d,$offset+2));
$offset -=4;
$now -= 300;
my $max = (($p == $end) ? ($nrreadings%64)*4+4 : 260);
my $step = b($d, 6);
for(my $off = 8; $off <= $max; $off += 4) {
$backlog++;
if($smooth && (w($d,$off+2) == 0xffff)) { # "smoothing"
next;
} else {
my $v = w($d,$off)*12/$div/$backlog;
my $f1 = b($d,$off+2);
my $f2 = b($d,$off+3);
my $f3 = w($d,$off+2);
while($backlog--) {
printf("%s %0.3f kWh (%d %d %d)\n", maketime($tm), $v,
($backlog?-1:$f1), ($backlog?-1:$f2), ($backlog?-1:$f3));
$tm += 300;
}
$backlog = 0;
}
}
}
}
@ -378,9 +397,12 @@ setTime()
my @d = split("-", $ARGV[2]);
my @t = split(":", $ARGV[3]);
my $d = getData(sprintf("73%02x%02x%02x00%02x%02x%02x",
my $s = sprintf("73%02x%02x%02x00%02x%02x%02x",
$d[2],$d[1],$d[0]-2000+0xd0,
$t[0],$t[1],$2[2]));
$t[0],$t[1],$t[2]);
print("-> $s\n");
my $d = getData($s);
if(b($d,0) == 6) {
print("OK");
} else {

View File

@ -5,11 +5,11 @@
# o'clock then the at-job for going down by sunset will be deleted
# put something like the following into your fhz100.cfg:
# notifyon rolwzo /usr/local/bin/rolwzo_not_off.sh
# define rolzwo_not_off notify rolwzo /usr/local/bin/rolwzo_not_off.sh
FHZ="/usr/local/bin/fhem.pl 7072"
order="delete at set rolwzo off"
order="delete rolwzo_off"
DATESTRING=`date +"%H"`
[[ $DATESTRING > 16 ]] && $FHZ "$order"

File diff suppressed because it is too large Load Diff

View File

@ -116,7 +116,7 @@ Please add day/month/weekday to it.</b>
<b>I defined my FS20STR as an FHT device, but I do not get any data from it.</b>
<ul>
The FS20STR is an FS20 device, even if it looks like an FHT80b.
You'll get "only" on-for-timer and off-fot-timer events sent.
You'll get "only" on-for-timer and off-for-timer events sent.
</ul>
<b>How to convert the FHT8b code seen in its display to the hex code needed by fhem.pl?</b>

View File

@ -14,3 +14,6 @@ where <code> is one of:
810e04d70213a001b16d000000000000 RM100-2 smoke off
81xx04xx0101a00180c2030011 FS20 dev: 1234 button: 03 on (11)
To send it:
set FHZ raw 04 0101a00180c2030011

View File

@ -7,12 +7,12 @@
#
# Common part
logfile /tmp/fhem-%Y-%m.log
savefile /tmp/fhem.save # where to save the state of the devices
verbose 3 # "normal" verbosity (min 1, max 5)
port 7072 # our TCP/IP port (working from localhost only)
modpath . # where our FHEM directory is
attr global logfile /tmp/fhem-%Y-%m.log
attr global statefile /tmp/fhem.save # where to save the state of the devices
attr global verbose 3 # "normal" verbosity (min 1, max 5)
attr global port 7072 # our TCP/IP port (localhost only)
attr global modpath . # where our FHEM directory is
define FHZ FHZ /dev/tts/USB0 # the serial port of an FHZ 1000 PC
define lamp FS20 8765 01 # type FS20, transmitter code 8765, button 2

View File

@ -9,13 +9,13 @@
# Common part
logfile /tmp/fhem-%Y-%m.log
savefile /tmp/fhem.save # where to save the state of the devices
verbose 3 # "normal" verbosity
port 7072 # our TCP/IP port (working from localhost only)
modpath . # where our FHEM directory is
define FHZ FHZ /dev/tts/USB0 # the serial port of an FHZ 1000 PC
attr global logfile /tmp/fhem-%Y-%m.log
attr global statefile /tmp/fhem.save # where to save the state of the devices
attr global verbose 3 # "normal" verbosity
attr global port 7072 # our TCP/IP port (localhost only)
attr global modpath . # where our FHEM directory is
define FHZ FHZ /dev/tts/USB0 # the serial port of an FHZ 1000 PC
define roll1 FS20 7777 02 # type FS20, transmitter code 7777, button 3
define roll2 FS20 7777 03 # type FS20, transmitter code 7777, button 4
@ -31,16 +31,16 @@ notifyon btn3 set roll1 %;; set roll2 %
notifyon btn3 set roll1,roll2 %
# Method 2a: perl.
notifyon btn3 { fhz "set roll1 %;; set roll2 %" }
notifyon btn3 { fhem "set roll1,roll2 %" }
# Method 2b: perl. open the rollades only to a certain amount if they are
# closed. Else do the required command.
notifyon btn3 {\
if("%" eq "on" && $value{roll1} eq "off") {\
fhz "set roll1 on-for-timer 10";;\
fhz "set roll2 on-for-timer 16";;\
fhem "set roll1 on-for-timer 10";;\
fhem "set roll2 on-for-timer 16";;\
} else { \
fhz "set roll1,roll2 %"\
fhem "set roll1,roll2 %"\
} \
}
@ -57,16 +57,15 @@ quit # Ignore the rest of this file
#
# Note that for greater time values the FS20 timer gets inaccurate, you
# can use something like
# $fhz 7072 "set roll1 on; at +00:00:21 set roll1 on"
# $fhem 7072 "set roll1 on; at +00:00:21 set roll1 on"
# instead.
#
fhz=/usr/local/bin/fhem.pl
fhem=/usr/local/bin/fhem.pl
if test $1 = "on"; then
$fhz 7072 "set roll1 on-for-timer 10
$fhz 7072 "set roll2 on-for-timer 16
$fhem 7072 "set roll1 on-for-timer 10
$fhem 7072 "set roll2 on-for-timer 16
else
$fhz 7072 "set roll1,roll2 off"
$fhem 7072 "set roll1,roll2 off"
fi

View File

@ -8,11 +8,11 @@
# After about 5-10 minutes, check if "list wz" returns something meaningful
#
logfile /tmp/fhem-%Y-%m.log
savefile /tmp/fhem.save # where to save the state of the devices
verbose 3 # "normal" verbosity
port 7072 # our TCP/IP port (working from localhost only)
modpath . # where our FHEM directory is
attr global logfile /tmp/fhem-%Y-%m.log
attr global statefile /tmp/fhem.save # where to save the state of the devices
attr global verbose 3 # "normal" verbosity
attr global port 7072 # our TCP/IP port (localhost only)
attr global modpath . # where our FHEM directory is
define FHZ FHZ /dev/tts/USB0 # the serial port of an FHZ 1000 PC
define wz FHT 3232 # type FHT, transmitter code 3232 (default value)
@ -20,11 +20,11 @@ define wz FHT 3232 # type FHT, transmitter code 3232 (default value)
#########################
# Some documentation suggests that the FHZ time should be set every minute.
# I only set it once a day.
at *03:30:00 set FHZ time
define fhz_timer at *03:30:00 set FHZ time
#########################
# If you wish to have up-to date information on certain strange parameters
# then comment out the line below. My devices send a message when a value
# changes, and send measured-temp, actuator and state messages regularly.
# Be patient: the reply comes in 5-10 minutes.
at *04:00:00 set wz refreshvalues
define wz_refresh at *04:00:00 set wz refreshvalues

View File

@ -4,11 +4,11 @@
# See the file fht.gnuplot for displaying the logged data (or webfrontend/pgm2)
#
logfile /tmp/fhem-%Y-%m.log
savefile /tmp/fhem.save # where to save the state of the devices
verbose 3 # "normal" verbosity
port 7072 # our TCP/IP port (working from localhost only)
modpath . # where our FHEM directory is
attr global logfile /tmp/fhem-%Y-%m.log
attr global statefile /tmp/fhem.save # where to save the state of the devices
attr global verbose 3 # "normal" verbosity
attr global port 7072 # our TCP/IP port (localhost only)
attr global modpath . # where our FHEM directory is
define FHZ FHZ /dev/tts/USB0 # the serial port of an FHZ 1000 PC
define wz FHT 3232 # type FHT, transmitter code 3232 (default value)
@ -27,7 +27,7 @@ define avglog FileLog /var/log/avg.log ks1:.*avg.*
# Alternative log method. It does the same, but it is somewhat slower as it
# starts the shellscript below. Don't forget the "", as some values contain
# paranthesis, and your shell will probably bark.
notifyon wz:temp.* "/usr/local/bin/log.sh @ "@ %""
define tmplog notifyon wz:temp.* "/usr/local/bin/log.sh @ "@ %""
##############################
# If using the frontends pgm2 or pgm3, then you can put the devices

View File

@ -5,19 +5,21 @@
#
# As the RM100-2 changes its code after the battery is changed (or the switch
# on the device itself is changed), we map _all_ RM100-2 to the device id 1001
# Check the commandref.html define, Type HMS section for details
# if there is no definition for it. Check the commandref.html define, Type HMS
# section for details
attr global logfile /tmp/fhem-%Y-%m.log
attr global statefile /tmp/fhem.save # where to save the state of the devices
attr global verbose 3 # "normal" verbosity (min 1, max 5)
attr global port 7072 # our TCP/IP port (localhost only)
attr global modpath . # where our FHEM directory is
logfile /tmp/fhem-%Y-%m.log
savefile /tmp/fhem.save # where to save the state of the devices
verbose 3 # "normal" verbosity (min 1, max 5)
port 7072 # our TCP/IP port (working from localhost only)
modpath . # where our FHEM directory is
define FHZ FHZ /dev/tts/USB0 # the serial port of an FHZ 1000 PC
define rm100 HMS 1001 # type HMS
define rm100log FileLog /var/log/wz-%Y-%U.log rm100:.*
notifyon rm100:smoke.*on "wall "FIRE: @ %""
define smokealarm notify rm100:smoke.*on "wall "FIRE: @ %""
# Test the log/notify
# fhem.pl 7072 'trigger rm100 smoke on'

View File

@ -3,37 +3,37 @@
##################################
# absolute ones:
at 17:00:00 set lamp on # fhz command
at 17:00:00 { Log 1, "Teetime" } # Perl command
at 17:00:00 "/bin/echo "Teetime" > /dev/console" # shell command
at *17:00:00 set lamp on # repeat every day
define a1 at 17:00:00 set lamp on # fhem command
define a2 at 17:00:00 { Log 1, "Teetime" } # Perl command
define a3 at 17:00:00 "/bin/echo "Teetime" > /dev/console" # shell command
define a4 at *17:00:00 set lamp on # repeat every day
##################################
# relative ones
at +00:00:10 set lamp on # switch the lamp on in 10 seconds
at +00:00:02 set lamp on-for-timer 1 # Blink once in 2 seconds
at +*{3}00:00:02 set lamp on-for-timer 1 # Blink 3 times
define a5 at +00:00:10 set lamp on # switch the lamp on in 10 seconds
define a6 at +00:00:02 set lamp on-for-timer 1 # Blink once in 2 seconds
define a7 at +*{3}00:00:02 set lamp on-for-timer 1 # Blink 3 times
##################################
# Switch the lamp on from sunset to 11 PM each day
# You have to install 99_SUNRISE.pm in the FHEM directory to have sunset()
# We have to use the relative versions, as the next event is computed now
{ sunrise_coord("8.686", "50.112", "Europe/Berlin") }
at +*{sunset_rel()} set lamp on
at *23:00:00 set lamp off
define a8 at +*{sunset_rel()} set lamp on
define a9 at *23:00:00 set lamp off
##################################
# A more elegant solution, which even works if sunset is after 23:00
at +*{sunset_rel()} set lamp on-till 23:00
define a10 at +*{sunset_rel()} set lamp on-till 23:00
##################################
# Only do this on weekend. For the preset perl variables see commandref.html
at +*{sunset_rel()} { fhz("set lamp on-till 23:00") if($we) }
define a11 at +*{sunset_rel()} { fhem("set lamp on-till 23:00") if($we) }
##################################
# Switch lamp1 and lamp2 on from 7:00 till 10 minutes after sunrise
at *07:00 set lamp1,lamp2 on-till {sunrise_abs(+600)}
define a12 at *07:00 set lamp1,lamp2 on-till {sunrise_abs(+600)}
##################################
# Blink 3 times if the piri sends a command
notify piri:on.* at +*{3}00:00:02 set lamp on-for-timer 1
define n1 notify piri:on.* define a13 at +*{3}00:00:02 set lamp on-for-timer 1

File diff suppressed because it is too large Load Diff