From f6bbddb4fec591aa751b0f0e03251b80dec48208 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Mon, 4 Aug 2008 13:47:53 +0000 Subject: [PATCH] Watchdog added + small changes git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@221 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- CHANGED | 3 ++ FHEM/90_at.pm | 6 +-- FHEM/91_watchdog.pm | 108 +++++++++++++++++++++++++++++++++++++++++++ docs/commandref.html | 63 +++++++++++++++++++++---- docs/faq.html | 38 ++++++++++++++- docs/fhem.html | 3 +- examples/03_fht | 18 ++++++++ fhem.pl | 27 ++++++----- 8 files changed, 236 insertions(+), 30 deletions(-) create mode 100755 FHEM/91_watchdog.pm diff --git a/CHANGED b/CHANGED index 65a9e300f..a04e0443b 100644 --- a/CHANGED +++ b/CHANGED @@ -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 diff --git a/FHEM/90_at.pm b/FHEM/90_at.pm index 9fbcde946..0d18e21f8 100755 --- a/FHEM/90_at.pm +++ b/FHEM/90_at.pm @@ -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); diff --git a/FHEM/91_watchdog.pm b/FHEM/91_watchdog.pm new file mode 100755 index 000000000..1c97a86b3 --- /dev/null +++ b/FHEM/91_watchdog.pm @@ -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 watchdog " + 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; diff --git a/docs/commandref.html b/docs/commandref.html index dc857aefa..80096891f 100644 --- a/docs/commandref.html +++ b/docs/commandref.html @@ -283,7 +283,7 @@ make editing of multiline commands transparent.

  • disable
    - Can be applied to at/notify/FileLog devices.
    + Can be applied to at/watchdog/notify/FileLog devices.
    Disables the corresponding at/notify or FileLog device. Note: If applied to an at, the command will not be executed, but the next time will be computed.

  • @@ -424,7 +424,7 @@ fs20sv fs20sv fs20usr -
  • HMS: hms100-t hms100-tf hms100-wd hms100-mg hms100-tfk rm100-2
  • +
  • HMS: hms100-t hms100-tf hms100-wd hms100-mg hms100-co hms100-tfk hms100-fit rm100-2
  • KS300: ks300
  • WS300: ws300pc
  • EM1010: em1010pc
  • @@ -701,24 +701,30 @@ fs20usr circumstances, the authors are not liable for any damage occuring as a result of incomplete or buggy code -
  • Currently supported devices are the HMS100T, HMS100TF, HMS100WD and - the RM100-2.
  • +
  • Currently supported devices are the HMS100-T HMS100-TF HMS100-WD + HMS100-MG HMS100-TFK HMS100-CO HMS100-FIT RM100-2
  • 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:
      -
    • 1000 for the HMS100TF
    • -
    • 1001 for the HMS100T
    • -
    • 1002 for the HMS100WD
    • +
    • 1000 for the HMS100-TF
    • +
    • 1001 for the HMS100-T
    • +
    • 1002 for the HMS100-WD
    • 1003 for the RM100-2
    • -
    • 1006 for the HMS100MG
    • +
    • 1004 for the HMS100-TFK/li> +
    • 1006 for the HMS100-MG
    • +
    • 1008 for the HMS100-CO
    • +
    • 100e for the HMS100-FIT
  • -
  • Some battery low notifications are not yet implemented (RM100, HMS100WD).
  • -
  • Please test your installation before relying on the functionality.
  • +
  • Some battery low notifications are not yet implemented (RM100, + HMS100WD).
  • +
  • Please test your installation before relying on the + functionality.
  • +
    @@ -1181,6 +1187,43 @@ fs20usr
    + + +

    Type watchdog

    +
      + define <name> watchdog <regexp1> <timespec> <regexp2> <command>
      +
      + Start an arbitrary fhem.pl command if after <timespec> receiving an + event matching <regexp1> no event matching <regexp2> is + received.
      + The syntax for <regexp1> and <regexp2> is the same as the + regexp for notify.
      + <timespec> is HH:MM[:SS]
      + <command> is a usual fhem command like used int the at or notify +

      + + Examples: +
      +    # "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"
      +    
      + + Notes:
      +
        +
      • if <regexp1> is . (dot), then activate the watchdog at + definition time. Else it will be activated when the first matching event + is received.
      • + +
      • if <regexp2> 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.
      • +
      +
      +
    +

    Type notify

    + +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? + +
      + + (Thanks for Martin Fischer for researching)
      + 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: +
      +  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");;\
      +    }\
      +  }
      +
      + +
    + + + diff --git a/docs/fhem.html b/docs/fhem.html index 65bfbc423..5ec921141 100644 --- a/docs/fhem.html +++ b/docs/fhem.html @@ -38,7 +38,7 @@ Currently implemented features:
    The FHT8b seems to work too. Note: the FHT8 wont work.
    Internal software buffer to prevent lost commands.
    -
  • reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)
  • +
  • reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK,-CO,-FIT and RM100-2)
  • reading KS300 data
  • Note:The FHZ1350 WLAN is probably not working due to a prorietary @@ -55,6 +55,7 @@ Currently implemented features:
  • notifying external programs or internal modules when receiving certain events
  • timed commands (e.g. switching a lamp on from sunset till midnight)
  • +
  • watchdog (e.g. trigger if the HMS100-FIT is inactive for HH:MM:SS)
  • modular architecture, easy to add your special device
  • different web frontends, choose your favorite

  • diff --git a/examples/03_fht b/examples/03_fht index a4fb13e3e..ccb1c5137 100644 --- a/examples/03_fht +++ b/examples/03_fht @@ -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");;\ + }\ +} diff --git a/fhem.pl b/fhem.pl index cad54a79e..85ae3d9d6 100755 --- a/fhem.pl +++ b/fhem.pl @@ -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