neues Modul 98_readingsWatcher , war 98_ReadingsSupervision

Begonnen von Wzut, 15 Februar 2016, 20:49:53

Vorheriges Thema - Nächstes Thema

mac1001

Guten Morgen,

kann es sein das sich das Modul nicht inactive setzen lässt oder ist mit "set inactive" nicht die Abschaltung der Überwachung gemeint?

Gruß Marco
FHEM ZBoxNano Debian9, nanoCUL 868MHz, MAX!, Sonoff S20&Pow, Shelly1&2.5, WemosD1Mini&SDM230-Modbus, Raspi3&ConBeeII&Phoscon, Hue Lights, Xiaomi Sensors, espRGBWW

Wzut

Hust, da scheint wohl jemand vergessen zu haben den inactive state in der sub OnTimer anbzufragen .... :(
Im Moment wirst du wohl nur mit disable 1 dein Ziel erreichen.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

mac1001

Danke für Dein rasanten Support, das hilft mir erstmal weiter [emoji106]

Gesendet von meinem Pixel 3 mit Tapatalk

FHEM ZBoxNano Debian9, nanoCUL 868MHz, MAX!, Sonoff S20&Pow, Shelly1&2.5, WemosD1Mini&SDM230-Modbus, Raspi3&ConBeeII&Phoscon, Hue Lights, Xiaomi Sensors, espRGBWW

dirk.k

1. Erst mal Danke für das tolle Modul. Es löst bei mir äußerst zufriedenstellend alle möglichen Bastellösungen für div. Geräte ab.

nur ein paar Kleinigkeiten:
- In Antwort #39 schreibst du, dass das Atribut "client-event" rausgeflogen ist, "da es heute keine Events des überwachten Gerätes mehr gibt,"
Die ??? lösen bei mir aber trotzdem bei jedem Prüfungsintervall Events aus und die Kurven sind versaut. (Lücken wären besser)

- die Einstellung "attr myReadingsWatcher readingActivity activ:0:1" führt bei mir dazu, dass am Geräte-Reading activ der Wert dead oder 1 steht.

Grüsse, Dirk

Wzut

- das sollte natürlich nicht sein , schau ich mir heute Abend an
- und wenn du activ:1:0 setzt bekommst du vermutlich 1 oder alive , np. das habe ich sofort gefunden
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

Wzut

also ich habe jetzt nochmal nachgeschaut und auch getestet
- um Events des überwachten Device zu vermeiden nutzt das Modul zum ersetzen eines Readings die FHEM interne Funktion
setReadingsVal und genau wie erwartet erzeugt die bei mir keinerlei Events. Kann es sein das du noch andere Hilfen am Start hast wie z.B. hier -> https://wiki.fhem.de/wiki/Plot-Abriss_vermeiden beschrieben ? Dann wäre es klar wie der Ersatz Wert in die Datei kommt.

- activ 0/alive habe ich gefixt und ist im nächsten Update
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

dirk.k

Hallo,
ich habe jetzt an einem Gerät mit überwachten readings ein "künstliches" reading angelegt, welches nicht aktualisiert wird und dieses in die Überwachung aufgenommen.
Das positive ... es sieht so aus, als wenn kein Event erzeugt wird, wenn die ??? eingetragen werden. Keine Ahnung wo das bei dem anderen herkam. Prüfe ich später
Aber ... nur springt das Gerät ständig zwischen activ:1 und activ:dead hin und her.
Ich habe also alle 90 sekunden die tot-sowie die alive Meldung.
Ich habe mehrere Geräte, welche einzelne Sensoren mit "sendeausfällen" haben. Einen konsequenten Gerätestatus (tot oder lebend) würde ich mir hier wünschen. (bevorzugt: wenn ein überwachtes reading aktualisiert wird, lebt das Gerät)

Wzut

sorry, aber das kann ich nicht nachvollziehen. Wenn ein überwachtes Reading nicht aktualisiert wird d.h der Zeitstempel bleibt gleich, bleibt auch der Actifity Status bestehen.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

dirk.k

Ich habe aber am selben Gerät mehrere readings überwacht (in diesem Testgerät sind das testreading,temperature,humidity ).
Wenn nur eines Ausfällt (hier halt das testreading) ist das neue Reading "activ" immer am hin und her schalten.
Im angehängten Bild ist sehr schön zu sehen, temp..&hum... werden regelmäßig aktualisiert, testreading ist tot und der Gerätegesamtstatus (activ) ist gerade "dead". 

Wzut

ja ist klar, für so eine Aufgabenstellung (halbtot) wurde das Modul nicht geschrieben.
 
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

dirk.k

Das ist schade.
Ich habe viele (WLAN-)Geräte mit mehreren Sensoren. Da ist öfter mal ein einzelner Sensor unpässlich.
Findest du die Idee so etwas zu betrachten nützlich? Ich hätte da eine kleine selbstgebastelte Anpassung.(5Zeilen)
Ich würde nämlich gern dein Modul weiter einsetzen und kein angepasstes mit eingefrorenem Stand.

Wzut

dann verrate doch mal deine fünf Zeilen,  wird sich schon irgend etwas daraus zaubern lassen :)
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

dirk.k

Ich habe leider mit SVN und ähnlichem null Erfahrung.
Notepad++ gab mir diese Änderungen aus. Einen ordentlichen Export gibt es hier aber nicht ... daher die Änderungen leider als Screenshots.
Kurze Erläuterung:
Ich habe nicht bei jedem geprüften Reading den Gerätestatus gesetzt, sondern nur die guten readings gezählt und am Ende einen Status gesetzt.
Alles findes im sub OnTimer statt.
- bei "foreach  $deviceName (@devs)"   definiere ich my $LivingDev = 0;
die beiden Zeilen
$error = CommandSetReading(undef, "$deviceName $areading $dead")  und
$error = CommandSetReading(undef, "$deviceName $areading $alive")  habe ich auskommentiert
und stattdessen die Readings ohne Fehler gezählt .. mittels $LivingDev++;
zum Schluss bei 0 funktionierenden readings dead und sonst alive gesendet ... wie es im Originalcode verwendet wurde. 
CodeAnpassung in sub OnTimer($):
sub OnTimer($)
{
  my ($hash) = @_;
  my $name = $hash->{NAME};
  my $interval = AttrNum($name, 'interval', 0);
  $hash->{INTERVAL} = $interval;
  RemoveInternalTimer($hash);

  return if (!$interval);

  InternalTimer(gettimeofday()+$interval, 'FHEM::readingsWatcher::OnTimer', $hash, 0);

  readingsSingleUpdate($hash, 'state', 'disabled', 0) if (IsDisabled($name));
  return if(IsDisabled($name) || !$init_done);

  my ($timeOutState, $errorValue, $timeout, $associated, $error, $readingsList);
  my ($deviceName, $rSA, $age, @devices, $rts, @parts, @devs);
  my ($alives, $deads, $state, $readings) = (0, 0, '', 0);
  my @timeOutdevs = ();

  foreach (keys %{$defs{$name}{READINGS}}) # alle eignen Readings
  { $readingsList .=  $_ .',' if ($_ =~ /_/); }# nur die mit _ im Namen

  @devs = devspec2array("readingsWatcher!=");

  my ($areading,$dead,$alive) = split(":",AttrVal($name,'readingActivity','none:dead:alive'));
  $dead = 'dead'  if(!$dead);
  $alive= 'alive' if(!$alive);
  $areading = ''  if ($areading eq 'none');

  readingsBeginUpdate($hash);

  foreach  $deviceName (@devs)
  {

    $rSA = ($deviceName eq  $name) ? '' : AttrVal($deviceName, 'readingsWatcher', undef);
my $LivingDev = 0;

    if(defined($rSA) && !IsDisabled($deviceName) && !IsIgnored($deviceName))
    {
      push @devices, $deviceName if  !grep {/$deviceName/} @devices; # keine doppelten Namen

      # rSA: timeout, errorValue, reading1, reading2, reading3, ...
      #      120,---,temperature,humidity,battery
      # or   900,,current,eState / no errorValue = do not change reading

      my @r = split(';', $rSA);
      foreach (@r)
      {
        @parts = split(',', $_);
        if (@parts > 2)
        {
        $timeout    = int($parts[0]);
        $errorValue = $parts[1]; # = leer, Readings des Device nicht anfassen !

        # die ersten beiden brauchen wir nicht mehr
        shift @parts;
        shift @parts;

        foreach (@parts) # alle zu überwachenden Readings
        {
          $_ =~ s/^\s+|\s+$//g; # $_ = Reading Name

          $state = 0;
          if ($_ eq 'STATE')
          {
           $_ = 'state'; $state = 1; # Sonderfall STATE
          }

          $age = ReadingsAge($deviceName, $_, undef);

          if (defined($age))
          {
           $readings++;

           if (($age > $timeout) && ($timeout>0))
           {
             push @timeOutdevs, $deviceName if  !grep {/$deviceName/} @timeOutdevs;
             $timeOutState = "timeout";
             $deads++;
             $rts = ReadingsTimestamp($deviceName, $_,0);
             setReadingsVal($defs{$deviceName},$_,$errorValue,$rts) if ($errorValue && $rts); # leise setzen ohne Event
#             $error = CommandSetReading(undef, "$deviceName $areading $dead") if ($areading); # und das mit Event
             $defs{$deviceName}->{STATE} = $errorValue if ($errorValue && $state);
           }
           else
           {
            $alives++;
            $timeOutState = "ok";
#            $error = CommandSetReading(undef, "$deviceName $areading $alive") if ($areading);
$LivingDev++;
           }

           Log3 $name,2,$name.', '.$error if ($error);

           my $r = $deviceName.'_'.$_;

           readingsBulkUpdate($hash, $r, $timeOutState) if ($timeout>0);
           $readingsList =~  s/$r,// if ($readingsList) ; # das Reading aus der Liste streichen, leer solange noch kein Device das Attr hat !

           if ($timeout < 1)
           {
            $alives--;
            $error = 'Invalid timeout value '.$timeout.' for reading '.$deviceName.'.'.$_;
            Log3 $name,2,$name.', '.$error;
           }
          }#age
          else
          { 
            $error = 'Timestamp for '.$_.' not found on device '.$deviceName;
            Log3 $name,3,$name.', reading '.$error;
            readingsBulkUpdate($hash, $deviceName.'_'.$_, 'no Timestamp');
          }
        }# foreach @parts

if ($LivingDev > 0)
{
   $error = CommandSetReading(undef, "$deviceName $areading $alive") if ($areading);
}
else
{
   $error = CommandSetReading(undef, "$deviceName $areading $dead") if ($areading);
}

       }# parts > 2
       else
       {
         $error = 'insufficient parameters for device '.$deviceName;
         Log3 $name,2,$name.', '.$error.' - skipped !';
       }
      }# if $readingsWatcherAttribute
    }
   }# foreach $deviceName

   readingsBulkUpdate($hash,'readings'       , $readings);
   readingsBulkUpdate($hash,'devices'        , int(@devices));
   readingsBulkUpdate($hash,'alive'          , $alives);
   readingsBulkUpdate($hash,'timeouts'       , $deads);
   readingsBulkUpdate($hash,'state'          , ($deads) ? 'timeout' : 'ok');

   # nicht aktualisierte Readings markieren oder löschen
   if ($readingsList)
   {
     my @a = split(",",$readingsList);
     foreach (@a)
     {
       if ($_)
       {
        if (AttrNum($name,'deleteUnusedReadings','1'))
        {
          readingsDelete($hash, $_);
          Log3 $name,3,$name.', delete unused reading '.$_;
        }
         else
        {
         readingsBulkUpdate($hash, $_ , 'unused');
         Log3 $name,4,$name.', unused reading '.$_;
        }
       }
     }
   }

   if (int(@devices))
   { readingsBulkUpdate($hash,'.associatedWith' , join(',',@devices)); }
   else
   { readingsDelete($hash, '.associatedWith'); }

   if (int(@timeOutdevs))
   { readingsBulkUpdate($hash,'timeoutdevs',join(',',@timeOutdevs));}
   else
   { readingsBulkUpdate($hash,'timeoutdevs','none');}

   readingsEndUpdate($hash, 1);

   return undef;
}

sub Attr (@)
{

my ($cmd, $name, $attrName, $attrVal) = @_;
my $hash = $defs{$name};
my $error;

if ($cmd eq 'set')
{
   if ($attrName eq 'disable')
   {
    readingsSingleUpdate($hash,'state','disabled',1) if ($attrVal == 1);
    OnTimer($hash) if ($attrVal == 0);
    $_[3] = $attrVal;
   }
   if (($attrName eq 'readingActivity') && ($attrVal eq 'state'))
   {
    $_[3] = '';
    my $err = 'forbidden value state !';
    Log3 $name,1,$name.', readingActivity '.$err;
    return $err;
   }
}
elsif ($cmd eq 'del')
{
  if ($attrName eq 'disable')
  {
   OnTimer($hash);
  }
}
   return undef;
}


Screenshots:

Wzut

ok, ich habe es begriffen. Einfach gesagt :
a. wird an einem Device nur ein Reading überwacht -> alles wie bisher
b. bei mehr als einem Readings sollte der User entscheiden (mal schauen wie) ob die einzelen überwachten Readings als UND oder ODER den Gesamtstatus bilden.

Eine einfache Möglichkeit wäre z.B.
attr Thermo1 readingsWatcher 300,???,CUL_RSSI,CUL2_RSSI
heute, Readings werden als ODER behandelt
attr Thermo1 readingsWatcher 300,???,CUL_RSSI+CUL2_RSSI
neu , als UND
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

dirk.k

Gute Idee beide Varianten zu ermöglichen.
Auch die Schreibweise gefällt mir.
Mein Vorschlag hat die "oder Variante" aber nicht beachtet.
Evtl. bräuchte man einen 2. Zähler, damit es nicht wieder zum flappen kommt.
(hauptsächlich das hatte mich ja gestört)
Wenn ich noch helfen kann ...