Beim TWS-Usertreffen (10/2025) haben wir mit der KI etwas gespielt und versucht aus zwei Logikbausteinen einen zu machen und inhaltlich auch noch zu erweitern. Das hat an der Stelle noch nicht so richtig funktionieren wollen.
Also habe ich mich da jetzt mal hingesetzt und das "per Hand" gebaut. (Copilot im VS-Code macht es aber schon deutlich einfacher und so manche Zeile Code hat das Ding einfach nach ENTER direkt korrekt abgeleitet)
Also was ist da jetzt entstanden?
Es gibt jetzt einen Baustein der einen Zählerwert entgegennimmt, auf einfache Konsistenz prüft und ggf korrigiert.
Dazu lässt sich optional noch ein Korrekturwert manuell ergänzen.
Soweit nichts neues zu diesem Baustein hier: viewtopic.php?t=4166
Als neues Feature lässt sich nun noch ein Skalierungsfaktor erfassen, um ggf eingehende Zählerstände in Wh auf die üblichen kWh zu skalieren.
Der Baustein gibt dann den validierten Zählerstand in beiden Skalierungen aus.
Der skalierte validierte Zählerstand ist dann die Ausgangsbasis für die Berechnung von Zählerstandsverlaufswerten. Da habe ich auch mal schon vor längerer Zeit bei einem Baustein hier aus dem Forum mir was abgeschaut.
Die periodischen Deltas werden hierbei nun aber alle 15 Minuten berechnet und zwar genau 3-Sekunden vor jeder Viertelstunde und auch zu diesen Zeiten vollständig ausgegeben.
Der Versatz von 3 Sekunden soll eine sauberere Abbildung in den Timeseries und Grafana abbilden. Es schaut da nicht gut aus wenn der Zählerstand Jahresende am 1.1. des Volgejahres geschrieben wird.
In der Auflösung von 15 Minuten bleibt die Gesamtmenge an redundanter Datenpunkte in der Datenbank aber auch überschaubar.
Die Deltas werden insgesamt für die folgenden Perioden ermittelt. 15-min, 1h, 1Tag, 1Woche, 1Monat, 1Quartal, 1Jahr.
Die Ausgabe sind jeweils das Delta zum letzten Periodenwechsel, jener Wert der Vorperiode und der Zählerstand zum jeweiligen Vorperioden Ende.
Ich stelle das jetzt hier erstmal zum Test zur Verfügung. Im Anschluss werde ich das auch noch genauer Beschreiben.
Bis dahin geht damit Spielen und meldet bitte Auffälligkeiten.
Code: Alles auswählen
/**===========================================================
Nimmt einen Zählerwert entgegen
und plausibilisiert ihn (versucht bei Zählerreset weiterzuzählen)
und reichert Ihn um einen Initialisierungswert / Korrekturwert an
und gibt ihn in zwei Werten aus, die um einen Umrechnungsfaktor auseinander liegen (z.B. 0.001 Wh >> KWh)
zum skalierten Zählerwert werden zusätzlich periodische (Deltas) für 15Min, Stunde, Tag, Woche, Monat, Quartal, Jahr ausgegeben
sowie dazugehörigene Vorperiodenwerte
Die beiden Zählerstände werden bei Änderung und den periodischen Enden ausgegeben
Die periodischen Deltas werden immer zum 15-Minuten Periodenende ausgegeben
Das 15 Minuten Periodenende liegt 3 Sekunden vor dem Ende. Das soll die Berechnung und Speicherung in der Timeseries nah am Ende sicherstellen und damit für geringe Verzerrungen in Grafanaauswertungen sorgen.
============================================================*/
// Version 0.5.0 2024-06-10 GB initial release with periodic deltas
{
"Input": [
["Eingang 1","Zählerrohwert","$P_Raw_Counter_Value","c"],
["Eingang 2","Korrektur- / Initialisierungswert","$P_Offset_Value","u"],
["Eingang 3","Umrechnungsfaktor","$P_Scale_Factor","u"]
],
"Output": [
["Aktueller Zählerstand","Zählerwert weitergezählt + korrigiert","$O_Current_Counter_QS","ct"],
["Aktueller Zählerstand skaliert","Zählerwert weitergezählt + korrigiert + umgerechnet","$O_Current_Counter_QS_Scaled","ct"],
["Zähler Reset erkannt","Reset am Inputzähler","$Lgc_Found_Counter_Reset","c"],
["15Min Zählerstand Vorperiode", "Zählerstand am Ende der letzten 15-Minuten-Periode", "$State_15Min_Counter_Prev", "t"],
["15Min Delta Vorperiode", "Verbrauch der letzten 15-Minuten-Periode", "$State_15Min_Delta_Prev", "t"],
["15Min Delta Aktuell", "Verbrauch der aktuellen 15-Minuten-Periode", "$O_15Min_Delta_Current", "t"],
["Stunde Zählerstand Vorperiode", "Zählerstand am Ende der letzten Stunden-Periode", "$State_Hour_Counter_Prev", "t"],
["Stunde Delta Vorperiode", "Verbrauch der letzten Stunden-Periode", "$State_Hour_Delta_Prev", "t"],
["Stunde Delta Aktuell", "Verbrauch der aktuellen Stunden-Periode", "$O_Hour_Delta_Current", "t"],
["Tag Zählerstand Vorperiode", "Zählerstand am Ende der letzten Tages-Periode", "$State_Day_Counter_Prev", "t"],
["Tag Delta Vorperiode", "Verbrauch des letzten Tages", "$State_Day_Delta_Prev", "t"],
["Tag Delta Aktuell", "Verbrauch des aktuellen Tages", "$O_Day_Delta_Current", "t"],
["Woche Zählerstand Vorperiode", "Zählerstand am Ende der letzten Wochen-Periode", "$State_Week_Counter_Prev", "t"],
["Woche Delta Vorperiode", "Verbrauch der letzten Wochen-Periode", "$State_Week_Delta_Prev", "t"],
["Woche Delta Aktuell", "Verbrauch der aktuellen Woche", "$O_Week_Delta_Current", "t"],
["Monat Zählerstand Vorperiode", "Zählerstand am Ende der letzten Monats-Periode", "$State_Month_Counter_Prev", "t"],
["Monat Delta Vorperiode", "Verbrauch des letzten Monats", "$State_Month_Delta_Prev", "t"],
["Monat Delta Aktuell", "Verbrauch des aktuellen Monats", "$O_Month_Delta_Current", "t"],
["Quartal Zählerstand Vorperiode", "Zählerstand am Ende der letzten Quartals-Periode", "$State_Quarter_Counter_Prev", "t"],
["Quartal Delta Vorperiode", "Verbrauch des letzten Quartals", "$State_Quarter_Delta_Prev", "t"],
["Quartal Delta Aktuell", "Verbrauch des aktuellen Quartals", "$O_Quarter_Delta_Current", "t"],
["Jahr Zählerstand Vorperiode", "Zählerstand am Ende der letzten Jahres-Periode", "$State_Year_Counter_Prev", "t"],
["Jahr Delta Vorperiode", "Verbrauch des letzten Jahres", "$State_Year_Delta_Prev", "t"],
["Jahr Delta Aktuell", "Verbrauch des aktuellen Jahres", "$O_Year_Delta_Current", "t"]
// Output internal results for debuging
,["15Min Periodenende Trigger", "Debugging-Output für 15-Minuten Periodenende", "$Lgc_15Min_Period_End_Trigger", "c" ]
,["Internal_1","Wert war Trigger","$Lgc_Triggered_By_Input","a"]
,["Internal_2","Zwischenspeicher letzter Input","$State_Raw_Counter_Value","a"]
,["Internal_3","Zwischenspeicher letzter weitergezählter","$State_Current_Counter_Raw","a"]
,["Internal_4","Zwischenspeicher weitergezählter","$Lgc_Current_Counter_Raw","a"]
],
"Level": [
// input parameters
// Input1 raw measurment
["$P_Raw_Counter_Value","float",0],
// Input2 offset value to correct raw measurement
["$P_Offset_Value","float",0],
// Input3 conversion factor to scale Output1 to Output2
["$P_Scale_Factor","float",1.0],
// result / output variables
// result counter: corrected, offset
["$O_Current_Counter_QS","float",0],
// result counter: corrected, offset, scaled
["$O_Current_Counter_QS_Scaled","float",0],
// periodic statistics variables
// for each period we need previous state and output values to calculate deltas
// delta results are delta of current running period and during the last ended period
// 15-Min Period Variables
["$State_15Min_Counter_Prev", "float", 0.0],
["$State_15Min_Delta_Prev", "float", 0.0],
["$O_15Min_Delta_Current", "float", 0.0],
// Hour Period Variables
["$State_Hour_Counter_Prev", "float", 0.0],
["$State_Hour_Delta_Prev", "float", 0.0],
["$O_Hour_Delta_Current", "float", 0.0],
// Day Period Variables
["$State_Day_Counter_Prev", "float", 0.0],
["$State_Day_Delta_Prev", "float", 0.0],
["$O_Day_Delta_Current", "float", 0.0],
// Week Period Variables
["$State_Week_Counter_Prev", "float", 0.0],
["$State_Week_Delta_Prev", "float", 0.0],
["$O_Week_Delta_Current", "float", 0.0],
// Month Period Variables
["$State_Month_Counter_Prev", "float", 0.0],
["$State_Month_Delta_Prev", "float", 0.0],
["$O_Month_Delta_Current", "float", 0.0],
// Quarter Period Variables
["$State_Quarter_Counter_Prev", "float", 0.0],
["$State_Quarter_Delta_Prev", "float", 0.0],
["$O_Quarter_Delta_Current", "float", 0.0],
// Year Period Variables
["$State_Year_Counter_Prev", "float", 0.0],
["$State_Year_Delta_Prev", "float", 0.0],
["$O_Year_Delta_Current", "float", 0.0],
// State variables
// last raw value
["$State_Raw_Counter_Value","float",0],
// last value continued counter
["$State_Current_Counter_Raw","float",0],
// internal variables
// logic was triggerd by new raw counter value
["$Lgc_Triggered_By_Input","bool",false],
// logic was triggerd by cron impuls
["$Lgc_Triggered_By_Cron","bool",true],
// a counter reset was identified
["$Lgc_Found_Counter_Reset","bool",false],
// continued raw counter value
["$Lgc_Current_Counter_Raw","float",0],
// Localtime Variables
["$Lgc_Unix_Current", "integer", 0],
["$Lgc_Min_Current", "integer", 0],
["$Lgc_Hour_Current", "integer", 0],
["$Lgc_Mon_Current", "integer", 0],
["$Lgc_Wday_Current", "integer", 0],
["$Lgc_Unix_Tomorrow", "integer", 0],
["$Lgc_Mday_Tomorrow", "integer", 0],
// periodic end triggers
// Period End Triggers
["$Lgc_Is_Min_59", "bool", false],
["$Lgc_Is_Hour_23", "bool", false],
["$Lgc_Is_Sunday", "bool", false],
["$Lgc_Is_Last_Day_Of_Month", "bool", false],
["$Lgc_Is_Mon_3", "bool", false],
["$Lgc_Is_Mon_6", "bool", false],
["$Lgc_Is_Mon_9", "bool", false],
["$Lgc_Is_Mon_12", "bool", false],
["$Lgc_Is_Quarter_Month", "bool", false],
["$Lgc_15Min_Period_End_Trigger", "bool", false],
["$Lgc_Hour_Period_End_Trigger", "bool", false],
["$Lgc_Day_Period_End_Trigger", "bool", false],
["$Lgc_Week_Period_End_Trigger", "bool", false],
["$Lgc_Month_Period_End_Trigger", "bool", false],
["$Lgc_Quarter_Period_End_Trigger", "bool", false],
["$Lgc_Year_Period_End_Trigger", "bool", false],
// constants
// constant 1
["$C_one_int","integer",1],
// constant TRUE
["$C_True","bool",true],
// time constants
["$C_Day_in_Sec","integer",86400],
["$C_Min_59", "integer", 59],
["$C_Hour_23", "integer", 23],
["$C_Wday_0_Sunday", "integer", 0],
["$C_Mon_3", "integer", 3],
["$C_Mon_6", "integer", 6],
["$C_Mon_9", "integer", 9],
["$C_Mon_12", "integer", 12],
// cron expression for periodic trigger (second 57 >> 3 seconds before 15 minute end period)
["$Cron_15","string","57 14,29,44,59 * * * *"],
// formulas
// formula to continue counting depending of reset y or n (y: last continued + new input ; n: last continued + new input - last input)
["$F_counting","string","X1?X2+X3:X2+X3-X4"],
// formula to add (e.g. offset value)
["$F_add","string","X1+X2"],
["$F_Sub", "string", "X1-X2"],
// formula to multiply (e.g. sacaling factor)
["$F_times","string","X1*X2"]
],
"Module": [
// Check logik trigger
// set true if logic trigger was a new raw counter value Input
["Triggered", "$P_Raw_Counter_Value", "$Lgc_Triggered_By_Input"],
// Cron Trigger: set trigger for 15 Min Period End Trigger
["Cron","$C_True","$Lgc_15Min_Period_End_Trigger",0,"$Cron_15"],
// get time values from current timestamp
["Localtime",0,"$Lgc_Unix_Current",0,"$Lgc_Min_Current","$Lgc_Hour_Current",0,"$Lgc_Mon_Current",0,"$Lgc_Wday_Current",0,0],
// get time values from tomorrow timestamp
["CalcFormula",["$Lgc_Unix_Current","$C_Day_in_Sec"],"$Lgc_Unix_Tomorrow","$F_add"],
["Localtime","$Lgc_Unix_Tomorrow",0,0,0,0,"$Lgc_Mday_Tomorrow",0,0,0,0,0],
// set periodic end triggers
// check end of periods (Hour / Day / Week / Month / Quarter / Year) 15 Min allready set by cron trigger
["Limiter", "$Lgc_Min_Current", 0, "$Lgc_Is_Min_59", ["$C_Min_59", "$C_Min_59"]],
["Limiter", "$Lgc_Hour_Current", 0, "$Lgc_Is_Hour_23", ["$C_Hour_23", "$C_Hour_23"]],
["Limiter", "$Lgc_Wday_Current", 0, "$Lgc_Is_Sunday", ["$C_Wday_0_Sunday", "$C_Wday_0_Sunday"]],
["Limiter", "$Lgc_Mday_Tomorrow", 0, "$Lgc_Is_Last_Day_Of_Month", ["$C_one_int", "$C_one_int"]],
["Limiter", "$Lgc_Mon_Current", 0, "$Lgc_Is_Mon_3", ["$C_Mon_3", "$C_Mon_3"]],
["Limiter", "$Lgc_Mon_Current", 0, "$Lgc_Is_Mon_6", ["$C_Mon_6", "$C_Mon_6"]],
["Limiter", "$Lgc_Mon_Current", 0, "$Lgc_Is_Mon_9", ["$C_Mon_9", "$C_Mon_9"]],
["Limiter", "$Lgc_Mon_Current", 0, "$Lgc_Is_Mon_12", ["$C_Mon_12", "$C_Mon_12"]],
["Or",["$Lgc_Is_Mon_3","$Lgc_Is_Mon_6","$Lgc_Is_Mon_9"],"$Lgc_Is_Quarter_Month"],
// set period end triggers: combine end of period conditions with trigger conditions
["And",["$Lgc_15Min_Period_End_Trigger","$Lgc_Is_Min_59"],"$Lgc_Hour_Period_End_Trigger"],
["And",["$Lgc_Is_Hour_23","$Lgc_Hour_Period_End_Trigger"],"$Lgc_Day_Period_End_Trigger"],
["And",["$Lgc_Is_Sunday","$Lgc_Day_Period_End_Trigger"],"$Lgc_Week_Period_End_Trigger"],
["And",["$Lgc_Is_Last_Day_Of_Month","$Lgc_Day_Period_End_Trigger"],"$Lgc_Month_Period_End_Trigger"],
["And",["$Lgc_Is_Quarter_Month","$Lgc_Month_Period_End_Trigger"],"$Lgc_Quarter_Period_End_Trigger"],
["And",["$Lgc_Is_Mon_12","$Lgc_Month_Period_End_Trigger"],"$Lgc_Year_Period_End_Trigger"],
// logic 1 calculate qualified counter value
// compare raw value with last raw value to check if reset (old > new : == true)
["Comparator" , "$State_Raw_Counter_Value" , "$Lgc_Found_Counter_Reset" , "$P_Raw_Counter_Value"],
// calculate new raw counter depending on reset event
["CalcFormula",["$Lgc_Found_Counter_Reset","$State_Current_Counter_Raw","$P_Raw_Counter_Value","$State_Raw_Counter_Value"], "$Lgc_Current_Counter_Raw", "$F_counting"],
// result1 adding offset value to continued counting value
["CalcFormula",["$Lgc_Current_Counter_Raw","$P_Offset_Value"], "$O_Current_Counter_QS", "$F_add"],
// result2 scale result1 with scaling factor
["CalcFormula",["$O_Current_Counter_QS","$P_Scale_Factor"], "$O_Current_Counter_QS_Scaled", "$F_times"],
// safe new input value as last value for next run of logic
["Latch","$P_Raw_Counter_Value","$State_Raw_Counter_Value","$Lgc_Triggered_By_Input",0],
// safe new continued value as last value for next run of logic
["Latch","$Lgc_Current_Counter_Raw","$State_Current_Counter_Raw","$Lgc_Triggered_By_Input",0],
// logic 2 update deltas for each current periods
// 15 Min Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_15Min_Counter_Prev"], "$O_15Min_Delta_Current", "$F_Sub"],
// Hour Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_Hour_Counter_Prev"], "$O_Hour_Delta_Current", "$F_Sub"],
// Day Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_Day_Counter_Prev"], "$O_Day_Delta_Current", "$F_Sub"],
// Week Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_Week_Counter_Prev"], "$O_Week_Delta_Current", "$F_Sub"],
// Month Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_Month_Counter_Prev"], "$O_Month_Delta_Current", "$F_Sub"],
// Quarter Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_Quarter_Counter_Prev"], "$O_Quarter_Delta_Current", "$F_Sub"],
// Year Period
["CalcFormula", ["$O_Current_Counter_QS_Scaled", "$State_Year_Counter_Prev"], "$O_Year_Delta_Current", "$F_Sub"],
// logic 3 at end of periods: save current counter and delta as previous for next period and output previous period values
// 15 Min Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_15Min_Counter_Prev", "$Lgc_15Min_Period_End_Trigger", 0],
["Latch", "$O_15Min_Delta_Current", "$State_15Min_Delta_Prev", "$Lgc_15Min_Period_End_Trigger", 0],
// Hour Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_Hour_Counter_Prev", "$Lgc_Hour_Period_End_Trigger", 0],
["Latch", "$O_Hour_Delta_Current", "$State_Hour_Delta_Prev", "$Lgc_Hour_Period_End_Trigger", 0],
// Day Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_Day_Counter_Prev", "$Lgc_Day_Period_End_Trigger", 0],
["Latch", "$O_Day_Delta_Current", "$State_Day_Delta_Prev", "$Lgc_Day_Period_End_Trigger", 0],
// Week Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_Week_Counter_Prev", "$Lgc_Week_Period_End_Trigger", 0],
["Latch", "$O_Week_Delta_Current", "$State_Week_Delta_Prev", "$Lgc_Week_Period_End_Trigger", 0],
// Month Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_Month_Counter_Prev", "$Lgc_Month_Period_End_Trigger", 0],
["Latch", "$O_Month_Delta_Current", "$State_Month_Delta_Prev", "$Lgc_Month_Period_End_Trigger", 0],
// Quarter Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_Quarter_Counter_Prev", "$Lgc_Quarter_Period_End_Trigger", 0],
["Latch", "$O_Quarter_Delta_Current", "$State_Quarter_Delta_Prev", "$Lgc_Quarter_Period_End_Trigger", 0],
// Year Period
["Latch", "$O_Current_Counter_QS_Scaled", "$State_Year_Counter_Prev", "$Lgc_Year_Period_End_Trigger", 0],
["Latch", "$O_Year_Delta_Current", "$State_Year_Delta_Prev", "$Lgc_Year_Period_End_Trigger", 0]
]
}
/**Der Schöpfer dieser Custom Logik überträgt die Nutzungsrechte gemäß der TOLL ("Timberwolf Open Logikblock License") die unter https://wrgt.news/TOLL zum Download zur Verfügung steht.*/
Göran
