+ Antworten
Seite 1 von 2 1 2 LetzteLetzte
Ergebnis 1 bis 10 von 11
  1. #1
    Registriert seit
    Sep 2008
    Ort
    Hamburg
    Beiträge
    1,226

    Standard Mit Problemen umgehen - wie ich es mache

    Nachdem mein Beitrag zum Thema automatische Lichtsteuerung ganz interessantes Echo erzeugt hatte, setze ich mich mal an ein weiteres Thema, das mich sehr interessiert und dessen Bedeutung für mich über die Jahre stark zugenommen hat. Es geht auch wieder um (leidvolle) Lernerfahrungen - denn lernen tun wir ja häufig insbesondere aus Fehlern.

    Fire & Forget
    Als ich mit Home Automation anfing war meine sämtliche Aktorik fire and forget. So nennen wir es in der Software salopp, wenn wir irgendeinen Befehl irgendwohin absenden und einfach darauf vertrauen, dass schon alles gut gehen wird. Ich sendete (damals per ELV FS10) halt so meine Schaltbefehle an die Lampen raus, irgendwann periodisch als mir auffiel, dass die Kommandos manchmal nicht ankommen. Das war sozusagen schon eine Stufe über dem klassischen fire and forget, praktisch ein agnostisches Dauerfeuer. Klappte ganz okay.

    Auch auf der Sensorseite vertraute ich blind und ohne großartige Überprüfung auf die ermittelten Werte. Ich tat allerdings auch nicht viel mehr, als diese irgendwo anzuzeigen. Die Heizungsanalge zu steuern hatte ich mich damals noch nicht getraut und das war wohl auch besser so.

    Über die Jahre wuchs die Komplexität meines Systems mit dem Anspruch, nicht bloß simpelste Logik vorzusehen, die nur funktioniert solange jedes Glied in der Kette intakt ist und das richtige tut. Zu oft kam ich in die Situation, dass irgendwo irgendein Teil versagte, aber ich es erst mitbekam, als es richtig störende Folgen hatte. Klassiker war meine Heizungssteuerung. Zuerst nutzte ich zur Gewinnung der Außentemperatur eine externe API. Dass diese seit mehr als einem Monat keine aktuellen Daten mehr hatte, fiel mir erst auf als es draußen kälter wurde und die Heizung aber nicht richtig warm wurde. Später hatte ich einen Temperaturfühler von EQ3 (HomeMatic oder noch HMS) im Einsatz, aber plötzlich schaltete sich mitten im Winter die Heizung ab - es war Wasser in den Fühler eingedrungen und er meldete eine Außentemperatur von 80°C.

    Aus diesen Erfahrungen und der anschließenden, mitunter auch recht zermürbenden Fehlersuche bin ich relativ pingelig geworden, was die Überwachung des korrekten Funktionierens so ziemlich jedes Gerätes in meinem System betrifft. Noch immer ist es bei neuen Geräten oft so, dass ich sie voller Euphorie einbinden will, aber das Abfragen von Störungen (es ist doch nagelneu, was soll schon schiefgehen?) eher nervige Pflicht ist. Trotzdem lohnt es sich, immer einen Blick darauf zu haben, was alles schief laufen könnte. Wir kennen ja Murphy's Gesetz...

    Bei der Hardware fängt es an
    Grundsätzlich ist von Vorteil, wenn die eingesetzte Hardware bereits Diagnosefunktionen bzw. Kanäle zur Störungsmeldung besitzt. Ein Gerät, das so freundlich ist uns selbst mitzuteilen wenn es nicht mehr korrekt funktioniert ist großartig, denn dieser Fall erspart uns viel educated guessing anhand von Sensordaten (dazu später mehr). Ideal sind Geräte wie die von HomeMatic, die spezielle Datenpunkte haben, um Störungen unterscheidbar zu melden. Auch meine Heizungsanlage kann relativ detailliert berichten, wenn etwas schief läuft. Andere Bausteine, etwa das Funkinterface zu den CO- und Hitzemeldern, haben einfach nur einen Ausgang "Sammelstörung" und wenn diese Meldung vorliegt, ist trotzdem einiges an Herumprobieren nötig, um Fehlerort und -ursache zu finden. Aber generell ist es (wie auch bei unseren Mitmenschen) erfreulich, wenn das Gerät mit uns spricht - auch und gerade über Probleme.

    Die Verarbeitung von Störungsmeldungen aller verbundenen Geräte ist Pflicht und das mache ich bei wirklich jedem Gerät, das solche Features bietet. Andere Geräte meide ich nach Möglichkeit ganz.

    Tote reden nicht
    Nicht in jedem Fehlerfall kann uns ein Gerät freundlich über Störungen informieren. Mitunter ist die Störung so gravierend, dass selbst der Teil des Gerätes, der Störungsmeldungen verschicken oder verarbeiten soll, defekt ist. Oder es ist einfach das Kabel defekt, die Spannungsversorgung ausgefallen, oder es gibt einen sonstigen Schaden an der Kommunikationsinfrastruktur.

    Daher ist es neben allen anderen Prüfungen und Fehlerbehandlungen immer notwendig, sog. Watchdogs zu installieren, also Mechanismen, die ein Ausbleiben von Statusmeldungen, Sensormesswerten oder ähnlichen "Lebenszeichen" des Gerätes detektieren.

    Watchdogs setze ich bei jedem Gerät ein, das mir regelmäßige "Lebenszeichen" sendet.

    Plausiblitätsprüfung
    Bei Geräten, die mit hohen Sicherheitsanforderungen konstruiert wurden (etwa einer Heizung) ist davon auszugehen, dass diese selbsttätig die Funktion ihrer Sensoren und in einigen Fällen auch die Plausiblität der gemeldeten Daten überprüfen. Wenn wir allerdings selbst Sensoren benutzen, um damit etwas zu steuern, dann sollten auch wir uns die Mühe machen, einige Prüfungen anzustellen, bevor wir gemeldeten Daten einfach blind vertrauen. Es ist, wenn schon nicht gefährlich, doch zumindest lästig, wenn wir fehlerhafte Sensordaten erst anhand von merkwürdigen Folgeproblemen bemerken.

    Die einfachste Plausiblitätsprüfung sind Ober- und Untergrenzen. Da wir nicht in Sibirien leben ist eine gemeldete Außentemperatur von -25°C vermutlich nicht korrekt, hier im Norden war das Kälteste was ich jemals gemessen hatte -12°C. Und im Sommer sollte es auch nicht 80°C werden, jedenfalls nicht auf einem (noch?) bewohnbaren Planeten wie der Erde. Anhand sinnvoller Grenzwerte kann man also schon Probleme erkennen.

    Außerdem wird ein gemessener Wert gewissen Schwankungen unterliegen. Bekommen wir von einer Datenquelle (egal ob eigener Sonsor oder fremde API) stets den exakt gleichen Messwert über längere Zeit, dann ist dies ein Hinweis darauf, dass etwas nicht stimmt.

    Wer es ganz genau nimmt, kann noch nach auffälligen Sprüngen von Messwerten suchen, die auf Probleme hinweisen können - das ist allerdings dann nicht mehr ganz trivial und birgt auch ein hohes Risiko für Fehlalarme. Ich mache hiervon keinen Gebrauch und setze bei steuerungskritischen Werten lieber auf Redundanz

    Plausiblitätsprüfung mache ich bei allen Messwerten, die ich für Steuerungsaufgaben nutze oder an prominenter Stelle anzeige.

    Doppelt und Dreifach
    In der Luftfahrt und bei KFZ sind einige Sensordaten so kritisch, dass es nicht ausreicht, einfach nur Fehler zu detektieren und zu melden - würden die Sensoren einfach ersatzlos ausfallen, so würden plötzlich wichtige Steuerungen versagen und es könnte zu gefährlichen Situationen kommen. Das System soll möglich auch bei Ausfall einzelner Sensoren weiter funktionieren (natürlich sollte die Störung immer trotzdem gemeldet und alsbald behoben werden).

    Darum sind in den genannten Bereichen viele Sensoren mehrfach vorhanden. Dies bietet neben der Ausfallsicherheit auch die Möglichkeit, die Sensorwerte zu vergleichen, und damit einen weiteren Plausiblitätscheck vorzunehmen.

    Angenommen, ich habe drei oder mehr Datenquellen für die aktuelle Außentemperatur. Melden diese dann 23°C, 22.7°C und 12°C, so deutet dies daraufhin, dass letzterer Wert vermutlich fehlerhaft ist, da die anderen beiden Werte relativ nah beieinander liegen. Voraussetzung für so eine Überprüfung ist natürlich, dass die Datenquellen ausreichend unterschiedlich funktionieren (also nicht bspw den HomeMatic-Doppel-Temperatursensor benutzen, um zwei Temperaturwerte zu bekommen, denn im Fehlerfall könnten diese ja beide vom selben Fehler betroffen sein).

    Redundanz benutze ich bei kritischen Messwerten in Steuerskripten, soweit es technisch mit vertretbarem Aufwand möglich ist.

    Bitte melde dich!
    Wenn ich nun also mit viel Fleiß alle denkbaren Probleme, Fehler und Störungen überwache, was tue ich mit diesen Informationen? Es nutzt ja nicht viel, wenn ich diese Dinge irgendwo in ein Log schreibe, aber dann nie in dieses Log hinein sehe. Oder wenn die Werte zwischen uninteressanten Statusmeldungen einfach untergehen.

    Ich habe bei meinem System eine tägliche Benachrichtigung per Email, in der alle Meldungen, kritische und eher unkritische zusammengefasst sind. Das ist sehr nützlich und ich lese diese auch wirklich jeden Tag (auch wenn manche Batteriemeldung auch mal ein, zwei Tage lang unbearbeitet bleibt).

    Zusätzlich gibt es bestimmte Störungen, über die ich mich sofort informieren lasse. Beispielsweise will ich sofort (und nicht erst am nächsten Morgen mit dem täglichen Report) mitbekommen, wenn die Heizung ausfällt, oder sonstige wichtige Komponenten wie die Verbindung zum LCN oder zu HomeMatic. Ähnlich verhält es sich natürlich mit Alarmmeldungen, aber das ist nochmal ein anderes Thema.

    Konsequenz und Selbstheilung
    Bei gewissen Problemen ist es logisch, dass man als Konsequenz bestimmte Aktionen auslösen möchte. Besitzt man beispielsweise ein elektrisches Ventil, um die Wasserzufuhr zu unterbrechen, so möchte man bei Hinweisen auf austretendes Wasser dieses vermutlich schließen.

    In einigen seltenen Fällen ist es auch bei "Softwareproblemen" möglich und sinnvoll, automatisch Skripte zur Behebung des Problems auszuführen. Früher hatte ich sogar mal Skripte, die automatisch IPS oder den Rechner neu starten. Das funktionierte aber selten gut und habe ich so nicht mehr in Betrieb.

    Was ich aktuell noch in Betrieb habe ist ein Skript zum automatischen Beheben von Verbindungsproblemen über Netzwerk-USB-Hubs. Nicht weil das besonders elegant wäre, sondern weil es leider nötig ist, aber immerhin klappt es, das zu automatisieren. Auch bei den Ebusd-MQTT-Devices für die Heizung habe ich Skripte, die bei Instanzfehlern automatisch diese reinitialisieren.

    Solche Methoden sind aber stets als Workarounds zu betrachten, denn sie beheben ja nicht die eigentliche Ursache des Problems, sondern mildern lediglich die Folgen ab.

    Profil zeigen
    Neben der oben beschriebenen Meldung per "Wartungs-Übersichts-Seite"/Email bin ich dazu übergegangen, bei Problemen, die ein bestimmtes Gerät betreffen, dies auch in der Bedienoberfläche des Gerätes anzuzeigen. Also beispielsweise möchte ich, wenn ein LCN-Busmodul nicht erreichbar ist, gerne beim Bedienfeld für die betroffenen Leuchten, dass dort statt dem üblichen Slider ein Fehlerstatus angezeigt wird. Ähnlich ist es bei den Raumthermostaten - wenn ein HomeMatic-Raumthermostat UNREACH ist, dann will ich dort eine Meldung im WebFront anstatt der üblichen Bedienelemente. Bei Sensoren wiederum will ich eben auch eine Warnung anzeigen, wenn etwas nicht stimmt und zwar an der gleichen Stelle, wo ich sonst den Messwert sehe.

    Ich löse dies über Skripte, die dynamisch das Variablenprofil der entsprechenden Variable (Sensorwert oder auch Dimmstufe / Stellwert / Modus) durch ein spezielles "Fehlerprofil" austauschen können. Letzteres besteht einfach nur aus einer einzigen Association in rot mit einer Warnmeldung als Text. Dadurch erreiche ich einen sehr übersichtlichen und eindeutigen Look im WebFront und habe nicht das Problem dass bei Ausfällen einfach irgendwelche Steuerelemente angezeigt werden, aber nicht mehr reagieren. Ich sehe dort, wo ich normalerweise etwas bedienen würde, dass es nicht funktioniert.

    Diese Methode hat sich sehr bewährt und ich wende sie nach und nach auf sämtliche Bedienlemente an, auch wenn das ein nicht unerheblicher Aufwand ist. Aber es wirkt auf mich alles viel "solider" seitdem ich davon ausgehen kann, dass ein normal aussehendes Bedienelement im WebFront bereits darauf hindeutet, dass das entsprechende Gerät intakt und erreichbar ist.

    Fazit
    Ich hoffe, dieser Beitrag ist auch ohne konkreten Code nützlich für manche von euch, und sei es nur als Anstoß, eure eigenen Erfahrungen und Gedanken zum Thema mitzuteilen. Es gibt noch Aspekte die ich gar nicht beleuchte, etwa dass man bei Fehlermeldungen in komplexen Systemen manchmal bestimmte Zusammenhänge beachten und danach priorisieren sollte, was man meldet (Beispiel: Ein Switch fällt aus - hier möchte ich vor allen Dingen erkennen können, dass der Switch nicht erreichbar ist, statt mit tausenden Meldungen über Folgeprobleme zugemüllt zu werden). Aber der Post ist ja schon recht lang geworden.
    LCN für alles fixe | HM für alles bewegliche | Lötkolben für alles, was es nicht gibt
    "Der RGB-Streifen ist das Arschgeweih der Home Automation."

  2. #2
    Registriert seit
    Apr 2016
    Beiträge
    125

    Hi
    Vielen Dank fuer den sehr detailierten Bericht!
    Aber eine Frage:
    Wie genau pruefst du die Variablen bzw. Aktoren/Sensoren im IPS?
    Ich erwarte jetzt keinen Code oder so aber hast du fuer jede Variable ein Ereignis bei Aenderung dafuer oder
    wie genau machst du das?
    Wuerde mich ueber eine Antwort freuen, da ich z.B. nur die Battiestatusvariablen zyklisch alle 12h per
    script uebepruefe. bei sowas wie Temperatursensoren wuesste ich nicht wie ich das machen soll.

  3. #3
    Registriert seit
    Sep 2008
    Ort
    Hamburg
    Beiträge
    1,226

    Ich schaue mal, dass ich das Skript teile. Ist allerdings komplex
    LCN für alles fixe | HM für alles bewegliche | Lötkolben für alles, was es nicht gibt
    "Der RGB-Streifen ist das Arschgeweih der Home Automation."

  4. #4
    Registriert seit
    Sep 2008
    Ort
    Hamburg
    Beiträge
    1,226

    Hier ein Skript, welches ich verwende. Das Skript könnt ihr prinzipiell übernehmen, wenn ihr die Konfiguration oben durch eure eigene ersetzt. Bitte habt Verständnis, dass ich für dieses Skript gerade keinen echten Support leisten kann. Ihr dürft natürlich trotzdem Fragen stellen.

    PHP-Code:
    <?

    /*
        Definitions array: "entry_name" => array( ... definition ... )
        
        Definitons can be either:
        * Single source / value verification or
        * Redundancy - multiple source values to provide redundancy for a target
            variable
        
        For single value definitions, simply specify the "source parameters" directly
        inside the definition array.
        
        For redundancy definitions, all sources must be defined in a separate
        sub-array named "sources", directly under the definition array:
        "entry_name" => array(
            "sources" => array(
                "my_source" => array( ... source parameters ... ),
                "my_other_source" => array( ... source parameters ... ), // and so on
            )
        ),
        
        Source parameter fields:
        * "id_value" => required, id of the variable holding the value for this source
        * "max_age" => required, the maximum age of the value from this source before
            it's considered unreliable and not used to calculate the target.
        * "id_status" => optional, id of a status variable to check before regarding
            the id_value variable. If the status variable's value is != what's provided
            in the field "status_ok", this source is regarded as having an error state
            and not used for the target. Note: You can also sepcify a simple array of
            multiple ids here, in which case the same number of check values must be
            provided in the field "status_ok" as a simple array as well.
        * "is_local" => optional, true if this source is local, false by default.
            Used to determine whether the resulting target value uses (factors in) local
            source(s).
        * "multiplier" => optional, if you use sources with different units (such as,
            for example, Pa and hPa for atmospheric pressure), you can specify a multi-
            plier in order to adapt to the target variables' unit
        * "valid_min" => optional, the lowest allowed value for this source. If the
            value of the variable specified by "id_value" is lower, the source is regar-
            ded as erroneous and not used for calculating the target.
        * "valid_max" => optional, the highest allowed value for this source. If the
            value of the variable specified by "id_value" is higher, the source is re-
            garded as erroneous and not used for calculating the target.
        * "use_error_profile" => optional, true if a special variable profile shall
            be used in order to flag the "id_value" variable as erroneous.
        * "smoothing" => optional, if true the average over the last 1h is used to
            calculate the target (rather than the current value). Logging must be ena-
            bled for the id_value variable.
        
        Supported redundancy types:
        * failover - take reading from the topmost valid source
        * avergage - calculate average of readings from valid sources
        * median   - determine median of readings from valid sources
        * none     - use no redundancy (only one source can be provided)
    */

    $definitions = array(
        
    "current_outside_brightness" => array(
            
    "id_value" => 28899,
            
    "id_status" => 37436,
            
    "status_ok" => false,
            
    "max_age" => 900,
            
    "use_error_profile" => true
        
    ),
        
    "soil_humidity" => array(
            
    "redundancy_type" => "average",
            
    "sources" => array(
                
    "irrigated" => array(
                    
    "is_local" => true,
                    
    "id_value" => 31662,
                    
    "id_status" => 34841,
                    
    "status_ok" => true,
                    
    "max_age" => 900,
                    
    "smoothing" => true,
                    
    "use_error_profile" => true
                
    ),
                
    //"unirrigated" => array(
                //    "is_local" => true,
                //    "id_value" => 20057,
                //    "id_status" => 37626,
                //    "status_ok" => true,
                //    "max_age" => 900,
                //    "smoothing" => true,
                //    "use_error_profile" => true
                //),
                
    "patio" => array(
                    
    "is_local" => true,
                    
    "id_value" => 27657,
                    
    "id_status" => 23074,
                    
    "status_ok" => true,
                    
    "max_age" => 900,
                    
    "smoothing" => true,
                    
    "use_error_profile" => true
                
    ),
                
    //"shed" => array(
                //    "is_local" => true,
                //    "id_value" => 45640,
                //    "id_status" => 23371,
                //    "status_ok" => true,
                //    "max_age" => 900,
                //    "smoothing" => true,
                //    "use_error_profile" => true
                //)
            
    ),
            
    "id_target" => 20261
        
    ),
        
    "current_outside_pressure" => array(
            
    "max_deviation" => 10// maximum deviation of a sources' reading from the average of the other sources' readings (0=disabled)
            
    "redundancy_type" => "failover",
            
    "sources" => array(
                
    "shed_sensor" => array(
                    
    "is_local" => true,
                    
    "id_value" => 36425,
                    
    "multiplier" => 0.01,
                    
    "valid_min" => 850,
                    
    "valid_max" => 1100,
                    
    "id_status" => 14929,
                    
    "status_ok" => true,
                    
    "max_age" => 300,
                    
    "use_error_profile" => true
                
    ),
                
    "haw" => array(
                    
    "is_local" => false,
                    
    "id_value" => 42155,
                    
    "valid_min" => 850,
                    
    "valid_max" => 1100,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
                
    "owm" => array(
                    
    "is_local" => false,
                    
    "id_value" => 45369,
                    
    "valid_min" => 850,
                    
    "valid_max" => 1100,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
            ),
            
    "id_target" => 53134,
        ),
        
    "outside_temp_min" => array(
            
    "max_deviation" => 0// maximum deviation of a sources' reading from the average of the other sources' readings (0=disabled)
            
    "redundancy_type" => "average",
            
    "decimal_places" => 1,
            
    "sources"  => array(
                
    "owm" => array(
                    
    "is_local" => false,
                    
    "id_value" => 31618,
                    
    "valid_min" => -25,
                    
    "valid_max" => 45,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
            ),
            
    "id_target" => 16344,
        ),
        
    "outside_temp_max" => array(
            
    "max_deviation" => 0// maximum deviation of a sources' reading from the average of the other sources' readings (0=disabled)
            
    "redundancy_type" => "average",
            
    "decimal_places" => 1,
            
    "sources"  => array(
                
    "owm" => array(
                    
    "is_local" => false,
                    
    "id_value" => 52790,
                    
    "valid_min" => -25,
                    
    "valid_max" => 45,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
            ),
            
    "id_target" => 46981,
        ),
        
    "current_outside_temp" => array(
            
    "max_deviation" => 2.5// maximum deviation of a sources' reading from the average of the other sources' readings (0=disabled)
            
    "redundancy_type" => "failover",
            
    "decimal_places" => 1,
            
    "sources" => array(
                
    "shed_station" => array(
                    
    "is_local" => true,
                    
    "id_value" => 59767,
                    
    "valid_min" => -25,
                    
    "valid_max" => 45,
                    
    "id_status" => 29762,
                    
    "status_ok" => true,
                    
    "max_age" => 300,
                    
    "use_error_profile" => true
                
    ),
                
    "shed_sensor" => array(
                    
    "is_local" => true,
                    
    "id_value" => 46875,
                    
    "valid_min" => -25,
                    
    "valid_max" => 45,
                    
    "id_status" => 48445,
                    
    "status_ok" => true,
                    
    "max_age" => 300,
                    
    "use_error_profile" => true
                
    ),
                
    "haw" => array(
                    
    "is_local" => false,
                    
    "id_value" => 48966,
                    
    "valid_min" => -25,
                    
    "valid_max" => 45,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
                
    "owm" => array(
                    
    "is_local" => false,
                    
    "id_value" => 45375,
                    
    "valid_min" => -25,
                    
    "valid_max" => 45,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
            ),
            
    "id_target" => 17551,
            
    "id_is_local" => 12055,
            
    "id_valid" => 14401,
        ),
        
    "current_outside_hum" => array(
            
    "max_deviation" => 15,
            
    "redundancy_type" => "average",
            
    "sources" => array(
                
    "shed_station" => array(
                    
    "is_local" => true,
                    
    "id_value" => 42515,
                    
    "valid_min" => 0,
                    
    "valid_max" => 98,
                    
    "id_status" => 24130,
                    
    "status_ok" => true,
                    
    "max_age" => 300,
                    
    "use_error_profile" => true
                
    ),
                
    "haw" => array(
                    
    "is_local" => false,
                    
    "id_value" => 26845,
                    
    "valid_min" => 0,
                    
    "valid_max" => 100,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
                
    "owm" => array(
                    
    "is_local" => false,
                    
    "id_value" => 38580,
                    
    "valid_min" => 0,
                    
    "valid_max" => 100,
                    
    "max_age" => 1500,
                    
    "use_error_profile" => true
                
    ),
            ),
            
    "id_target" => 15451
        
    )
    );

    $mailer_id 28440;
    $err_profile_text "Fehler";
    $report "";

    process_entries();

    $saved_report_id = @IPS_GetObjectIDByIdent('report'$_IPS['SELF']);
    if(
    $saved_report_id === false) {
        
    $saved_report_id IPS_CreateVariable(3);
        
    IPS_SetIdent($saved_report_id'report');
        
    IPS_SetParent($saved_report_id$_IPS['SELF']);
        
    IPS_SetName($saved_report_id'Report');
    }
    $saved_report GetValue($saved_report_id);

    if(
    $saved_report != $report) {
        
    SetValue($saved_report_id$report);
        if(
    $_IPS['SENDER'] != 'Execute') {
            
    //send_report();
        
    }
    }

    function 
    send_report() {
        global 
    $report$mailer_id;
        if(
    $report == "") return;
        if(
    $mailer_id == 0) return;
        
    SMTP_SendMail(
            
    $mailer_id,
            
    IPS_GetName($_IPS['SELF']),
            
    $report
        
    );
    }

    function 
    process_entries() {
        global 
    $definitions;
        
    // loop over all the defined entries
        
    report_info("About to process " count($definitions) . " entries.");
        foreach(
    $definitions as $entry_name => $entry) {
            if(!
    array_key_exists("sources"$entry)) {
                if(
    array_key_exists("id_value"$entry)) { // assume single unnamed source
                    //report_info("Entry \"" . $entry_name . "\" is single-source.");
                    
    $entry["sources"] = array(
                        
    "unnamed" => $entry
                    
    );
                } else {
                    
    report_error("No sources defined for value \"" $entry_name "\" (entry \"sources\" missing)!");
                    
    $definitions[$entry_name]["valid"] = false;
                    continue;
                }
            }
            
    $sources $entry["sources"];
            if(
    $_IPS['SENDER'] == 'Variable') { // if called by update script, process only update
                
    $this_entry_update false;
                foreach(
    $sources as $source) {
                    if(
    array_key_exists("id_status"$source)) {
                        if(
    is_array($source["id_status"])) {
                            foreach(
    $source["id_status"] as $id) {
                                if(
    $id == $_IPS['VARIABLE']) {
                                    
    $this_entry_update true;
                                    break 
    2;
                                }
                            }
                        } else if(
    $source['id_status'] == $_IPS['VARIABLE']) {
                            
    $this_entry_update true;
                            break;
                        }
                    }
                    if(
    array_key_exists("id_value"$source) && $source['id_value'] == $_IPS['VARIABLE']) {
                        
    $this_entry_update true;
                        break;
                    }
                }
                if(!
    $this_entry_update) continue;
            } 
    // if
            
            
    if(count($sources) == 0) {
                
    report_error("No sources defined for value \"" $entry_name "\"!");
                
    $definitions[$entry_name]["valid"] = false;
                continue;
            } else if(
    count($sources) == && array_key_exists("redundancy_type"$entry)
                && 
    $entry["redundancy_type"] != "none") {
                
    report_warning("Only single source defined for value \"" $entry_name .
                    
    "\" - redundancy type \"" $entry["redundancy_type"] .
                    
    "\" can not be provided!");
            } else if(
    count($sources) > && array_key_exists("redundancy_type"$entry)
                && 
    $entry["redundancy_type"] == "none") {
                
    report_warning("Multiple sources defined for value \"" $entry_name .
                
    "\" - which is configured to have no redundancy. Defaulting to redundancy " .
                
    "type \"failover\".");
            } else {
                
    report_info("Entry \"" $entry_name "\" has " count($sources) . " defined source(s).");
            }
            
            
    $valid_sources = array();
            foreach(
    $sources as $source_name => $source) {
                if(
    array_key_exists("enabled"$source)) {
                    
    report_info("Source \"" $source_name "\" for entry \"" .
                        
    $entry_name "\" is disabled.");
                    if(!
    $source["enabled"]) continue;
                }
                
                if(
    array_key_exists("id_status"$source)) {
                    if(
    array_key_exists("status_ok"$source)) {
                        if(
    is_array($source["id_status"]) && is_array($source["status_ok"]) &&
                            
    count($source["id_status"]) == count($source["status_ok"])) {
                            for(
    $i 0$i count($source["id_status"]); $i++) {
                                if(!
    verify_status($source["id_status"][$i], $source["status_ok"][$i], $source_name$entry_name)) {
                                    
    set_error_profile($source"err_status");
                                    continue 
    2;
                                }
                            }
                        } else if(!
    is_array($source["id_status"]) && !is_array($source["status_ok"])) {
                            if(!
    verify_status($source["id_status"], $source["status_ok"], $source_name$entry_name)) {
                                
    set_error_profile($source"err_status");
                                continue;
                            }
                        }
                        
    report_info("Status check(s) on source \"" $source_name "\" for entry \"" .
                            
    $entry_name "\" successful.");
                    } else if(
    $source["id_status"]) {
                        
    report_warning("Source \"" $source_name "\" for entry \"" $entry_name "\" has field \"id_status\" without corresponding \"status_ok\".");
                    }
                } 
    // if
                
                
    if(!array_key_exists("id_value"$source)) {
                    
    report_warning("Definition \"id_value\" for source \"" $source_name "\" for entry \"" $entry_name "\" missing.");
                    continue;
                } else if(!
    IPS_VariableExists($source["id_value"])) {
                    
    remove_event_for($source["id_value"]);
                    
    report_warning("Value variable of source \"" $source_name "\" for entry \"" $entry_name "\" not found.");
                    continue;
                }
                
    ensure_event_exists_for($source["id_value"], 0);
                
                if(
    array_key_exists("smoothing"$source) && $source["smoothing"]) {
                    
    $ac_id IPS_GetInstanceListByModuleID("{43192F0B-135B-4CE7-A0A7-1475603F3060}")[0];
                    
    $aggr AC_GetAggregatedValues(
                        
    $ac_id$source["id_value"], 0time() - 60 60time(), 0);
                    if(
    count($aggr) >= 1) {
                        
    $aggr $aggr[0];
                        if(
    array_key_exists("Avg"$aggr)) {
                            
    $value $aggr["Avg"];
                            
    report_info("Values of source \"" $source_name .
                                
    "\" for entry \"" $entry_name "\" smoothed using logged history.");
                        } else {
                            
    report_warning("Values of source \"" $source_name .
                                
    "\" for entry \"" $entry_name "\" could not be smoothed - no history found.");
                            
    $value GetValue($source["id_value"]);
                        }
                    } else {
                        
    report_warning("Values of source \"" $source_name .
                            
    "\" for entry \"" $entry_name "\" could not be smoothed - no history found.");
                        
    $value GetValue($source["id_value"]);
                    }
                } else {
                    
    $value GetValue($source["id_value"]);
                }
                if(
    array_key_exists("multiplier"$source)) {
                    
    $value *= $source["multiplier"];
                }
                
    $updated_ts IPS_GetVariable($source["id_value"])['VariableUpdated'];
                
    $age time() - $updated_ts;
                
                if(
    array_key_exists("max_age"$source)) {
                    if(
    $age $source["max_age"]) {
                        
    set_error_profile($source"too_old");
                        
    report_warning("No current reading from source \"" $source_name "\" for entry \"" $entry_name "\". (Last reading is " $age " > " $source["max_age"] . " seconds old).");
                        continue;
                    }
                }
                
                if(
    array_key_exists("valid_min"$source)) {
                    if(
    $value $source["valid_min"]) {
                        
    set_error_profile($source"too_low");
                        
    report_warning("Reading " $value " from source \"" $source_name "\" for entry \"" $entry_name "\" is too low (" $value " < " $source["valid_min"] . ").");
                        continue;
                    }
                }
                if(
    array_key_exists("valid_max"$source)) {
                    if(
    $value $source["valid_max"]) {
                        
    set_error_profile($source"too_high");
                        
    report_warning("Reading " $value " from source \"" $source_name "\" for entry \"" $entry_name "\" is too high (" $value " > " $source["valid_max"] . ").");
                        continue;
                    }
                }
                
                
    report_info("Value retrieved from source \"" $source_name .
                    
    "\" for entry \"" $entry_name "\": " $value);
                
    set_error_profile($source"");
                
    $source['value'] = $value;
                
                
    $valid_sources[$source_name] = $source;
            } 
    // foreach $sources
            
            
    if(!array_key_exists("id_target"$entry)) {
                if(
    array_key_exists("redundancy_type"$entry) && $entry["redundancy_type"] != "none") {
                    
    report_error("Definition \"id_target\" missing for entry \"" $entry_name "\".");
                }
                continue;
            }
            
            if(
    count($valid_sources) == 0) {
                
    report_error("Entry \"" $entry_name "\" has no usable sources!");
                
    $definitions[$entry_name]["valid"] = false;
                continue;
            } else {
                
    report_info("Entry \"" $entry_name "\" has " count($valid_sources) .
                    
    " source(s) providing usable values.");
            }
            
            if(
    array_key_exists("max_deviation"$entry)) {
                
    $max_deviation $entry["max_deviation"];
            } else {
                
    $max_deviation false;
            }
            if(
    $max_deviation) {
                if(
    count($valid_sources) < 3) {
                    
    report_warning("Less than three sources providing readings for entry \"" $entry_name "\" - deviation check skipped!");
                } else {
                    
    // remove sources whose readings deviate too much from the (average of the) others.
                    
    $count_reliable count($valid_sources);
                    
    report_info("About to perform deviation check on " $count_reliable .
                        
    " value(s) for entry \""$entry_name "\".");
                    do {
                        
    $remove_source false;
                        
    $highest_deviation_found 0;
                        
    $count_deviating_too_much 0;
                        foreach(
    $valid_sources as $source_name => $source) {
                            
    $other_avg 0;
                            
    $other_count 0;
                            foreach(
    $valid_sources as $other_source_name => $other_source) {
                                if(
    $source_name != $other_source_name) {
                                    
    $other_avg += $other_source["value"];
                                    
    $other_count++;
                                }
                            }
                            
    $other_avg /= $other_count;
                        
                            
    $deviation abs($source["value"] - $other_avg);
                            if(
    $deviation $max_deviation) {
                                if(
    $deviation $highest_deviation_found) {
                                    
    $remove_deviation $deviation;
                                    
    $remove_value $source["value"];
                                    
    $remove_other_avg $other_avg;
                                    
    $remove_source $source_name;
                                    
    $highest_deviation_found $deviation;
                                }
                                
    $count_deviating_too_much++;
                            }
                        } 
    // foreach $valid_sources
                        
                        
    if($remove_source !== false) {
                            
    $count_reliable count($valid_sources) - $count_deviating_too_much;
                            unset(
    $valid_sources[$remove_source]);
                            
    report_warning("Value " $remove_value " retrieved from source \"" .
                                
    $remove_source "\" for entry \"" $entry_name .
                                
    "\" deviates too much from the average (" $remove_other_avg .
                                
    ") of the other readings (deviation " $remove_deviation .
                                
    " > " $max_deviation ") and will be discarded.");
                        }
                    } while(
    $remove_source !== false && count($valid_sources) > 2);
                    
    // if we don't have at least two "reliable" readings left, they are
                    // either all over the place, or the threshold has been set too low.
                    
    if($count_reliable 2) {
                        
    report_warning("Deviation check for entry \"" $entry_name "\" " .
                            
    "flagged values from all sources, leaving no reliable result. " .
                            
    "Ensure sources are okay and try increasing the maximum allowed " .
                            
    "deviation.");
                    } else {
                        
    report_info("Deviation check for entry \""$entry_name "\" " .
                            
    "leaves " $count_reliable " values to be used for end result.");
                    }
                }
            } 
    // if
            
            
    $sum 0;
            
    $sortable = array();
            
    $count 0;
            
    $value NULL;
            
    $is_local false;
            if(!
    array_key_exists("redundancy_type"$entry)) {
                
    $entry['redundancy_type'] = "failover";
            }
            foreach(
    $valid_sources as $source_name => $source) {
                switch(
    $entry["redundancy_type"]) {
                    case 
    "none":
                    case 
    "failover":
                        
    report_info("Redundancy setting \"failover\" for entry \"" .
                            
    $entry_name "\": Topmost value source (\"" $source_name .
                            
    "\") is used.");
                        if(
    array_key_exists("is_local"$source)) {
                            
    $is_local $source["is_local"];
                        }
                        
    $value $source["value"];
                        break 
    2;
                    case 
    "average":
                        if(
    array_key_exists("is_local"$source)) {
                            if(
    $source["is_local"]) $is_local true;
                        }
                        
    $sum += $source["value"];
                        
    $count++;
                        break;
                    case 
    "median":
                        if(
    array_key_exists("is_local"$source)) {
                            if(
    $source["is_local"]) $is_local true;
                        }
                        
    $sortable[] = $source["value"];
                        break;
                    default:
                        
    $definitions[$entry_name]["valid"] = false;
                        
    report_error("Redundancy type \"" $entry["redundancy_type"] .
                            
    "\" for entry \"" $entry_name "\" is not supported.");
                        continue 
    2;
                } 
    // switch
            
    // foreach $valid_sources
            
            
    if($count 0) { // calculate average
                
    report_info("Redundancy setting \"average\" applied for entry \"" .
                    
    $entry_name "\".");
                
    $value $sum $count;
            } else if(
    count($sortable) > 0) { // get median
                
    report_info("Redundancy setting \"median\" applied for entry \"" .
                    
    $entry_name "\".");
                
    $count count($sortable);
                
    sort($sortable);
                
    $mid_index floor($count 2);
                if(
    $count 2) { // odd
                    
    $value $sortable[$mid_index];
                } else if(
    $count 0) { // even
                    
    $value = ($sortable[$mid_index] + $sortable[$mid_index 1]) / 2;
                }
            }
            
            if(
    array_key_exists("decimal_places"$entry)) {
                
    $value round($value$entry["decimal_places"]);
            }
            
            if(
    is_null($value)) {
                
    report_error("No result could be calculated for entry \"" $entry_name "\".");
                
    $definitions[$entry_name]["valid"] = false;
                continue;
            } else {
                
    report_info("Result for entry \"" $entry_name "\" is " $value ".");
            }
            
            
    $target_var_id $entry["id_target"];
            if(!
    IPS_VariableExists($target_var_id)) {
                
    report_error("Target variable for value \"" $entry_name "\" not found.");
                continue;
            }
            
            if(
    SetValue($target_var_id$value)) {
                
    $definitions[$entry_name]["valid"] = true;
                
    $definitions[$entry_name]["is_local"] = $is_local;
                
    $definitions[$entry_name]["count_sources"] = count($valid_sources);
            } else {
                
    report_error("Target variable could not be set for value \"" $entry_name "\".");
                
    $definitions[$entry_name]["valid"] = false;
                continue;
            }
        } 
    // foreach $definitions
        
        
    foreach($definitions as $entry_name => $entry) {
            if(
    array_key_exists("valid"$entry)) {
                if(
    array_key_exists("id_valid"$entry)) {
                    if(
    IPS_VariableExists($entry["id_valid"])) {
                        
    SetValue($entry["id_valid"], $entry["valid"]);
                    } else {
                        
    report_warning("Validity status variable for value \"" $entry_name .
                            
    "\" not found.");
                    }
                }
            }
            if(
    array_key_exists("is_local"$entry)) {
                if(
    array_key_exists("id_is_local"$entry)) {
                    if(
    IPS_VariableExists($entry["id_is_local"])) {
                        
    SetValue($entry["id_is_local"], $entry["is_local"]);
                    } else {
                        
    report_warning("Local data availability status variable for value \"" $entry_name .
                            
    "\" not found.");
                    }
                }
            }
            if(
    array_key_exists("count_sources"$entry)) {
                if(
    array_key_exists("id_count_sources"$entry)) {
                    if(
    IPS_VariableExists($entry["id_count_sources"])) {
                        
    SetValue($entry["id_count_sources"], $entry["count_sources"]);
                    } else {
                        
    report_warning("Valid source count variable for value \"" $entry_name .
                            
    "\" not found.");
                    }
                }
            }
        } 
    // foreach $definitions
    // process_entriess

    function ensure_event_exists_for($var_id$trigger_type) {
        
    $ident "var_event_" $var_id;
        
    $event_id = @IPS_GetObjectIDByIdent($ident$_IPS['SELF']);
        if(
    $event_id === false) {
            
    $event_id IPS_CreateEvent(0);
            
    IPS_SetParent($event_id$_IPS['SELF']);
            
    IPS_SetIdent($event_id$ident);
            
    IPS_SetEventTrigger($event_id$trigger_type$var_id);
            
    IPS_SetEventActive($event_idtrue);
        }
    // ensure_event_exists_for

    function remove_event_for($var_id) {
        
    $ident "var_event_" $var_id;
        
    $event_id = @IPS_GetObjectIDByIdent($ident$_IPS['SELF']);
        if(
    $event_id !== false) {
            
    IPS_DeleteEvent($event_id);
        }
    // remove_event_for

    // verify a sources' status variable
    function verify_status($id$status_ok$source_name$entry_name) {
        if(
    $id) {
            if(!
    IPS_VariableExists($id)) {
                
    remove_event_for($id);
                
    report_warning("Status variable with id " $id " of source \"" .
                    
    $source_name "\" for value \"" $entry_name "\" not found.");
                return 
    true;
            }
            
    ensure_event_exists_for($id1);
            
    $status GetValue($id);
            if(
    $status != $status_ok) {
                
    report_warning("Source \"" $source_name "\" for value \"" .
                    
    $entry_name "\" has an error status (".
                    (
    $status_ok === true 'not ' : ($status_ok === false '' $status_ok "!=")) .
                    
    "\"" IPS_GetName($id) . "\"" .
                    
    ") and will not be used.");
                return 
    false;
            }
        }
        return 
    true;
    // verify_status

    function set_error_profile($source$suffix) {
        if(!
    array_key_exists("use_error_profile"$source)) return;
        if(!
    array_key_exists("id_value"$source)) return;
        
    $prefix "err_prof_";
        
    $id $source["id_value"];
        
    $var IPS_GetVariable($id);
        
    $profile_name $var["VariableCustomProfile"];
        if(
    substr($profile_name0strlen($prefix)) == $prefix) {
            
    $original_profile_name IPS_GetObject($id)["ObjectInfo"];
        } else {
            
    IPS_SetInfo($id$profile_name);
            
    $original_profile_name $profile_name;
        }
        if(
    $suffix == "") {
            
    $profile_name $original_profile_name;
        } else {
            
    $var_type $var["VariableType"];
            
    ensure_error_profile_exists($var_type$suffix);
            
    $profile_name $prefix $var_type "_" $suffix;
        }
        
    IPS_SetVariableCustomProfile($id$profile_name);
    // set_error_profile

    // create the specified error profile if necessary
    function ensure_error_profile_exists($var_type$suffix) {
        global 
    $err_profile_text;
        
    $prefix "err_prof_";
        switch(
    $suffix) {
            case 
    "too_high"$icon "HollowDoubleArrowUp"; break;
            case 
    "too_low"$icon "HollowDoubleArrowDown"; break;
            case 
    "too_old"$icon "Hourglass"; break;
            case 
    "err_status"$icon "Warning"; break;
            default: 
    $icon "Cross";
        }
        
    $profile_name $prefix $var_type "_" $suffix;
        if(!
    IPS_VariableProfileExists($profile_name)) {
            
    IPS_CreateVariableProfile($profile_name$var_type);
        }
        
    IPS_SetVariableProfileAssociation($profile_name, -1000$err_profile_text,
            
    $icon0xFF0000);
    // ensure_error_profile_exists

    function report_error($msg) {
        global 
    $report;
        if(
    $_IPS['SENDER'] == 'Execute') {
            echo 
    "[ERR!] " $msg "\n";
        } else {
            
    IPS_LogMessage(IPS_GetName($_IPS['SELF']), $msg);
        }
        
    $report .= "[ERR!] " $msg "\n";
    // report_error

    function report_warning($msg) {
        global 
    $report;
        
    $msg "[WARN] " $msg "\n";
        if(
    $_IPS['SENDER'] == 'Execute') {
            echo 
    $msg;
        }
        
    $report .= $msg;
    // report_warning

    function report_info($msg) {
        global 
    $report;
        
    $msg "[INFO] " $msg "\n";
        if(
    $_IPS['SENDER'] == 'Execute') {
            echo 
    $msg;
        }
        
    $report .= $msg;
    // report_info

    ?>
    LCN für alles fixe | HM für alles bewegliche | Lötkolben für alles, was es nicht gibt
    "Der RGB-Streifen ist das Arschgeweih der Home Automation."

  5. #5
    Registriert seit
    Nov 2009
    Ort
    Essen
    Beiträge
    2,593

    Zitat Zitat von sokkederheld Beitrag anzeigen
    Neben der oben beschriebenen Meldung per "Wartungs-Übersichts-Seite"/Email bin ich dazu übergegangen, bei Problemen, die ein bestimmtes Gerät betreffen, dies auch in der Bedienoberfläche des Gerätes anzuzeigen. [...] Bei Sensoren wiederum will ich eben auch eine Warnung anzeigen, wenn etwas nicht stimmt und zwar an der gleichen Stelle, wo ich sonst den Messwert sehe.
    Sehr sehr gute Idee. Danke!

    Zitat Zitat von n1ck1355 Beitrag anzeigen
    Hi
    Wie genau pruefst du die Variablen bzw. Aktoren/Sensoren im IPS?
    Zitat Zitat von sokkederheld Beitrag anzeigen
    Ich schaue mal, dass ich das Skript teile. Ist allerdings komplex
    Das Skript ist wirklich komplex. Das ist nichts, was man mal eben durch einfaches draufgucken innerhalb von 5 Minuten versteht.
    Mein Tipp: Ein Skript zyklisch laufen lassen und dabei schauen, wann die Werte aktualisiert wurden. Wenn der Sensor beispielsweise alle 2 Minuten die Werte sendet, könnte man - je nachdem wir kritisch die Werte sind - alle 2:30 Minuten ein Skript laufen lassen, welches prüft, ob der Wert nicht älter als 2 Minuten ist. Die Werte muss man natürlich auf die Gegebenheiten anpassen.

    Alternativ kann man auch ein Skript immer auf Aktualisierung triggern und dieses Skript über einen SkriptTimer Alarm schlagen lassen, wenn das Ereignis nicht ausgelöst hat.

    Viele Wege führen nach Rom.

    Auf jeden Fall ein sehr guter Beitrag von sokkederheld!
    Deutschlandweite Dienstleistungen rund um und mit IP-Symcon. Systemintegrator im Bereich KNX. ekey Partner. Infos unter https://schrader-it.net

  6. #6
    Registriert seit
    Jun 2012
    Ort
    House of Dragons @ Lübeck
    Beiträge
    10,637

    Und als Ergänzung für User welche nicht so komplexe Scripte einsetzen wollen; es gibt im Modul Store mindestens zwei Module ( Watchdog und Variablenüberwachung) welche auf ausbleibende Änderungen/Aktualisierungen reagieren können.
    Michael
    on Win10VM (ESXi): I7, 32GB RAM, HW-RAID5, 2xSat | HW: pivccu + ca.130 Geräte (ca.550ch), EM1000, CUL, 1Wire, FritzBox Cable, Android Phone + Tablet, Onkyo NR| SW: IPS, Apache2(mod_ssl/PHP), MySQL, hMailServer, PRTG, RoundCube, Win2016 Ess., MediaPortal, Kodi

  7. #7
    Registriert seit
    Jan 2012
    Beiträge
    284

    Hallo sokkederheld,
    will mich hier für deinen ausgiebigen Text und dein Skript bedanken.
    Ist schon öfters mal schade, dass man sich um so vieles selbst kümmern muss.
    Eine Plausibilitätsprüfung der Variablenänderungen sowie eine Überwachung sollte eigentlich schon längst in Symcon integriert sein - meine Meinung nach. So einfach wie man eine Variable archivieren kann (toggle) so einfach sollte auch eine Plausibilitätsprüfung und die zeitliche Überwachung aktivierbar sein.

    Wunschdenken ist doch erlaubt, oder?

    Grüße
    Stefan

  8. #8
    Registriert seit
    Sep 2008
    Ort
    Hamburg
    Beiträge
    1,226

    Zitat Zitat von steppe Beitrag anzeigen
    Eine Plausibilitätsprüfung der Variablenänderungen sowie eine Überwachung sollte eigentlich schon längst in Symcon integriert sein
    Ich bin ja sehr glücklich über all die Features, die Symcon hat - insbesondere die Tatsache, dass ich selbst jederzeit fehlende Features ergänzen kann.

    Ich verstehe allerdings auch, wenn man an diesem Punkt - Symcon ist ja eine recht stabile und ernstzunehmende Angelegenheit geworden - dann schnell auch solche Features vermisst, die vielleicht für reine "Hobbyisten" uninteressant sind, aber für einen Einsatz nach professionellen Maßstäben schon wichtig wären. Die muss man sich derzeit oft selbst stricken.

    Aber wer weiß, ich habe ja bspw. schon mal als es noch hieß, dass MQTT nicht relevant sei (oder so ähnlich) einen MQTT-Server für Symcon geschrieben und einige Monate später kam das als festes Feature (auch durchaus noch besser integriert und natürlich viel performanter als mein Skript).

    Insofern, ja, man darf sich bestimmt was wünschen. Schneller geht es aber oft, wenn man es selbst macht
    LCN für alles fixe | HM für alles bewegliche | Lötkolben für alles, was es nicht gibt
    "Der RGB-Streifen ist das Arschgeweih der Home Automation."

  9. #9
    Registriert seit
    Aug 2009
    Ort
    Lippe
    Beiträge
    2,560

    Um das ganze wasserdicht zu machen, müsste jeder Aktor von einem Sensor überwacht werden, und im Fehlerfall sofort Meldung geben.
    Das wird schon mal teuer im LCN.
    Also so nicht machbar, bzw richtig teuer,

    Aber der Lösungsansatz ist richtig, so müsste es laufen.
    lg Thomas
    IPS Raspberry Pi2(3) mit LCN, HM, Sonoff+Shelly per MQTT, SONOS und viel Eigenbau + Pi2(3) mit Heizungssteuerung über GPIO per IPS

  10. #10
    Registriert seit
    May 2011
    Beiträge
    340

    Moin sokkederheld,

    100% ACK. Mir gefällt dein "zentraler" Lösungsansatz zur Überwachung. Da werde ich mal was für mich rausziehen, danke dafür! Bisher wird hier doch eher jede kritische Variable einzeln mit eigenem Checkskript überwacht.

    Einen weiteren praktischen Tipp habe ich noch: gerade bei kleinen Helferskripten für Routineaufgaben schreibt man gerne nur mal schnell sowas wie
    HM_WriteValueBoolean(12345,'STATE',true); oder RequestAction(23456,true);
    Das ist eigentlich schonmal FALSCH! Wird dieses Skript nun z.B. zeitgesteuert irgendwann mal gestartet und der Aktor hat einen Fehler, landet bestenfalls nur eine Meldung im Log. Das liest ja wieder keiner ;-)
    Die meisten Aktorik-Befehle sind Bidirektional, das vergisst man oft! Ich versuche mich also nun häufiger zu zwingen, den Befehl nach diesem Schema aufzubauen: if(RequestAction(23456,true)==false) { Pseudo(Warnung/Mail-verschicken/Alarm) };

Ähnliche Themen

  1. Lichtautomatik - wie ich es mache (kein Code)
    Von sokkederheld im Forum Anleitungen / Nützliche PHP Skripte
    Antworten: 24
    Letzter Beitrag: 03.09.20, 07:35
  2. Jalousie - Wie mache ich es richtig?
    Von Nocturne im Forum IPSStudio & IPSView
    Antworten: 3
    Letzter Beitrag: 12.09.17, 17:44
  3. Dashboard Basis, wie und wo mache ich dort was?
    Von f4steffen im Forum Dashboard
    Antworten: 1
    Letzter Beitrag: 13.03.15, 08:00
  4. Was mache ich Falsch ?
    Von Ironeagle1967 im Forum Eaton Xcomfort
    Antworten: 3
    Letzter Beitrag: 02.10.08, 17:22
  5. Wie mache ich ein IPS-Panel durchsichtig?
    Von Olli im Forum Dashboard
    Antworten: 6
    Letzter Beitrag: 29.10.06, 13:00