ioBroker / ioBroker.sql

Store history data in SQL Database: MySQL, PostgreSQL or SQLite
MIT License
45 stars 25 forks source link

"Alias-DP mit Konvertierungsfunktion nur bei Änderung aufzeichnen" #370

Open Hoedi1030 opened 2 months ago

Hoedi1030 commented 2 months ago

Hallo,

Describe the bug
ich habe folgendes Szenario: Die für mich relevanten Datenpunkt organisiere ich als Aliase (aufgrund der Konvertierungsfunktion, wird gleich noch an einem Beispiel erläutert). Diese Alias-Datenpunkte logge ich dann bei Bedarf mit dem SQL-Adapter. Grundsätzliche möchte ich nur Änderungen aufzeichnen, dementsprechend setze ich diese Option via Checkbox "nur Änderungen aufzeichnen". Nun ist es aber so, dass auch Werte in meine SQL-Datenbank geschrieben werden, die gar keine Änderung abbilden.

Konkretes Beispiel: Ich habe einen dreiphasigen Heizstab, jede der drei Phasen kann über ein Relais separat geschalten werden. Auf dem Relais selbst ist Tasmota installiert, die Kommunikation erfolgt über den MQTT-Adapter. Zudem liefert mir das Relais die bezogene Leistung pro Schaltkontakt. So wird im 10-Sekunden-Takt ein Datenpunkt im MQTT-Adapter aktualisiert, der mir die Messinformationen des Relais liefert.

Nun habe ich für jede der Phasen einen Alias-Datenpunkt "Operating", der mir abbildet, ob über die Phase tatsächlich Strom genutzt wird oder nicht. Dafür verwende ich die praktische Konvertierungsfunktion mit einer Bedingung (Wenn Leistung > 0 ==> true; ansonsten false). image image

Diesen boolean-Datenpunkt lasse ich dann vom SQL-Adapter protokollieren. Soweit funktioniert das auch, nur leider wird jede Aktualisierung (die eben alle 10 Sekunden erfolgt) als Änderung gewertet, selbst, wenn der Wert des Datenpunktes sich nicht geändert hat... image

So werden dann aus den wenigen Schaltzyklen am Tag, die sich mit vielleicht 10 Einträgen in der SQL-Datenpunkt abbilden lassen würden gleich hunderte Aufzeichnungen, die sich im 10-Sekunden-Takt ständig wiederholen. image

To Reproduce

  1. Alias-Datenpunkt erstellen
  2. Verknüpfung des Alias-Datenpunktes mit einem sich regelmäßig aktualisierenden Datenpunkt
  3. Aktivieren der SQL-Protokollierung für den Alias-Datenpunkt
  4. Setzen der Option "nur Änderungen aufzeichnen"
  5. Es wird fälschlicherweise auch aufgezeichnet, wenn keine Änderung des Wertes vom DP erfolgt.

Expected behavior
Es soll nur aufgezeichnet werden, wenn sich der Wert des Datenpunktes tatsächlich geändert hat.

Versions:

Additional context
Eine Vermutung meinerseits ist, dass der Adapter eine Änderung auf Basis des Attributs "zuletzt geändert: ..." eines Datenpunkts beurteilt, ob eine Änderung vorliegt und selbst gar nicht den alten mit dem neuen Wert vergleicht. "zuletzt geändert: ..." wird in meinem Beispiel von oben mit dem Alias-DP auch bei jedem Lesevorgang des Quelldatenpunktes auf den aktuellen Zeitstempel gesetzt, ungeachtet dessen, ob wirklich eine wertmäßige Änderung (z.B. Wechsel von "true" auf "false") erfolgt.

Für die Protokollierung von Zahlenwerten habe ich einen "Workaround" gefunden, indem ich (zusätzlich zu "nur Änderungen aufzeichnen") auch die Abweichungsprüfung aktiviere. So werden zwar Änderungen immer noch nicht richtig erkannt (der SQL-Adapter würde den DP also prinzipiell aufzeichnen, trotz fehlender Wertänderung), aber aufgrund der fehlenden Abweichung (keine Änderung, also Abweichung=0) wird der DP zumindest nicht protokolliert: image

Wie man im Log sieht, ist der neue Wert ("new-value=0") sowie auch der alte ("last-value=0") dem SQL-Adapter bekannt und wird auch richtig im Log ausgegeben, nur findet offenbar kein Vergleich der beiden Werte statt, um zu beurteilen, ob überhaupt eine Änderung erfolgt ist...

Beim Typ Boolean habe ich den "Workaround" auch versucht, indem ich die "minimale Abweichung zum letzten Wert" auf 1 gesetzt habe (nach dem Motto "true=1", "false=0"). Nur leider habe ich den Eindruck, dass das nur beim Typ "number" berücksichtigt wird (im Log: "Min-Delta ignored because no number") image

Ich hoffe ich konnte das Problem ausreichend präzise beschreiben und stelle eventuell fehlenden Informationen gerne bereit und stehe für Fragen zur Verfügung.

Apollon77 commented 2 months ago

Read the Readme :-)))

Da gibts ein Setting was die Werte "Charting optimiert" loggt... Wenn DU das nicht willst schalte es aus

Disable charting optimized logging of skipped values - By default, the adapter tries to record the values for optimized charting. This can mean that additional values (that e.g. not fulfilled all checks above) are logged automatically. If this is not wanted, you can disable this feature.

Hoedi1030 commented 2 months ago

Read the Readme :-)))

Da gibts ein Setting was die Werte "Charting optimiert" loggt... Wenn DU das nicht willst schalte es aus

Disable charting optimized logging of skipped values - By default, the adapter tries to record the values for optimized charting. This can mean that additional values (that e.g. not fulfilled all checks above) are logged automatically. If this is not wanted, you can disable this feature.

Keine Sorge, mit der Einstellung bin ich mittlerweile soweit vertraut. Ist außerdem ohnehin schon deaktiviert (siehe auch zweiter Screenshot).

Apollon77 commented 2 months ago

Ok, sorry hab ich übersehen. also jetzt brauche ich dann mal vloles debug log von so einem Datenpunkt und bitte nicht als Grafik ... text ist sooo viel besser zu lesen :-)

Es gab glaube ich im js-controller einen Bug das alias subscription triggers ggf doppelt gefeuert wurden ... das könnte das vllt erklkären wa sich vermuten kann basierend auf deinen Infos aber ohne Log nicht nachverfolgen kann. Das wäre im neueste js-controller 6 alpha gefixt, aber ist halt noch früh im testing.

Hoedi1030 commented 1 month ago

Kein Problem :)

Nachfolgend das Debug-Log vom SQL-Adapter:

sql.0 debug log (in zip-File, da sehr groß...) [iobroker.2024-05-30.zip](https://github.com/ioBroker/ioBroker.sql/files/15503272/iobroker.2024-05-30.zip)

Ich habe mich an der Interpretation des Logs und auch des Adapter Source-Codes versucht und möchte dazu mal meine Erkentnisse teilen:

  1. Die "Abweichungsprüfung" funktioniert nur beim Datentyp "number". Beim Typ "Boolean" wird die Prüfung nicht durchgeführt und dementsprechend eine Eingabe im Feld "minimale Differenz zum letzten Wert" ignoriert: https://github.com/ioBroker/ioBroker.sql/blob/e3518e52377eb568efbdbcc878e3b9ef9823ba5c/main.js?plain=1#L1225C17-L1241C18

  2. Ob sich der Wert geändert hat, oder nicht wird bei der Option "nur Änderungen aufzeichnen" (unter anderem) daran beurteilt, ob die Attribute "ts" und "lc" des Datenpunktes ungleich sind (wird später nochmal wichtig!): https://github.com/ioBroker/ioBroker.sql/blob/e3518e52377eb568efbdbcc878e3b9ef9823ba5c/main.js#L1201C13-L1210C22

Das ist aus meiner Sicht auch durchaus logisch:


Somit habe ich auch mal versucht, einen Alias-DP alias.0.test1 zu erstellen, der mit einem Bool-DP 0_userdata.0.test2 verknüpft ist. Hier funktioniert die Logik beim manuellen Setzen von 0_userdata.0.test2 auch entsprechend, dass "ts" bei jedem Setzen des Datenpunktes aktualisiert wird, "lc" aber nur bei einer tatsächlichen Änderung des Wertes. Sowohl bei 0_userdata.0.test2 als auch beim verknüpften DP alias.0.test1.


Interessanterweise verhält sich das bei meinem Alias-DP aus der Issue-Eröffnung aber nicht so. Hier wird "ts" und "lc" immer auf denselben Wert gesetzt, auch, wenn keine Änderung des Wertes erfolgt. Daher resultiert wohl auch das beobachtete Berhalten des SQL-Adapters...

Meine Annahme ist, dass hier ein Fehler bei den Konvertierungsfunktionen vorliegen könnte, wie ich an meinem konkreten Beispiel aus der Issue-Eröffnung nachfolgend darlegen möchte:

  1. Rohdaten werden vom MQTT-Adapter empfangen und alle 10 Sekunden in den DP mqtt.0.home/vorraum-garage/sonoff-spm/tele/SPM/SENSOR im JSON-Format geschrieben.
    beispielhafte Rohdaten
{
  "Time": "2024-05-30T17:02:19",
  "SPM": {
    "Energy": [
      25.2,
      22.6,
      18.3,
      0
    ],
    "Yesterday": [
      1.4,
      1.4,
      0,
      0
    ],
    "Today": [
      3.5,
      2.7,
      1.3,
      0
    ],
    "ActivePower": [
      0,
      0,
      0,
      0
    ],
    "ApparentPower": [
      0,
      0,
      0,
      0
    ],
    "ReactivePower": [
      0,
      0,
      0,
      0
    ],
    "Factor": [
      0,
      0,
      0,
      0
    ],
    "Voltage": [
      0,
      0,
      0,
      0
    ],
    "Current": [
      0.02,
      0,
      0,
      0
    ]
  }
}

Hier decken sich auch bei jeder 10-sekündlichen Übermittlung die Attribute "ts" und "lc", da unter anderem ein Zeitstempel in den Rohdaten inkludiert ist, der naturgemäß nicht gleich bleibt und somit immer eine Änderung vorliegt!

  1. Auf die Änderung von mqtt.0.home/vorraum-garage/sonoff-spm/tele/SPM/SENSOR reagiert der Alias-DP alias.0.KG.Heizraum.Boiler_EHK.Heizwendel1.Operating und liest gemäß Konvertierungsfunktion
    JSON.parse(val).SPM.ActivePower[0] > 0

    den gewünschten Wert aus den Rohdaten. Hier erfolgt wie schon eingangs beschrieben ein einfacher Vergleich mit der vom Heizstab bezogenen Leistung, um den Betriebszustand als Boolean abzubilden zu können.

Auch das funktioniert prinzipiell problemlos, nur leider scheint es so, dass der Alias-DP den "lc"-Wert vom Rohdaten-DP mqtt.0.home/vorraum-garage/sonoff-spm/tele/SPM/SENSOR einfach übernimmt und nicht selbst den "lc"-Status auf Basis des vorherigen Wertes von alias.0.KG.Heizraum.Boiler_EHK.Heizwendel1.Operating evaluiert.

Somit wird - wie es für mich scheint - weder von der Alias-Funktion im ioBroker noch vom SQL-Adapter ein Vergleich des vorher/nachher-Wertes durchgeführt, wodurch sich (hoffentlich ausreichend ausführlich) beschriebenes Problem ergibt...