mirror of
https://github.com/fhem/fhem-mirror.git
synced 2024-11-22 02:59:49 +00:00
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:
parent
154ba72193
commit
1af4b93426
13
fhem/CHANGED
13
fhem/CHANGED
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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));
|
||||
|
@ -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;
|
34
fhem/HISTORY
34
fhem/HISTORY
@ -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
|
||||
|
||||
|
@ -32,8 +32,6 @@ DbLog_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Category} = "none";
|
||||
|
||||
# Lets connect here, so we see the error at startup
|
||||
DbConnect();
|
||||
}
|
||||
|
@ -31,8 +31,7 @@ use warnings;
|
||||
sub
|
||||
ALARM_Initialize($$)
|
||||
{
|
||||
my ($hash, $init) = @_;
|
||||
$hash->{Type} = "none";
|
||||
my ($hash) = @_;
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,8 +30,6 @@ sub
|
||||
SUNRISE_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Category} = "none";
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
1056
fhem/fhem.pl
1056
fhem/fhem.pl
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user