Batterieüberwachung

Aus FHEMWiki
Version vom 3. Oktober 2016, 15:11 Uhr von Fabian (Diskussion | Beiträge) (→‎Geräte ohne Batteriestatus: Batteriestatus via userReading eingefügt)

Geräte mit Batteriestatus

Homematic-Komponenten und teilweise andere Komponenten (RFXtrx, ZWave,..) übermitteln unter anderem den Zustand der eingelegten Batterie. Um Ausfälle frühzeitig zu erkennen, kann man sich per E-Mail benachrichtigen lassen, sobald eine Batteriemeldung mit etwas anderem als "ok" gesendet wird (z.B. "low"). Zusätzlich erzeugt der unten stehende Code einen Eintrag im Logfile.

define n_batt_chk notify .*:[Bb]attery.* { if ($EVENT !~ m/ok/) { \
  { FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \
   Log 3, "$NAME : Batteriewarnung $EVENT";; \
  } \
 }

Achtung: Für Nutzer eines HM-CC-RT-DN muss der Code anders aussehen, da mit diesem Thermostat erstmalig der aktuelle Spannungswert der Batterie gesendet wird, also z.B.:

UG.Treppe.Heizung batteryLevel: 3.1 V

Man würde bei der Verwendung des o.g. Codes bei jeder Batteriemeldung eines HM-CC-RT-DN eine E-Mail erhalten. Daher muss der o.g. Code wie folgt geändert werden (Doppelpunkt hinter "[Bb]attery"):

define n_batt_chk notify .*:[Bb]attery:.* { if($EVENT !~ m/ok/) { \
  { FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \
   Log 3, "$NAME: Batteriewarnung $EVENT";; \
  } \
 }

Achtung: FB_mail setzt die Installation auf einer FritzBox voraus. Für andere Hardware-/OS-Plattformen ist die Vorgehensweise unter dem Titel E-Mail_senden beschrieben.

Testen kann man dies z.B. mit trigger HeizungWZ Battery:low

Man sollte auch darauf achten, dass sich das Ereignis, auf das man triggert, nicht zu häufig wiederholt (z.B. durch das Attribut event-on-change-reading).

Geräte ohne Batteriestatus

Erweiterung des Geräts um battery-Reading

Mit Hilfe von userReadings kann man recht einfach einen Batteriestatus schätzen und als Reading bereitstellen. Dann greift auch direkt die oben beschriebene Auswertung.

Die Idee ist, den zeitlichen Abstand des aktuellen Timestamps mit dem letzten geloggten Timestamp zu vergleichen und daraus auf den Batteriestatus zu schliessen - bspw. Abstand > 10min = Batterie low.

Dazu muss lediglich folgendes userReading für jedes batteriebetriebene Device (ohne Batteriestatus) angelegt werden (um bei >10min "low" zu setzen):

Anzupassen ist nur der Schwellwert (600), alles andere passt automatisch (vgl. [1]).

Im Webinterface:

battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );; return "low" }

Alternativ im Config-File:

attr MeinSensor userReadings battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );;;; return "low" }
Erläuterung
battery {...} - Name des userreadings mit Spezifikation, vgl. [2]
return "ok" if ( ... );; return "low" - Spezifikation: Reading = "ok", wenn if erfüllt, sonst "low"
time_str2num(ReadingsTimestamp($NAME,"state","0") - Aktueller Timestamp in Sekunden, vgl. [3], [4]
time_str2num(OldTimestamp($NAME)) - Letzter Timestamp im Log in Sekunden (egal ob FileLog oder DbLog), vgl. [5], [6]
600 - Schwellwert für "low" (600 sec = 10 min)


Per Skript

Andere Komponenten, wie z. B. FS20 Komponenten, übermitteln keinen Batteriestatus.

Um dort dennoch einen Test darauf zu machen, ob die Batterie evtl. leer ist, kann man z. B. prüfen, wann der letzte Status des jeweiligen Gerätes empfangen wurde, etwa mit folgender Funktion in 99_myUtils.pm:

sub check_if_alive($$) {
  # Expects:
  # 1. Devicename to be checked
  # 2. Age in hours, after the expiry of which with no new state the device will be considered as dead.
  # Returns:
  # 0 -> Device dead
  # 1 -> Device alive
  # 2 -> Error
  my ($Device,$hours_threshold) = @_;
  my ($Device) = @_;
  my $now = time;
  my $Timestamp = ReadingsTimestamp($Device,"state","0");
  if ($Timestamp eq "0") {
    return 2;
  }

  my @splitdatetime = split(/ /,$Timestamp);
  my @splitdate = split(/-/, $splitdatetime[0]);
  my @splittime = split(/:/, $splitdatetime[1]);
  my $last_state_time =  timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);
  my $age_in_hours = ($now - $last_state_time) / 3600;

  if ($age_in_hours > $hours_threshold) {
    Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");
    return 0;
  } else {
    return 1;
  }
   
}

Diese Funktion kann man z.B. in einem at je zu prüfendem Gerät regelmäßig (z. B. einmal am Tag um 05:55 Uhr) aufrufen, und testen, ob die letzten 12 Stunden etwas empfangen wurde:

*05:55:55 { 
  check_if_alive("KS300", 12);
}

KS300 ist dabei der Name des Devices in fhem.

Wenn das Gerät nicht geantwortet hat, erzeugt die oben vorgeschlagene Funktion einen Logeintrag.

Hinweis: Dieser Batterietest schlägt natürlich auch an, wenn die FS20 Geräte noch funktionieren, aber der CUL zum Empfangen der Signale nicht mehr funktioniert. In dem Fall sind dann auf einen Schlag angeblich alle Batterien leer. Um dies zumindest teilweise abzufangen, könnte man vor dem Erzeugen des Logeintrags noch auf den state des CUL testen, dass dieser nicht "disconnected" ist.

Visualisierung

Der Abschnitt Links unten enthält einen Verweis, wie man den Batteriestatus visuell anzeigen kann. Das funktioniert mit der oben vorgeschlagenen Funktion mit einigen Ergänzungen auch, wenn das Gerät selbst keinen Batteriestatus anzeigt.

Dafür braucht man einen zusätzlichen Dummy je zu überwachendem Gerät, mit dem Namen dum_<zu_überwachendes_Gerät>_dead. Für das Gerät KS300 heißt dieser dummy also z. B. dum_KS300_dead:

Internals: 
   NAME       dum_KS300_dead 
   NR         795 
   STATE      nein 
   TYPE       dummy 
   Readings: 
     2015-04-28 07:47:48   state           nein 
Attributes: 
   devStateIcon ja:measure_battery_50@red nein:measure_battery_100@green

Dieser dummy soll hier die Zustände "ja" und "nein" annehmen können. Bei ja ist ihm über devStateIcon ein rotes Icon einer eher leeren Batterie zugewiesen, bei nein ein grünes Icon einer vollen Batterie.

Nun muss noch die oben vorgeschlagene Funktion angepasst werden, um den Zustand des dummy entsprechend dem ermittelten Batteriestatus neu zu setzen. Dafür wird die Abfrage des Alters am Ende der Funktion um eine Zeile erweitert, die den Status des dummy setzt:

  if ($age_in_hours > $hours_threshold) {
    Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");
    fhem("set dum_".$Device."_dead ja");
    return 0;
  } else {
    fhem("set dum_".$Device."_dead nein");
    return 1;
  }

Den Dummy mit diesem devStateIcon kann man so der unter "Links" unten vorgeschlagenen readingsGroup hinzufügen, und damit auch Geräte ohne eigenen Batteriestatus überwachen.

Links

Siehe auch visuelle Batterieüberwachung mit readingsGroup.