Watchdog added + small changes

git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@221 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2008-08-04 13:47:53 +00:00
parent bdf77c3db1
commit f6bbddb4fe
8 changed files with 236 additions and 30 deletions

View File

@ -417,3 +417,6 @@
- feature: autoloading FHEM modules
- bugfix: STATE/$value is carrying again the correct value
- feature: enhancing the Makefile and the documentation
- feature: 90_at is using now InternalTimer, subsecond precision added
- feature: HMS100-FIT added (01.01.08 by Peter and 22.01.08 by Juergen)
- feature: 91_watchdog added to handle the HMS100-FIT

View File

@ -3,6 +3,7 @@ package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday);
#####################################
sub
@ -11,7 +12,6 @@ at_Initialize($)
my ($hash) = @_;
$hash->{DefFn} = "at_Define";
$hash->{TimeFn} = "at_Exec";
$hash->{AttrFn} = "at_Attr";
$hash->{AttrList} = "disable:0,1 skip_next:0,1";
}
@ -42,7 +42,7 @@ at_Define($$)
$rep = "" if(!defined($rep));
$cnt = "" if(!defined($cnt));
my $ot = time;
my $ot = gettimeofday();
my @lt = localtime($ot);
my $nt = $ot;
@ -65,7 +65,7 @@ at_Define($$)
}
$hash->{NTM} = $ntm if($rel eq "+" || $fn);
$hash->{TRIGGERTIME} = $nt;
$nextat = $nt if(!$nextat || $nextat > $nt);
InternalTimer($nt, "at_Exec", $name, 0);
$hash->{STATE} = "Next: " . FmtTime($nt);

108
FHEM/91_watchdog.pm Executable file
View File

@ -0,0 +1,108 @@
##############################################
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday);
#####################################
sub
watchdog_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "watchdog_Define";
$hash->{NotifyFn} = "watchdog_Notify";
$hash->{AttrList} = "disable:0,1";
}
#####################################
# defined watchme watchdog reg1 timeout reg2 command
sub
watchdog_Define($$)
{
my ($ntfy, $def) = @_;
my ($name, $type, $re1, $to, $re2, $command) = split("[ \t]+", $def, 6);
return "Usage: define <name> watchdog <re1> <timeout> <re2> <command>"
if(!$command);
# Checking for misleading regexps
eval { "Hallo" =~ m/^$re1$/ };
return "Bad regexp 1: $@" if($@);
$re2 = $re1 if($re2 eq "SAME");
eval { "Hallo" =~ m/^$re2$/ };
return "Bad regexp 2: $@" if($@);
return "Wrong timespec, must be HH:MM[:SS]"
if($to !~ m/^(\d\d):(\d\d)(:\d\d)?$/);
$to = $1*3600+$2*60+($3 ? substr($3,1) : 0);
$ntfy->{RE1} = $re1;
$ntfy->{RE2} = $re2;
$ntfy->{TO} = $to;
$ntfy->{CMD} = $command;
$ntfy->{STATE} = ($re1 eq ".") ? "active" : "defined";
watchdog_Activate($ntfy) if($ntfy->{STATE} eq "active");
return undef;
}
#####################################
sub
watchdog_Notify($$)
{
my ($ntfy, $dev) = @_;
my $ln = $ntfy->{NAME};
return "" if($attr{$ln} && $attr{$ln}{disable});
my $n = $dev->{NAME};
my $re1 = $ntfy->{RE1};
my $re2 = $ntfy->{RE2};
my $max = int(@{$dev->{CHANGED}});
for (my $i = 0; $i < $max; $i++) {
my $s = $dev->{CHANGED}[$i];
$s = "" if(!defined($s));
if($ntfy->{STATE} =~ m/Next:/) {
if($n =~ m/^$re2$/ || "$n:$s" =~ m/^$re2$/) {
RemoveInternalTimer($ntfy);
if($re1 eq $re2) {
watchdog_Activate($ntfy);
} else {
$ntfy->{STATE} = "defined";
}
}
} elsif($n =~ m/^$re1$/ || "$n:$s" =~ m/^$re1$/) {
watchdog_Activate($ntfy);
}
}
return "";
}
sub
watchdog_Trigger($)
{
my ($ntfy) = @_;
Log(3, "Watchdog $ntfy->{NAME} triggered");
my $exec = SemicolonEscape($ntfy->{CMD});;
AnalyzeCommandChain(undef, $exec);
$ntfy->{STATE} = "triggered";
}
sub
watchdog_Activate($)
{
my ($ntfy) = @_;
my $nt = gettimeofday() + $ntfy->{TO};
$ntfy->{STATE} = "Next: " . FmtTime($nt);
InternalTimer($nt, "watchdog_Trigger", $ntfy, 0)
}
1;

View File

@ -283,7 +283,7 @@ make editing of multiline commands transparent.<br><br>
<a name="disable"></a>
<li>disable<br>
Can be applied to at/notify/FileLog devices.<br>
Can be applied to at/watchdog/notify/FileLog devices.<br>
Disables the corresponding at/notify or FileLog device. Note:
If applied to an <a href="#at">at</a>, the command will not be executed,
but the next time will be computed.</li><br>
@ -424,7 +424,7 @@ fs20sv
fs20sv
fs20usr</pre></li>
<li>HMS: hms100-t hms100-tf hms100-wd hms100-mg hms100-tfk rm100-2</li>
<li>HMS: hms100-t hms100-tf hms100-wd hms100-mg hms100-co hms100-tfk hms100-fit rm100-2</li>
<li>KS300: ks300</li>
<li>WS300: ws300pc</li>
<li>EM1010: em1010pc</li>
@ -701,24 +701,30 @@ fs20usr</pre></li>
circumstances, the authors are not liable for any damage occuring as a
result of incomplete or buggy code</li>
<li>Currently supported devices are the HMS100T, HMS100TF, HMS100WD and
the RM100-2.</li>
<li>Currently supported devices are the HMS100-T HMS100-TF HMS100-WD
HMS100-MG HMS100-TFK HMS100-CO HMS100-FIT RM100-2 </li>
<li>The housecode of the HMS devices may change if the battery is renewed.
In order to make life easier, you can define a "wildcard" device for each
type of HMS device. First the real device-id will be checked, then the
wildcard device id. The wildcards are:
<ul>
<li>1000 for the HMS100TF</li>
<li>1001 for the HMS100T</li>
<li>1002 for the HMS100WD</li>
<li>1000 for the HMS100-TF</li>
<li>1001 for the HMS100-T</li>
<li>1002 for the HMS100-WD</li>
<li>1003 for the RM100-2</li>
<li>1006 for the HMS100MG</li>
<li>1004 for the HMS100-TFK/li>
<li>1006 for the HMS100-MG</li>
<li>1008 for the HMS100-CO</li>
<li>100e for the HMS100-FIT</li>
</ul>
</li>
<li>Some battery low notifications are not yet implemented (RM100, HMS100WD).</li>
<li>Please test your installation before relying on the functionality.</li>
<li>Some battery low notifications are not yet implemented (RM100,
HMS100WD).</li>
<li>Please test your installation before relying on the
functionality.</li>
</ul>
<br>
</ul>
@ -1181,6 +1187,43 @@ fs20usr</pre></li>
<br>
</ul>
<a name="watchdog"></a>
<h4>Type watchdog</h4>
<ul>
<code>define &lt;name&gt; watchdog &lt;regexp1&gt; &lt;timespec&gt; &lt;regexp2&gt; &lt;command&gt;</code><br>
<br>
Start an arbitrary fhem.pl command if after &lt;timespec&gt; receiving an
event matching &lt;regexp1&gt; no event matching &lt;regexp2&gt; is
received.<br>
The syntax for &lt;regexp1&gt; and &lt;regexp2&gt; is the same as the
regexp for <a href="#notify">notify</a>.<br>
&lt;timespec&gt; is HH:MM[:SS]<br>
&lt;command&gt; is a usual fhem command like used int the <a
href="#at">at</a> or <a href="#notify">notify</a>
<br><br>
Examples:
<pre>
# "Reset" the FHT80 if we do not receive any message for 15 Minutes
define w watchdog FHT80 00:15:00 SAME set FHT80 refreshvalues
# Shout if the HMS100-FIT is not alive
define w watchdog HMS100-FIT 01:00:00 SAME "alarm-fit.sh"
</pre>
Notes:<br>
<ul>
<li>if &lt;regexp1&gt; is . (dot), then activate the watchdog at
definition time. Else it will be activated when the first matching event
is received.</li>
<li>if &lt;regexp2&gt; is SAME, then it will be the same as the first
regexp, and it will be reactivated, when it is received. This is probably
the normal operation.</li>
</ul>
<br>
</ul>
<a name="notify"></a>
<h4>Type notify</h4>
<ul>

View File

@ -44,9 +44,16 @@ hex code needed by fhem.pl?</a><br><br>
<a href="#faq11">11. I'd like to use this sunrise/sunset stuff, can you help
me?</a><br><br>
<a href="#faq12">12. I'd like to switch on the ventilator if the FHT tells me its too hot. How to tell fhem to do that?</a><br><br>
<a href="#faq12">12. I'd like to switch on the ventilator if the FHT tells me
its too hot. How to tell fhem to do that?</a><br><br>
<a href="#faq13">13. I'd like to see directly in the Web frontend if a window
is open. How to do that?</a><br><br>
<a href="#faq14">14. In the summer I get a lot of "actuator:lime-protection"
messages from my FHT80b. How to switch back to the actuator:0% messages?</a>
<br><br>
<a href="#faq12">13. I'd like to see directly in the Web frontend if a window is open. How to do that?</a><br><br>
<br/>
<br/>
@ -285,5 +292,32 @@ How to do that? (by fwolff)</b>
</pre>
</ul>
<a name="faq14"></a>
<b>14. In the summer I get a lot of "actuator:lime-protection
messages from my FHT80b. How to switch back to the actuator:0% messages?
</b>
<ul>
(Thanks for Martin Fischer for researching)<br>
The problem happens if at the weekly lime-protection time (usually saturday
at 11:00 AM) the desired temperature is lower than the measured temperature.
I think this is an FHT80b firmware bug, a workaround is to set the desired
temperature for a short time higher than the measured temperature.
You can automate it with the following notify:
<pre>
define lime_reset notify .*lime-protection {\
$d = $defs{@}{READINGS}{"desired-temp"}{VAL};;\
$m = $defs{@}{READINGS}{"measured-temp"}{VAL};;\
if($m > $d) {\
fhem("set @ desired-temp 29");;\
fhem("set @ desired-temp $d");;\
}\
}
</pre>
</ul>
<a name="faq14">
</body>
</html>

View File

@ -38,7 +38,7 @@ Currently implemented features:<br>
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.<br>
Internal software buffer to prevent lost commands.<br>
</li>
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)</li>
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK,-CO,-FIT and RM100-2)</li>
<li>reading KS300 data</li>
</ul>
<b>Note:</b>The FHZ1350 WLAN is probably not working due to a prorietary
@ -55,6 +55,7 @@ Currently implemented features:<br>
<li>notifying external programs or internal modules when receiving certain
events</li>
<li>timed commands (e.g. switching a lamp on from sunset till midnight)</li>
<li>watchdog (e.g. trigger if the HMS100-FIT is inactive for HH:MM:SS)</li>
<li>modular architecture, easy to add your special device</li>
<li>different web frontends, choose your favorite</li>
<br>

View File

@ -32,3 +32,21 @@ define wz_refresh at *04:00:00 set wz report1 255 report2 255
# alias for the above
define wz_refresh at *04:00:00 set wz refreshvalues
###################
# If at the weekly lime-protection time (usually saturday at 11:00 AM) the
# desired temperature is lower than the measured temperature, then you'll get
# instead of "actuator:0%" the "actuator:lime-protection" messsages every 2.5
# minutes. I think this is an FHT80b firmware bug, a workaround is to set the
# desired temperature for a short time higher than the measured temperature.
# You can automate it (for all FHT's) with the following notify:
define lime_reset notify .*lime-protection {\
my $d = $defs{@}{READINGS}{"desired-temp"}{VAL};;\
my $m = $defs{@}{READINGS}{"measured-temp"}{VAL};;\
if($m > $d) {\
fhem("set @ desired-temp 29");;\
fhem("set @ desired-temp $d");;\
}\
}

27
fhem.pl
View File

@ -58,6 +58,7 @@ sub Log($$);
sub OpenLogfile($);
sub PrintHash($$);
sub ResolveDateWildcards($@);
sub RemoveInternalTimer($);
sub SemicolonEscape($);
sub SignalHandling();
sub TimeNow();
@ -103,7 +104,6 @@ sub CommandTrigger($$);
# SetFn - set/activate this device
# GetFn - get some data from this device
# StateFn - set local info for this device, do not activate anything
# TimeFn - if the TRIGGERTIME of a device is reached, call this function
# NotifyFn - call this if some device changed its properties
# ReadyFn - check for available data, if no FD
# ReadFn - Reading from a Device (see FHZ/WS300)
@ -125,7 +125,6 @@ use vars qw(%attr); # Attributes
use vars qw(%value); # Current values, see commandref.html
use vars qw(%oldvalue); # Old values, see commandref.html
use vars qw($nextat); # used by the at module
use vars qw($init_done); #
use vars qw($internal_data); #
@ -140,10 +139,11 @@ my $global_cl; # To use from perl snippets
my $devcount = 0; # To sort the devices
my %defaultattr; # Default attributes
my %intAt; # Internal at timer hash.
my $nextat; # Time when next timer will be triggered.
my $intAtCnt=0;
my $reread_active = 0;
my $AttrList = "room comment";
my $cvsid = '$Id: fhem.pl,v 1.49 2008-07-28 12:33:29 rudolfkoenig Exp $';
my $cvsid = '$Id: fhem.pl,v 1.50 2008-08-04 13:47:53 rudolfkoenig Exp $';
$init_done = 0;
@ -1580,17 +1580,6 @@ HandleTimeout()
return ($nextat-$now) if($now < $nextat);
$nextat = 0;
foreach my $i (keys %defs) {
next if(!$defs{$i}{TRIGGERTIME});
if($now >= $defs{$i}{TRIGGERTIME}) {
CallFn($i, "TimeFn", $i);
} else {
$nextat = $defs{$i}{TRIGGERTIME}
if(!$nextat || $nextat > $defs{$i}{TRIGGERTIME});
}
}
#############
# Check the internal list.
foreach my $i (keys %intAt) {
@ -1631,6 +1620,16 @@ InternalTimer($$$$)
$nextat = $tim if(!$nextat || $nextat > $tim);
}
#####################################
sub
RemoveInternalTimer($)
{
my ($arg) = @_;
foreach my $a (keys %intAt) {
delete($intAt{$a}) if($intAt{$a}{ARG} eq $arg);
}
}
#####################################
sub