diff --git a/fhem/CHANGED b/fhem/CHANGED index aabf05131..29826b02a 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - new: 98_monitoring: introducing new module to monitor devices towards + events and stores them in two lists - update: 88_HMCCU: Prepared code for version 4. - update: 98_DOIFtools: minor fixes, added create DOIF Definition with event derived operands when using event monitor in DOIFtools diff --git a/fhem/FHEM/98_monitoring.pm b/fhem/FHEM/98_monitoring.pm new file mode 100644 index 000000000..7e4efb852 --- /dev/null +++ b/fhem/FHEM/98_monitoring.pm @@ -0,0 +1,1370 @@ +# Id ########################################################################## +# $Id$ + +# copyright ################################################################### +# +# 98_monitoring.pm +# +# Copyright by igami +# +# This file is part of FHEM. +# +# FHEM is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# FHEM is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with FHEM. If not, see . + +# packages #################################################################### +package main; + use strict; + use warnings; + +# forward declarations ######################################################## +sub monitoring_Initialize($); + +sub monitoring_Define($$); +sub monitoring_Set($@); +sub monitoring_Get($@); +sub archetype_Attr(@); +sub monitoring_Notify($$); + +sub monitoring_modify($); +sub monitoring_return($$); +sub monitoring_setActive($); + +# initialize ################################################################## +sub monitoring_Initialize($) { + my ($hash) = @_; + my $TYPE = "monitoring"; + + $hash->{DefFn} = $TYPE."_Define"; + $hash->{SetFn} = $TYPE."_Set"; + $hash->{GetFn} = $TYPE."_Get"; + $hash->{AttrFn} = $TYPE."_Attr"; + $hash->{NotifyFn} = $TYPE."_Notify"; + + $hash->{AttrList} = + "addStateEvent:1,0 " + . "disable:1,0 " + . "disabledForIntervals " + . "errorFuncAdd:textField-long " + . "errorFuncRemove:textField-long " + . "errorWait " + . "errorReturn:textField-long " + . "getDefault:all,error,warning " + . "setActiveFunc:textField-long " + . "warningFuncAdd:textField-long " + . "warningFuncRemove:textField-long " + . "warningWait " + . "warningReturn:textField-long " + . $readingFnAttributes + ; +} + +# regular Fn ################################################################## +sub monitoring_Define($$) { + my ($hash, $def) = @_; + my ($SELF, $TYPE, @re) = split(/[\s]+/, $def, 5); + + return("Usage: define $TYPE []") + if(int(@re) < 1 || int(@re) > 2); + + readingsBeginUpdate($hash); + # readingsBulkUpdate($hash, "warning", "") unless($hash->{READINGS}{warning}); + # readingsBulkUpdate($hash, "error", "") unless($hash->{READINGS}{error}); + readingsEndUpdate($hash, 0); + monitoring_setActive($hash) if($init_done); + + return; +} + +sub monitoring_Set($@) { + my ($hash, @a) = @_; + my $TYPE = $hash->{TYPE}; + + return("\"set $TYPE\" needs at least one argument") if(@a < 2); + + my $SELF = shift @a; + my $argument = shift @a; + my $value = join(" ", @a) if (@a); + my %monitoring_sets = ( + "active" => "active:noArg" + , "clear" => "clear:all,error,warning" + , "errorAdd" => "errorAdd:textField" + , "errorRemove" => "errorRemove:" + . join(",", ReadingsVal($SELF, "error", "")) + , "inactive" => "inactive:noArg" + , "warningAdd" => "warningAdd:textField" + , "warningRemove" => "warningRemove:" + . join(",", ReadingsVal($SELF, "warning", "")) + ); + + return( + "Unknown argument $argument, choose one of " + . join(" ", sort(values %monitoring_sets)) + ) unless(exists($monitoring_sets{$argument})); + + if($argument eq "active"){ + monitoring_setActive($hash); + } + elsif($argument eq "inactive"){ + readingsSingleUpdate($hash, "state", $argument, 0); + Log3($SELF, 3, "$SELF ($TYPE) set $SELF inactive"); + } + elsif($argument eq "clear"){ + readingsBeginUpdate($hash); + + if($value =~ m/^(warning|all)$/){ + readingsBulkUpdate($hash, "warning", "", 0); + + foreach my $r (keys %{$hash->{READINGS}}){ + delete $hash->{READINGS}{$r} if($r =~ m/warningAdd_(.+)/); + } + } + if($value =~ m/^(error|all)$/){ + readingsBulkUpdate($hash, "error", "", 0); + + foreach my $r (keys %{$hash->{READINGS}}){ + delete $hash->{READINGS}{$r} if($r =~ m/errorAdd_(.+)/); + } + } + + readingsBulkUpdate($hash, "state", "$argument $value", 0) + unless(IsDisabled($SELF)); + readingsEndUpdate($hash, 0); + + Log3($SELF, 2, "$SELF ($TYPE) set $SELF $argument $value"); + } + elsif($argument =~ /^(error|warning)(Add|Remove)$/){ + monitoring_modify("$SELF|$1|".lc($2)."|$value"); + } + + return; +} + +sub monitoring_Get($@) { + my ($hash, @a) = @_; + my $TYPE = $hash->{TYPE}; + my $SELF = shift @a; + + return if(IsDisabled($SELF)); + return("\"get $TYPE\" needs at least one argument") if(@a < 1); + + my $argument = shift @a; + my $value = join(" ", @a) if (@a); + my $default = AttrVal($SELF, "getDefault", "all"); + my %monitoring_gets = ( + "all" => "all:noArg" + , "default" => "default:noArg" + , "error" => "error:noArg" + , "warning" => "warning:noArg" + ); + my @ret; + + return( + "Unknown argument $argument, choose one of " + . join(" ", sort(values %monitoring_gets)) + ) unless(exists($monitoring_gets{$argument})); + + if($argument eq "all" || ($argument eq "default" && $default eq "all")){ + push(@ret, monitoring_return($hash, "error")); + push(@ret, monitoring_return($hash, "warning")); + } + elsif($argument eq "default"){ + push(@ret, monitoring_return($hash, $default)); + } + elsif($argument eq "error"){ + push(@ret, monitoring_return($hash, "error")); + } + elsif($argument eq "warning"){ + push(@ret, monitoring_return($hash, "warning")); + } + + return(join("\n\n", @ret)."\n") if(@ret); + return; +} + +sub monitoring_Attr(@) { + my ($cmd, $SELF, $attribute, $value) = @_; + my ($hash) = $defs{$SELF}; + + if($attribute eq "disable"){ + if($cmd eq "set" and $value == 1){ + monitoring_setActive($hash); + } + else{ + readingsSingleUpdate($hash, "state", "disabled", 0); + Log3($SELF, 3, "$SELF ($hash->{TYPE}) attr $SELF disabled"); + } + } +} + +sub monitoring_Notify($$) { + my ($hash, $dev_hash) = @_; + my $SELF = $hash->{NAME}; + my $name = $dev_hash->{NAME}; + my $TYPE = $hash->{TYPE}; + + return if( + !$init_done + || IsDisabled($SELF) + || IsDisabled($name) + || $SELF eq $name # do not process own events + ); + + my $events = deviceEvents($dev_hash, AttrVal($SELF, "addStateEvent", 0)); + + if($name eq "global" && "INITIALIZED" =~ m/@{$events}/){ + monitoring_setActive($hash); + + return; + } + + my ($addRegex, $removeRegex) = split(/[\s]+/, InternalVal($SELF, "DEF", "")); + + return unless( + $addRegex =~ m/^$name:/ + || $removeRegex && $removeRegex =~ m/^$name:/ + || $events + ); + + foreach my $event (@{$events}){ + my $addMatch = "$name:$event" =~ $addRegex; + my $removeMatch = $removeRegex ? "$name:$event" =~ $removeRegex : 0; + + next unless(defined($event) && ($addMatch || $removeMatch)); + + Log3($SELF, 4 , "$SELF ($TYPE) triggered by \"$name $event\""); + + foreach my $list ("warning", "error"){ + my $listFuncAdd = AttrVal($SELF, $list."FuncAdd", "preset"); + my $listFuncRemove = AttrVal($SELF, $list."FuncRemove", "preset"); + my $listWait = eval(AttrVal($SELF, $list."Wait", 0)); + $listWait = 0 unless(looks_like_number($listWait)); + + if($listFuncAdd eq "preset" && $listFuncRemove eq "preset"){ + Log3($SELF, 5 + , "$SELF ($TYPE) " + . $list."FuncAdd and " + . $list."FuncRemove are preset" + ); + if(!$removeRegex){ + if($listWait == 0){ + Log3($SELF, 2 + , "$SELF ($TYPE) set \"$list"."Wait\" while \"$list" + . "FuncAdd\" and \"$list"."FuncRemove\" are same" + ) if($list eq "error"); + + next; + } + + Log3($SELF, 5, "$SELF ($TYPE) only addRegex is defined"); + + monitoring_modify("$SELF|$list|remove|$name"); + monitoring_modify( + "$SELF|$list|add|$name|$listWait" + ); + + next; + } + else{ + next unless($list eq "error" || AttrVal($SELF, "errorWait", undef)); + + Log3($SELF, 5 + , "$SELF ($TYPE) addRegex ($addRegex) " + . "and removeRegex ($removeRegex) are defined" + ); + + monitoring_modify("$SELF|$list|remove|$name") if($removeMatch); + monitoring_modify("$SELF|$list|add|$name|$listWait") if($addMatch); + + next; + } + } + + $listFuncAdd = 1 if($listFuncAdd eq "preset" && $addMatch); + + if(!$removeRegex){ + Log3($SELF, 5, "$SELF ($TYPE) only addRegex is defined"); + + if($listFuncRemove eq "preset"){ + if($listWait == 0){ + Log3($SELF, 2 + , "$SELF ($TYPE) set \"$list"."Wait\" while \"$list" + . "FuncAdd\" and \"$list"."FuncRemove\" are same" + ) if($list eq "error"); + + next; + } + + $listFuncRemove = $listFuncAdd; + } + } + else{ + Log3($SELF, 5 + , "$SELF ($TYPE) addRegex ($addRegex) " + . "and removeRegex ($removeRegex) are defined" + ); + + $listFuncRemove = 1 if($listFuncRemove eq "preset" && $removeMatch); + } + + $listFuncAdd = eval($listFuncAdd) if($listFuncAdd =~ /^\{.*\}$/s); + $listFuncRemove = eval($listFuncRemove) + if($listFuncRemove =~ /^\{.*\}$/s); + + monitoring_modify("$SELF|$list|remove|$name") + if($listFuncRemove && $listFuncRemove eq "1"); + monitoring_modify("$SELF|$list|add|$name|$listWait") + if($listFuncAdd && $listFuncAdd eq "1"); + + next; + } + } + + return; +} + +# module Fn ################################################################### +sub monitoring_modify($) { + my ($SELF, $list, $operation, $value, $wait) = split("\\|", shift); + + return if(IsDisabled($SELF)); + + my $at = eval($wait + gettimeofday()) if($wait); + my $hash = $defs{$SELF}; + my $TYPE = $hash->{TYPE}; + my (@change, %readings); + %readings = map{$_, 1} split(",", ReadingsVal($SELF, $list, "")); + my $arg = "$SELF|$list|$operation|$value"; + my $reading = $list."Add_".$value; + + Log3( + $SELF, 5 , "$SELF ($TYPE)" + . "\n entering monitoring_modify" + . "\n reading: $list" + . "\n operation: $operation" + . "\n value: $value" + . "\n at: ".($at ? FmtDateTime($at) : "now") + ); + + if($operation eq "add"){ + return if($readings{$value}); + if($at){ + return if($hash->{READINGS}{$reading}); + + readingsSingleUpdate( + $hash, $reading, FmtDateTime($at), 0 + ); + InternalTimer($at, "monitoring_modify", $arg); + + return; + } + else{ + monitoring_modify("$SELF|warning|remove|$value") if($list eq "error"); + $readings{$value} = 1; + delete $hash->{READINGS}{$reading}; + } + } + elsif($operation eq "remove"){ + push(@change, 1) if(delete $readings{$value}); + delete $hash->{READINGS}{"$reading"}; + } + + RemoveInternalTimer("$SELF|$list|add|$value"); + + return unless(@change || $operation eq "add"); + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "state", "$list $operation: $value"); + readingsBulkUpdate($hash, $list, join(",", sort(keys %readings))); + readingsEndUpdate($hash, 1); + + return; +} + +sub monitoring_return($$) { + my ($hash, $list) = @_; + my $SELF = $hash->{NAME}; + my @errors = split(",", ReadingsVal($SELF, "error", "")); + my @warnings = split(",", ReadingsVal($SELF, "warning", "")); + my $value = ReadingsVal($SELF, $list, undef); + my $ret = AttrVal($SELF, $list."Return", undef); + $ret = '"$list: $value"' if(!$ret && $value); + + return unless($ret); + return eval($ret); +} + +sub monitoring_setActive($) { + my ($hash) = @_; + my $SELF = $hash->{NAME}; + my $TYPE = $hash->{TYPE}; + + readingsSingleUpdate($hash, "state", "active", 0); + Log3($SELF, 3, "$SELF ($TYPE) set $SELF active"); + + foreach my $reading (sort(keys %{$hash->{READINGS}})){ + if($reading =~ m/(error|warning)Add_(.+)/){ + my $wait = time_str2num(ReadingsVal($SELF, $reading, "")); + + next unless(looks_like_number($wait)); + + $wait -= gettimeofday(); + + if($wait > 0){ + Log3($SELF, 4 + , "$SELF ($TYPE) restore Timer \"$SELF|$1|add|$2\"" + ); + } + else{ + monitoring_modify("$SELF|$1|add|$2"); + } + } + } + + AnalyzeCommandChain(undef, AttrVal($SELF, "setActiveFunc", "preset")); + + return; +} + +1; + +# commandref ################################################################## +=pod +=item helper +=item summary monitors devices towards events and stores them in two lists +=item summary_DE überwacht Geräte auf Events und speichert diese in zwei Listen + +=begin html + + +

monitoring

+( en | de ) +
+
    + Each monitoring has a warning and an error list, which are stored + as readings.
    + When a defined add-event occurs, the device is set to the warning + list after a predefined time.
    + After a further predefined time, the device is deleted from the + warning list and set to the error list.
    + If a defined remove-event occurs, the device is deleted from both + lists and still running timers are canceled.
    + This makes it easy to create group messages and send them + formatted by two attributes.
    +
    + The following applications are possible and are described + below:
    +
      +
    • opened windows
    • +
    • battery warnings
    • +
    • activity monitor
    • +
    • + regular maintenance (for example changing the table water + filter or cleaning rooms) +
    • +
    • + operating hours dependent maintenance (for example clean the + Beamer filter) +
    • +
    +
    + The monitor does not send a message by itself, a notify or DOIF is + necessary, which responds to the event "<monitoring-name> error + add: <name>" and then sends the return value of "get + <monitoring-name> default". +
    +
    + + Define +
      + + define <name> <add-event> [<remove-event>] + +
      + The syntax for <add-event> and <remove-event> is the + same as the pattern for notify + (device-name or device-name:event).
      + If only an <add-event> is defined, the device is deleted from + both lists as it occurs and the timers for warning and error are + started.
      +
    +
    + + Set +
      +
    • + active
      + Two things will happen:
      + 1. Restores pending timers, or sets the devices immediately to the + corresponding list if the time is in the past.
      + 2. Executes the commands specified under the "setActiveFunc" attribute. +
    • +
    • + clear (warning|error|all)
      + Removes all devices from the specified list and aborts timers for this + list. With "all", all devices are removed from both lists and all + running timers are aborted. +
    • +
    • + errorAdd <name>
      + Add <name> to the error list. +
    • +
    • + errorRemove <name>
      + Removes <name> from the error list. +
    • +
    • + inactive
      + Inactivates the current device. Note the slight difference to the + disable attribute: using set inactive the state is automatically saved + to the statefile on shutdown, there is no explicit save necesary. +
    • +
    • + warningAdd <name>
      + Add <name> to the warning list. +
    • +
    • + warningRemove <name>
      + Removes <name> from the warning list. +
    • +
    +
    + + Get +
      +
    • + all
      + Returns the error and warning list, separated by a blank line.
      + The formatting can be set with the attributes "errorReturn" and + "warningReturn". +
    • +
    • + default
      + The "default" value can be set in the attribute "getDefault" and is + intended to leave the configuration for the return value in the + monitoring device. If nothing is specified "all" is used. +
    • +
    • + error
      + Returns the error list.
      + The formatting can be set with the attribute "errorReturn". +
    • +
    • + warning
      + Returns the warning list.
      + The formatting can be set with the attribute "warningReturn". +
    • +
    +
    + + Readings
    +
      +
    • + error
      + Comma-separated list of devices. +
    • +
    • + errorAdd_<name>
      + Displays the time when the device will be set to the error list. +
    • +
    • + state
      + Displays the status (active, inactive, or disabled). In "active" it + displays which device added to which list or was removed from which + list. +
    • +
    • + warning
      + Comma-separated list of devices. +
    • +
    • + warningAdd_<name>
      + Displays the time when the device will be set to the warning list. +
    • +
    +
    + + Attribute +
      +
    • + + addStateEvent + +
    • +
    • + disable (1|0)
      + 1: Disables the monitoring.
      +        0: see "set active" +
    • +
    • + + disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ... + +
    • +
    • + errorFuncAdd {<perl code>}
      + The following variables are available in this function: +
      +
        +
      • + $name
        + Name of the event triggering device +
      • +
      • + $event
        + Includes the complete event, e.g. + measured-temp: 21.7 (Celsius) +
      • +
      • + $addMatch
        + Has the value 1 if the add-event is true +
      • +
      • + $removeMatch
        + Has the value 1 if the remove-event is true +
      • +
      • + $SELF
        + Name of the monitoring +
      • +
      + If the function returns a 1, the device is set to the error list after + the wait time.
      + If the attribute is not set, it will be checked for + $addMatch. +
    • +
    • + errorFuncRemove {<perl code>}
      + This function provides the same variables as for "errorFuncAdd".
      + If the function returns a 1, the device is removed from the error list + and still running timers are canceled.
      + If the attribute is not set, it will be checked for + $removeMatch if there is a + <remove-event> in the DEF, otherwise it will be + checked for errorFuncAdd. +
    • +
    • + errorWait <perl code>
      + Wait until the device is set to the error list. +
    • +
    • + errorReturn {<perl code>}
      + The following variables are available in this attribute: +
        +
      • + @errors
        + Array with all devices on the error list. +
      • +
      • + @warnings
        + Array with all devices on the warning list. +
      • +
      • + $SELF
        + Name of the monitoring +
      • +
      + With this attribute the output created with "get <name> error" + can be formatted. +
    • +
    • + getDefault (all|error|warning)
      + This attribute can be used to specify which list(s) are / are returned + by "get <name> default". If the attribute is not set, "all" will + be used. +
    • +
    • + setActiveFunc <Anweisung>
      + The statement is one of the FHEM command types and is executed when you + define the monitoring or "set active".
      + For a battery message "trigger battery=low battery: low" + can be useful. +
    • +
    • + warningFuncAdd {<perl code>}
      + Like errorFuncAdd, just for the warning list. +
    • +
    • + warningFuncRemove {<perl code>}
      + Like errorFuncRemove, just for the warning list. +
    • +
    • + warningWait <perl code>
      + Like errorWait, just for the warning list. +
    • +
    • + warningReturn {<perl code>}
      + Like errorReturn, just for the warning list. +
    • +
    • + + readingFnAttributes + +
    • +
    +
    + + Examples +
      + + The following sample codes can be imported via "Raw definition". + +

      +
    • + + Global, flexible opened windows/doors message + + (similar to those described in the forum) + + +
      +
      defmod Fenster_monitoring monitoring .*:(open|tilted) .*:closed
      +attr Fenster_monitoring errorReturn {return unless(@errors);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@errors);;\
      + return("Das Fenster \"$errors[0]\" ist schon länger geöffnet.") if(int(@errors) == 1);;\
      + @errors = sort {lc($a) cmp lc($b)} @errors;;\
      + return(join("\n - ", "Die folgenden ".@errors." Fenster sind schon länger geöffnet:", @errors))\
      +}
      +attr Fenster_monitoring errorWait {AttrVal($name, "winOpenTimer", 60*10)}
      +attr Fenster_monitoring warningReturn {return unless(@warnings);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@warnings);;\
      + return("Das Fenster \"$warnings[0]\" ist seit kurzem geöffnet.") if(int(@warnings) == 1);;\
      + @warnings = sort {lc($a) cmp lc($b)} @warnings;;\
      + return(join("\n - ", "Die folgenden ".@warnings." Fenster sind seit kurzem geöffnet:", @warnings))\
      +}
      + As soon as a device triggers an "open" or "tilded" event, the device is + set to the warning list and a timer is started after which the device + is moved from the warning to the error list. The waiting time can be + set for each device via userattr "winOpenTimer". The default value is + 10 minutes.
      + As soon as a device triggers a "closed" event, the device is deleted + from both lists and still running timers are stopped. +
    • +
      +
    • + Battery monitoring
      +
      defmod Batterie_monitoring monitoring .*:battery:.low .*:battery:.ok
      +attr Batterie_monitoring errorReturn {return unless(@errors);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@errors);;\
      + return("Bei dem Gerät \"$errors[0]\" muss die Batterie gewechselt werden.") if(int(@errors) == 1);;\
      + @errors = sort {lc($a) cmp lc($b)} @errors;;\
      + return(join("\n - ", "Die folgenden ".@errors." Geräten muss die Batterie gewechselt werden:", @errors))\
      +}
      +attr Batterie_monitoring errorWait 60*60*24*14
      +attr Batterie_monitoring warningReturn {return unless(@warnings);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@warnings);;\
      + return("Bei dem Gerät \"$warnings[0]\" muss die Batterie demnächst gewechselt werden.") if(int(@warnings) == 1);;\
      + @warnings = sort {lc($a) cmp lc($b)} @warnings;;\
      + return(join("\n - ", "Die folgenden ".@warnings." Geräten muss die Batterie demnächst gewechselt werden:", @warnings))\
      +}
      + As soon as a device triggers a "battery: low" event, the device is set + to the warning list and a timer is started after which the device is + moved from the warning to the error list. The waiting time is set to 14 + days.
      + As soon as a device triggers a "battery: ok" event, the device is + deleted from both lists and still running timers are stopped. +
    • +
      +
    • + Activity Monitor
      +
      defmod Activity_monitoring monitoring .*:.*
      +attr Activity_monitoring errorReturn {return unless(@errors);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@errors);;\
      + return("Das Gerät \"$errors[0]\" hat sich seit mehr als 24 Stunden nicht mehr gemeldet.") if(int(@errors) == 1);;\
      + @errors = sort {lc($a) cmp lc($b)} @errors;;\
      + return(join("\n - ", "Die folgenden ".@errors." Geräten haben sich seit mehr als 24 Stunden nicht mehr gemeldet:", @errors))\
      +}
      +attr Activity_monitoring errorWait 60*60*24
      +attr Activity_monitoring warningReturn {return unless(@warnings);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@warnings);;\
      + return("Das Gerät \"$warnings[0]\" hat sich seit mehr als 12 Stunden nicht mehr gemeldet.") if(int(@warnings) == 1);;\
      + @warnings = sort {lc($a) cmp lc($b)} @warnings;;\
      + return(join("\n - ", "Die folgenden ".@warnings." Geräten haben sich seit mehr als 12 Stunden nicht mehr gemeldet:", @warnings))\
      +}
      +attr Activity_monitoring warningWait 60*60*12
      + Devices are not monitored until they have triggered at least one event. + If the device does not trigger another event in 12 hours, it will be + set to the warning list. If the device does not trigger another event + within 24 hours, it will be moved from the warning list to the error + list. +
    • +
      +
    • + Regular maintenance (for example changing the table water filter) +
      +
      defmod Wasserfilter_monitoring monitoring Wasserfilter_DashButton:.*:.short
      +attr Wasserfilter_monitoring errorReturn {return unless(@errors);;\
      + return "Der Wasserfilter muss gewechselt werden.";;\
      +}
      +attr Wasserfilter_monitoring errorWait 60*60*24*30
      +attr Wasserfilter_monitoring warningReturn {return unless(@warnings);;\
      + return "Der Wasserfilter muss demnächst gewechselt werden.";;\
      +}
      +attr Wasserfilter_monitoring warningWait 60*60*24*25
      + A DashButton is used to tell FHEM that + the water filter has been changed.
      + After 30 days, the DashButton is set to the error list. +
    • +
      +
    • + Regular maintenance (for example cleaning rooms) +
      +
      defmod putzen_DashButton dash_dhcp
      +attr putzen_DashButton allowed AC:63:BE:2E:19:AF,AC:63:BE:49:23:48,AC:63:BE:49:5E:FD,50:F5:DA:93:2B:EE,AC:63:BE:B2:07:78
      +attr putzen_DashButton devAlias ac-63-be-2e-19-af:Badezimmer\
      +ac-63-be-49-23-48:Küche\
      +ac-63-be-49-5e-fd:Schlafzimmer\
      +50-f5-da-93-2b-ee:Arbeitszimmer\
      +ac-63-be-b2-07-78:Wohnzimmer
      +attr putzen_DashButton event-min-interval .*:5
      +attr putzen_DashButton port 6767
      +attr putzen_DashButton userReadings state {return (split(":", @{$hash->{CHANGED}}[0]))[0];;}
      +attr putzen_DashButton widgetOverride allowed:textField-long devAlias:textField-long
      +
      +defmod putzen_monitoring monitoring putzen_DashButton:.*:.short
      +attr putzen_monitoring errorFuncAdd {$event =~ m/^(.+):/;;\
      + $name = $1;;\
      + return 1;;\
      +}
      +attr putzen_monitoring errorReturn {return unless(@errors);;\
      + return("Der Raum \"$errors[0]\" muss wieder geputzt werden.") if(int(@errors) == 1);;\
      + return(join("\n - ", "Die folgenden Räume müssen wieder geputzt werden:", @errors))\
      +}
      +attr putzen_monitoring errorWait 60*60*24*7
      + Several DashButton are used to inform + FHEM that the rooms have been cleaned.
      + After 7 days, the room is set to the error list.
      + However, the room name is not the device name but the readings name and + is changed in the errorFuncAdd attribute. +
    • +
      +
    • + + Operating hours dependent maintenance + (for example, clean the Beamer filter) + +
      +
      defmod BeamerFilter_monitoring monitoring Beamer_HourCounter:pulseTimeOverall BeamerFilter_DashButton:.*:.short
      +attr BeamerFilter_monitoring userattr errorInterval
      +attr BeamerFilter_monitoring errorFuncAdd {return 1\
      +   if(ReadingsVal($name, "pulseTimeOverall", 0) >= \
      +        ReadingsVal($name, "pulseTimeService", 0)\
      +      + (AttrVal($SELF, "errorInterval", 0))\
      +      && $addMatch\
      +   );;\
      + return;;\
      +}
      +attr BeamerFilter_monitoring errorFuncRemove {return unless($removeMatch);;\
      + fhem(\
      +    "setreading $name pulseTimeService "\
      +   .ReadingsVal($name, "pulseTimeOverall", 0)\
      + );;\
      + return 1;;\
      +}
      +attr BeamerFilter_monitoring errorInterval 60*60*200
      +attr BeamerFilter_monitoring errorReturn {return unless(@errors);;\
      + return "Der Filter vom Beamer muss gereinigt werden.";;\
      +}
      +attr BeamerFilter_monitoring warningFuncAdd {return}
      +attr BeamerFilter_monitoring warningFuncRemove {return}
      + An HourCounter is used to record the + operating hours of a beamer and a + DashButton to tell FHEM that the filter + has been cleaned.
      + If the filter has not been cleaned for more than 200 hours, the device + is set to the error list.
      + If cleaning is acknowledged with the DashButton, the device is removed + from the error list and the current operating hours are stored in the + HourCounter device. +
    • +
    +
+
+ +=end html + +=begin html_DE + + +

monitoring

+( en | de ) +
+
    + Jedes monitoring verfügt über eine warning- und eine error-Liste, + welche als Readings gespeichert werden.
    + Beim auftreten eines definierten add-events wird das Gerät nach einer + vorgegeben Zeit auf die warning-Liste gesetzt.
    + Nach einer weiteren vorgegeben Zeit wird das Gerät von der + warning-Liste gelöscht und auf die error-Liste gesetzt.
    + Beim auftreten eines definierten remove-events wird das Gerät von + beiden Listen gelöscht und noch laufende Timer abgebrochen.
    + Hiermit lassen sich auf einfache Weise Sammelmeldungen erstellen und durch + zwei Attribute formatiert ausgeben.
    +
    + Folgende Anwendungen sind möglich und werden + unten beschrieben:
    +
      +
    • geöffnete Fenster
    • +
    • Batterie Warnungen
    • +
    • Activity Monitor
    • +
    • + regelmäßige Wartungsarbeiten + (z.B. Tischwasserfilter wechseln oder Räume putzen) +
    • +
    • + Betriebsstunden abhängige Wartungsarbeiten + (z.B. Beamer Filter reinigen) +
    • +
    +
    + Das monitor sendet selbst keine Benachrichtung, hierfür ist ein notify + oder DOIF notwendig, welches auf das Event "<monitoring-name> error + add: <name>" reagiert und dann den Rückgabewert von + "get <monitoring-name> default" versendet. +
    +
    + + Define +
      + + define <name> <add-event> [<remove-event>] + +
      + Die Syntax für <add-event> und <remove-event> ist die + gleiche wie für das Suchmuster von + notify (Gerätename + oder Gerätename:Event).
      + Ist nur ein <add-event> definiert wird beim auftreten das + Gerät von beiden Listen gelöscht und die Timer für warning + und error werden gestartet.
      +
    +
    + + Set +
      +
    • + active
      + Es passieren zwei Dinge:
      + 1. Stellt noch ausstehende Timer wieder her, bzw. setzt die Geräte + sofort auf die entsprechende Liste, falls der Zeitpunkt in der + Vergangenheit liegt.
      + 2. Führt die unter dem Attribut "setActiveFunc" angegeben Befehle + aus. +
    • +
    • + clear (warning|error|all)
      + Entfernt alle Geräte von der angegeben Liste und bricht für + diese Liste laufende Timer ab. Bei "all" werden alle Geräte von + beiden Listen entfernt und alle laufenden Timer abgebrochen. +
    • +
    • + errorAdd <name>
      + Fügt <name> zu der error-Liste hinzu. +
    • +
    • + errorRemove <name>
      + Entfernt <name> von der error-Liste. +
    • +
    • + inactive
      + Deaktiviert das monitoring. Beachte den leichten semantischen + Unterschied zum disable Attribut: "set inactive" wird bei einem + shutdown automatisch in fhem.state gespeichert, es ist kein save + notwendig. +
    • +
    • + warningAdd <name>
      + Fügt <name> zu der warning-Liste hinzu. +
    • +
    • + warningRemove <name>
      + Entfernt <name> von der warning-Liste. +
    • +
    +
    + + Get +
      +
    • + all
      + Gibt, durch eine Leerzeile getrennt, die error- und warning-Liste + zurück.
      + Die Formatierung kann dabei mit den Attributen "errorReturn" und + "warningReturn" eingestellt werden. +
    • +
    • + default
      + Der "default" Wert kann in dem Attribut "getDefault" festgelegt werden + und ist dazu gedacht um die Konfiguration für den + Rückgabewert im monitoring Gerät zu belassen. Wird nichts + angegeben wird "all" verwendent. +
    • +
    • + error
      + Gibt die error-Liste zurück.
      + Die Formatierung kann dabei mit dem Attribut "errorReturn" eingestellt + werden. +
    • +
    • + warning
      + Gibt die warning-Liste zurück.
      + Die Formatierung kann dabei mit dem Attribut "warningReturn" + eingestellt werden. +
    • +
    +
    + + Readings
    +
      +
    • + error
      + Durch Komma getrennte Liste von Geräten. +
    • +
    • + errorAdd_<name>
      + Zeigt den Zeitpunkt an wann das Gerät auf die error-Liste gesetzt + wird. +
    • +
    • + state
      + Zeigt den Status (active, inactive oder disabled) an. Bei "active" wird + angezeigt welches Gerät zu welcher Liste hinzugefügt bzw. von welcher + Liste entfernt wurde. +
    • +
    • + warning
      + Durch Komma getrennte Liste von Geräten. +
    • +
    • + warningAdd_<name>
      + Zeigt den Zeitpunkt an wann das Gerät auf die warning-Liste + gesetzt wird. +
    • +
    +
    + + Attribute +
      +
    • + + addStateEvent + +
    • +
    • + disable (1|0)
      + 1: Deaktiviert das monitoring.
      + 0: siehe "set active" +
    • +
    • + + disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ... + +
    • +
    • + errorFuncAdd {<perl code>}
      + In dieser Funktion stehen die folgende Variablen zur Verfügung: +
      +
        +
      • + $name
        + Name des Event auslösenden Gerätes +
      • +
      • + $event
        + Beinhaltet das komplette Event, z.B. + measured-temp: 21.7 (Celsius) +
      • +
      • + $addMatch
        + Hat den Wert 1, falls das add-event zutrifft +
      • +
      • + $removeMatch
        + Hat den Wert 1, falls das remove-event zutrifft +
      • +
      • + $SELF
        + Eigenname des monitoring +
      • +
      + Gibt die Funktion eine 1 zurück, wird das Gerät, nach der + Wartezeit, auf die error-Liste gesetzt.
      + Wenn das Attribut nicht gesetzt ist wird auf $addMatch + geprüft. +
    • +
    • + errorFuncRemove {<perl code>}
      + In dieser Funktion stehen die selben Variablen wie bei "errorFuncAdd" + zur Verfügung.
      + Gibt die Funktion eine 1 zurück, wird das Gerät von der + error-Liste entfernt und noch laufende Timer werden abgebrochen.
      + Wenn das Attribut nicht gesetzt ist wird bei einer DEF mit + <remove-event> auf $removeMatch + geprüft und bei einer DEF ohne <remove-event> + auf errorFuncAdd. +
    • +
    • + errorWait <perl code>
      + Wartezeit bis das Gerät auf die error-Liste gesetzt wird. +
    • +
    • + errorReturn {<perl code>}
      + In diesem Attribut stehen folgende Variablen zur Verfügung: +
        +
      • + @errors
        + Array mit allen Geräten auf der error-Liste. +
      • +
      • + @warnings
        + Array mit allen Geräten auf der warning-Liste. +
      • +
      • + $SELF
        + Eigenname des monitoring +
      • +
      + Mit diesem Attribut kann die Ausgabe die mit "get <name> error" + erzeugt wird angepasst werden. +
    • +
    • + getDefault (all|error|warning)
      + Mit diesem Attribut kann festgelegt werden welche Liste/n mit "get + <name> default" zurück gegeben wird/werden. Wenn das + Attribut nicht gesetzt ist wird "all" verwendet. +
    • +
    • + setActiveFunc <Anweisung>
      + Die Anweisung ist einer der FHEM + Befehlstypen und wird beim definieren des + monitoring oder bei "set active" ausgeführt.
      + Für eine Batterie Meldung kann "trigger battery=low + battery:low" sinnvoll sein. +
    • +
    • + warningFuncAdd {<perl code>}
      + Wie errorFuncAdd, nur für die warning-Liste. +
    • +
    • + warningFuncRemove {<perl code>}
      + Wie errorFuncRemove, nur für die warning-Liste. +
    • +
    • + warningWait <perl code>
      + Wie errorWait, nur für die warning-Liste. +
    • +
    • + warningReturn {<perl code>}
      + Wie errorReturn, nur für die warning-Liste. +
    • +
    • + + readingFnAttributes + +
    • +
    +
    + + Beispiele +
      + + + Die folgenden beispiel Codes können per "Raw defnition" + importiert werden. + + +

      +
    • + + Globale, flexible Fenster-/Tür-Offen-Meldungen + + (ähnlich wie im Forum beschrieben) + + +
      +
      defmod Fenster_monitoring monitoring .*:(open|tilted) .*:closed
      +attr Fenster_monitoring errorReturn {return unless(@errors);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@errors);;\
      + return("Das Fenster \"$errors[0]\" ist schon länger geöffnet.") if(int(@errors) == 1);;\
      + @errors = sort {lc($a) cmp lc($b)} @errors;;\
      + return(join("\n - ", "Die folgenden ".@errors." Fenster sind schon länger geöffnet:", @errors))\
      +}
      +attr Fenster_monitoring errorWait {AttrVal($name, "winOpenTimer", 60*10)}
      +attr Fenster_monitoring warningReturn {return unless(@warnings);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@warnings);;\
      + return("Das Fenster \"$warnings[0]\" ist seit kurzem geöffnet.") if(int(@warnings) == 1);;\
      + @warnings = sort {lc($a) cmp lc($b)} @warnings;;\
      + return(join("\n - ", "Die folgenden ".@warnings." Fenster sind seit kurzem geöffnet:", @warnings))\
      +}
      + Sobald ein Gerät ein "open" oder "tilded" Event auslöst wird + das Gerät auf die warning-Liste gesetzt und es wird ein Timer + gestartet nach dessen Ablauf das Gerät von der warning- auf die + error-Liste verschoben wird. Die Wartezeit kann für jedes + Gerät per userattr "winOpenTimer" festgelegt werden. Der + Vorgabewert sind 10 Minuten.
      + Sobald ein Gerät ein "closed" Event auslöst wird das + Gerät von beiden Listen gelöscht und noch laufende Timer + werden gestoppt. +
    • +
      +
    • + Batterieüberwachung
      +
      defmod Batterie_monitoring monitoring .*:battery:.low .*:battery:.ok
      +attr Batterie_monitoring errorReturn {return unless(@errors);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@errors);;\
      + return("Bei dem Gerät \"$errors[0]\" muss die Batterie gewechselt werden.") if(int(@errors) == 1);;\
      + @errors = sort {lc($a) cmp lc($b)} @errors;;\
      + return(join("\n - ", "Die folgenden ".@errors." Geräten muss die Batterie gewechselt werden:", @errors))\
      +}
      +attr Batterie_monitoring errorWait 60*60*24*14
      +attr Batterie_monitoring warningReturn {return unless(@warnings);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@warnings);;\
      + return("Bei dem Gerät \"$warnings[0]\" muss die Batterie demnächst gewechselt werden.") if(int(@warnings) == 1);;\
      + @warnings = sort {lc($a) cmp lc($b)} @warnings;;\
      + return(join("\n - ", "Die folgenden ".@warnings." Geräten muss die Batterie demnächst gewechselt werden:", @warnings))\
      +}
      + Sobald ein Gerät ein "battery: low" Event auslöst wird das + Gerät auf die warning-Liste gesetzt und es wird ein Timer + gestartet nach dessen Ablauf das Gerät von der warning- auf die + error-Liste verschoben wird. Die Wartezeit ist auf 14 Tage + eingestellt.
      + Sobald ein Gerät ein "battery: ok" Event auslöst wird das + Gerät von beiden Listen gelöscht und noch laufende Timer + werden gestoppt. +
    • +
      +
    • + Activity Monitor
      +
      defmod Activity_monitoring monitoring .*:.*
      +attr Activity_monitoring errorReturn {return unless(@errors);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@errors);;\
      + return("Das Gerät \"$errors[0]\" hat sich seit mehr als 24 Stunden nicht mehr gemeldet.") if(int(@errors) == 1);;\
      + @errors = sort {lc($a) cmp lc($b)} @errors;;\
      + return(join("\n - ", "Die folgenden ".@errors." Geräten haben sich seit mehr als 24 Stunden nicht mehr gemeldet:", @errors))\
      +}
      +attr Activity_monitoring errorWait 60*60*24
      +attr Activity_monitoring warningReturn {return unless(@warnings);;\
      + $_ = AttrVal($_, "alias", $_) foreach(@warnings);;\
      + return("Das Gerät \"$warnings[0]\" hat sich seit mehr als 12 Stunden nicht mehr gemeldet.") if(int(@warnings) == 1);;\
      + @warnings = sort {lc($a) cmp lc($b)} @warnings;;\
      + return(join("\n - ", "Die folgenden ".@warnings." Geräten haben sich seit mehr als 12 Stunden nicht mehr gemeldet:", @warnings))\
      +}
      +attr Activity_monitoring warningWait 60*60*12
      + Geräte werden erst überwacht, wenn sie mindestens ein Event + ausgelöst haben. Sollte das Gerät in 12 Stunden kein weiterer + Event auslösen, wird es auf die warning-Liste gesetzt. Sollte das + Gerät in 24 Stunden kein weiteres Event auslösen, wird es von + der warning- auf die error-Liste verschoben. +
    • +
      +
    • + + regelmäßige Wartungsarbeiten + (z.B. Tischwasserfilter wechseln) + +
      +
      defmod Wasserfilter_monitoring monitoring Wasserfilter_DashButton:.*:.short
      +attr Wasserfilter_monitoring errorReturn {return unless(@errors);;\
      + return "Der Wasserfilter muss gewechselt werden.";;\
      +}
      +attr Wasserfilter_monitoring errorWait 60*60*24*30
      +attr Wasserfilter_monitoring warningReturn {return unless(@warnings);;\
      + return "Der Wasserfilter muss demnächst gewechselt werden.";;\
      +}
      +attr Wasserfilter_monitoring warningWait 60*60*24*25
      + Hierbei wird ein DashButton genutzt um + FHEM mitzuteilen, dass der Wasserfilter gewechselt wurde.
      + Nach 30 Tagen wird der DashButton auf die error-Liste gesetzt. +
    • +
      +
    • + + regelmäßige Wartungsarbeiten + (z.B. Räume putzen) + +
      +
      defmod putzen_DashButton dash_dhcp
      +attr putzen_DashButton allowed AC:63:BE:2E:19:AF,AC:63:BE:49:23:48,AC:63:BE:49:5E:FD,50:F5:DA:93:2B:EE,AC:63:BE:B2:07:78
      +attr putzen_DashButton devAlias ac-63-be-2e-19-af:Badezimmer\
      +ac-63-be-49-23-48:Küche\
      +ac-63-be-49-5e-fd:Schlafzimmer\
      +50-f5-da-93-2b-ee:Arbeitszimmer\
      +ac-63-be-b2-07-78:Wohnzimmer
      +attr putzen_DashButton event-min-interval .*:5
      +attr putzen_DashButton port 6767
      +attr putzen_DashButton userReadings state {return (split(":", @{$hash->{CHANGED}}[0]))[0];;}
      +attr putzen_DashButton widgetOverride allowed:textField-long devAlias:textField-long
      +
      +defmod putzen_monitoring monitoring putzen_DashButton:.*:.short
      +attr putzen_monitoring errorFuncAdd {$event =~ m/^(.+):/;;\
      + $name = $1;;\
      + return 1;;\
      +}
      +attr putzen_monitoring errorReturn {return unless(@errors);;\
      + return("Der Raum \"$errors[0]\" muss wieder geputzt werden.") if(int(@errors) == 1);;\
      + return(join("\n - ", "Die folgenden Räume müssen wieder geputzt werden:", @errors))\
      +}
      +attr putzen_monitoring errorWait 60*60*24*7
      + Hierbei werden mehrere DashButton + genutzt um FHEM mitzuteilen, dass die Räume geputzt wurden.
      + Nach 7 Tagen wird der Raum auf die error-Liste gesetzt.
      + Der Raum Name ist hierbei jedoch nicht der Geräte-Name, sondern der + Readings-Name und wird in dem errorFuncAdd-Attribut + geändert. +
    • +
      +
    • + + Betriebsstunden abhängige Wartungsarbeiten + (z.B. Beamer Filter reinigen) + +
      +
      defmod BeamerFilter_monitoring monitoring Beamer_HourCounter:pulseTimeOverall BeamerFilter_DashButton:.*:.short
      +attr BeamerFilter_monitoring userattr errorInterval
      +attr BeamerFilter_monitoring errorFuncAdd {return 1\
      +   if(ReadingsVal($name, "pulseTimeOverall", 0) >= \
      +        ReadingsVal($name, "pulseTimeService", 0)\
      +      + (AttrVal($SELF, "errorInterval", 0))\
      +      && $addMatch\
      +   );;\
      + return;;\
      +}
      +attr BeamerFilter_monitoring errorFuncRemove {return unless($removeMatch);;\
      + fhem(\
      +    "setreading $name pulseTimeService "\
      +   .ReadingsVal($name, "pulseTimeOverall", 0)\
      + );;\
      + return 1;;\
      +}
      +attr BeamerFilter_monitoring errorInterval 60*60*200
      +attr BeamerFilter_monitoring errorReturn {return unless(@errors);;\
      + return "Der Filter vom Beamer muss gereinigt werden.";;\
      +}
      +attr BeamerFilter_monitoring warningFuncAdd {return}
      +attr BeamerFilter_monitoring warningFuncRemove {return}
      + Hierbei wird ein HourCounter genutzt + um die Betriebsstunden eine Beamer zu erfassen und ein + DashButton um FHEM mitzuteilen, dass der + Filter gereinigt wurde.
      + Wurde der Filter länger als 200 Betriebsstunden nicht gereinigt + wird das Gerät auf die error-Liste gesetzt.
      + Wurde die Reinigung mit dem DashButton quittiert wird das Gerät + von der error-Liste entfernt und der aktuelle Betriebsstunden-Stand in + dem HourCounter Gerät gespeichert. +
    • +
    +
+
+ +=end html_DE +=cut diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index d9bf182e3..3a70646ed 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -413,6 +413,7 @@ FHEM/98_HourCounter.pm john http://forum.fhem.de MAX FHEM/98_logProxy.pm justme1968 http://forum.fhem.de Frontends/SVG Plots logProxy FHEM/98_mark.pm betateilchen http://forum.fhem.de Sonstiges FHEM/98_MaxScanner.pm john http://forum.fhem.de MAX +FHEM/98_monitoring.pm igami http://forum.fhem.de Unterstuetzende Dienste FHEM/98_notice.pm mfr69bs http://forum.fhem.de Sonstiges FHEM/98_pilight.pm andreas-fey http://forum.fhem.de Unterstuetzende Dienste FHEM/98_ping mattwire http://forum.fhem.de Sonstiges