Skript zur Verbrauchsberechnung Gestern/Heute einer Sandfilteranlage

Hi,
ich möchte gerne die Verbrauchsdaten meiner Sandfilteranlage abbilden für den gestrigen Tag und den heutigen Tag. Jetzt habe ich mal im Forum mir einiges angeschaut und habe mir dann zwei Skripte angelegt, die folgendermaßen ausschauen. (Die Variable des Leistungsmesser logge ich als Aggregation/Zähler)

für den heutigen Tag:

$werte = AC_GetAggregatedValues(13449, 44848, 1 /* Täglich */, strtotime("today 00:00"), time(), 0); //13449 ID des Archives, 44848 ID des Homematic Zwischenstecker mit Leistungsmesser

foreach($werte as $wert) {
	SetValue(24483, $wert['Avg']); //Variable mit dem heutigen Verbrauch
}

Dazu ein Ereignis, bei Änderung der Variable Leistungsmesser, soll das Skript ausgeführt werden.

für den gestrigen Tag:

$werte = AC_GetAggregatedValues(13449 /*[Archive]*/, 44848 /*[Hardware\SDM 630\Total kWh]*/, 1 /* täglich */, strtotime("yesterday 23:59"), time(), -1); //13449 ID des Archives, 44848 ID des Homematic Zwischenstecker mit Leistungsmesser

foreach($werte as $wert) {
	echo date("d.m.Y H:i:s", $wert['TimeStamp']) . " -> " . $wert['Avg'] . PHP_EOL;
}
SetValue(23522 /*[Hardware\SDM 630\kWh Vortag]*/, $wert['Avg']);//Variable mit dem gestrigen Verbrauch

Zu dem gestrigen Verbrauch dann noch ein Ereignis angelegt das um 23:59:59 das Skript ausführt.

Wäre das so korrekt oder fehlt da noch was?

Hatte mir mal noch das Skript von @pitti angeschaut und das müsste ja eigentlich das gleiche machen, halt nur ausführlicher.

VG
Stefan

Irgendwo ist da ein Fehler bei der Berechnung des Wertes „Heutiger Tag“. Dieser Wert hinkt immer hinterher. Es fehlen immer ca. 20 - 30 Wh wenn ich die Werte aus dem Archiv ausrechne.

image
image

Wenn ich den Werte oben manuell ausrechne, komme ich auf den Wert 587,4 Wh. Die Variable hat aber nur 561,50 Wh.

Er schreibt mir wie es aussieht immer den „vorletzten“ Wert in die Variable.

Hast du das Skript mal einige Zeit nach der letzten Änderung der Variable manuell gestartet und geguckt, ob es dann passt? Wenn du das Skript durch Änderung der Variable triggerst, wird der letzte Wert noch nicht vom Archiv verarbeitet sein und du bekommst den vorherigen Wert vor der letzten Änderung.

Ich habe mir jetzt mal noch ein weiteres Skript erstellt aus einem Thread von KaiS:

$werteday = AC_GetAggregatedValues(13449 , 44848, 1 /* täglich */, strtotime("today 00:00"), strtotime("now"), 0); 
print_r($werteday);  //Ganzes Array ausgeben
echo $werteday[0]['Avg']; //Den Wert möchtest du haben, hier brauchst du keine Schleife.

SetValue(24483, $werteday[0]['Avg']);

Wenn ich das manuell ausführe nach einer Minute nach der letzten Aktualisierung dann passt das und wenn das Ereignis wieder auslöst, dann schreibt er wieder den niedrigeren Wert bzw. den vorletzten Wert rein.

Kann man das irgendwie umgehen, so das immer der aktuelle Wert geschrieben wird?

Sollte ich dann besser ein Ereignis erstellen das zyklisch z.B. jede Minute auslöst?

Du kannst versuchen, über den Spezialschalter ArchiveCommitInterval die Zeit zum Schreiben der Archivdaten zu optimieren. Würde ich aber nicht unbedingt empfehlen und ich glaube auch nicht, dass du es damit zuverlässig gelöst kriegst.

Ich arbeite in solchen Fällen mit einem Skripttimer und aktualisiere die Daten mit ca. 1 Minute Verzögerung.

Also meinst du das Ereignis komplett weg lassen und dann dieses hier einfügen im skript:

//veranlasst, dass das Skript alle 10 Sekunden ausgeführt wird        
IPS_SetScriptTimer($ScriptID, 10);

Zu meiner Schande: Diese Funktion kannte ich noch gar nicht, schon mal gesehen aber nicht weiter verfolgt.

Prinzipiell geht das natürlich auch, dass du das Skript permanent periodisch startest. Ob du das willst, hängt letzten Endes davon ab, was du sonst noch alles laufen hast und ob du mit dem Skript evtl. noch andere Dinge tust, bei denen das evtl. Probleme macht.

Ich mache es in der Regel so, dass ich das Skript durch die Variablenänderung triggern lasse, dann aktiviere ich den Timer und deaktiviere ihn nach der erneuten Ausführung wieder.

Du könntest auch im Skript einfach die erforderliche Zeit warten. Dann blockierst du allerdings für die Zeit einen Thread. Letzten Endes führen viele Wege nach Rom…

Da stehe ich dann am Ende mit meinem Latein. Wie würde das dann aussehen? Ereignis ist klar und was muss ich dann im Skript einfügen?

Habe es jetzt so angepasst.:

$werteday = AC_GetAggregatedValues(13449 , 44848, 1 /* täglich */, strtotime("today 00:00"), strtotime("now"), 0); 
print_r($werteday);  //Ganzes Array ausgeben
echo $werteday[0]['Avg']; //Den Wert möchtest du haben, hier brauchst du keine Schleife.

//veranlasst, dass das Skript alle 10 Sekunden ausgeführt wird        
IPS_SetScriptTimer(24782, 10); //ID des Skriptes

SetValue(24483, $werteday[0]['Avg']); //Schreibt den Wert in die Variable

Du rufst das Skript ganz normal über die Variablenänderung auf.

Anschließend prüfst du mit $_IPS['SENDER'] und/oder $_IPS['EVENT'], ob das Skript durch die Variablenänderung oder den Skripttimer aufgerufen wurde.

War es die Variablenänderung, startest du den Skripttimer und machst sonst nichts, war es der Skripttimer, rufst du die Daten aus dem Archiv ab, aktualisierst deine Variable und deaktivierst anschließend den Skripttimer wieder.

Du könntest auch beim Aufruf prüfen, ob der Skripttimer bereits läuft. Dann könnte es aber sein, dass das Skript zwischendurch schon wieder durch eine erneute Variablenänderung aufgerufen wurde, je nachdem, wie oft da Änderungen kommen. Die erste Variante ist die sichere.

Deine 10 Sekunden für den Timer sind übrigens zu wenig, damit es zuverlässig funktioniert. Du solltest hier aus eigener Erfahrung mindestens die Zeit des o.g. Spezialschalters ansetzen, also 60 Sekunden.

Wenn sich die Variable häufig ändert, solltest du zusätzlich noch sicherstellen, das der Skripttimer immer ab der letzten Variablenänderung mindestens einmal komplett (60 Sekunden) durch läuft. Sonst kann es passieren, dass kurz vor Ablauf des Timers noch ein Wert ins Archiv geschrieben wird und dieser dann doch wieder fehlt.

Jetzt haste mich liegen. Sorry bin eine null im Skripten.

Ich kann morgen mal ein Beispiel posten, wenn ich am Rechner bin. Vom Handy ist mir das zu mühsam.

Ja, wäre sehr nett von dir und Danke für deine Hilfe.

So, hier mal eine einfache Variante, wie du es lösen könntest:

<?php

// Hier die Daten aus dem Archiv abrufen und in Variable schreiben

// Wenn das Skript durch den ScriptTimer aufgerufen wurde, den ScriptTimer deaktivieren
if (@$_IPS['EVENT'] === @IPS_GetObjectIDByName('ScriptTimer', $_IPS['SELF'])) {
    IPS_SetScriptTimer($_IPS['SELF'], 0);
}

// Wenn das Skript nicht durch den ScriptTimer aufgerufen wurde, ScriptTimer aktivieren
else {
    IPS_SetScriptTimer($_IPS['SELF'], 70);
}

Wenn das Skript durch eine beliebige Aktion außer den ScriptTimer aufgerufen wird, startet es einen ScriptTimer mit 70 Sekunden oder setzt einen bereits laufenden Timer zurück und startet ihn neu. Wird das Skript hingegen durch den ScriptTimer aufgerufen, wird dieser wieder deaktiviert.

Wenn du das Skript also durch die Änderung deiner Variablen triggerst, werden einmal deine Daten aus dem Archiv gezogen, wobei der neuste Wert noch nicht dabei sein wird. Anschleißend wird der ScriptTimer mit 70 Sekunden (wegen des Commit-Intervalls von 60 Sekunden) gestartet und die Daten werden nach 70 Sekunden noch mal aus dem Archiv gezogen. Dann sollte der letzte Wert ebenfalls enthalten sein. Danach wird der ScriptTimer deaktiviert und das Ganze geht mit der nächsten Variablenänderung von vorne los.

Sollte sich in der Zwischenzeit (während der ScriptTimer läuft) die Variable erneut ändern, wird der ScriptTimer zurückgesetzt und läuft wieder von vorne los. Wenn sich deine Variable also häufig innerhalb der 70 Sekunden ändert, wird der ScriptTimer permanent laufen und du könntest dir die ganze Logik im Prinzip auch sparen.

Ansonsten kannst du natürlich noch beliebige Optimeriungen vornehmen (Semaphore einbauen, auf andere Ereignisse gezielt reagieren etc.). Das hängt davon ab, ob und was du sonst noch so mit dem Skript machst. Ich habe jetzt einfach mal unterstellt, dass es nur die Daten aus dem Archiv abruft, durch die Variablenänderung getriggert wird und sich die Variable nicht in kürzeren Intervallen als 70 Sekunden ändert.

Gruß
Slummi

Guten Morgen,
Danke dir für die Hilfestellung und ausführliche Erklärung. Das Skript aktualisiert nur den Wert der Variable und das passiert so ca. alle 3 Minuten. Ansonsten soll das Skript nichts machen.

Habe es jetzt so eingefügt:

<?php

$werteday = AC_GetAggregatedValues(13449 , 44848, 1 /* täglich */, strtotime("today 00:00"), strtotime("now"), 0); 
print_r($werteday);  //Ganzes Array ausgeben
echo $werteday[0]['Avg']; //Den Wert möchtest du haben, hier brauchst du keine Schleife.

// Wenn das Skript durch den ScriptTimer aufgerufen wurde, den ScriptTimer deaktivieren
if (@$_IPS['EVENT'] === @IPS_GetObjectIDByName('ScriptTimer', $_IPS['SELF'])) {
    IPS_SetScriptTimer($_IPS['SELF'], 0);
}

// Wenn das Skript nicht durch den ScriptTimer aufgerufen wurde, ScriptTimer aktivieren
else {
    IPS_SetScriptTimer($_IPS['SELF'], 70);
}


SetValue(24483, $werteday[0]['Avg']); //Schreibt den Wert in die Variable

Das ist normal das wenn der SkriptTimer ausgelöst hat mir ein graues Ausrufezeichen angezeigt wird? Wenn das Event auslöst ist das Ausrufezeichen weg.

VG
Stefan

Ja, das bedeutet einfach nur, dass der ScriptTimer dann deaktiviert ist.

Muss das Thema wieder kurz aufgreifen. Habe die Nacht um 0:00 Uhr gesehen das die Variable „Verbrauch Heute“ den Wert behält, also praktisch der gestrige und heutige Tag, zeigen den gleichen Verbrauchswert. Ist mehr oder weniger ein Schönheitsfehler. Wenn die Pumpe um 7:00 Uhr das erste mal angeht springt sie dann auf 0,00 Wh.
Ich habe jetzt eben der Variable „Verbrauch Heute“ ein Zyklisches Ereignis zugefügt das um 0:00:00 Uhr der Wert auf 0,00 Wh setzt. Um 23:59:59 wird aber der Wert von der Variable „Verbrauch Heute“ in die Variable „Verbrauch Gestern“ geschrieben.

Jetzt bezieht sich meine Frage ob diese Zeit reicht oder kommt es dann zu Überschneidungen?

Normalerweise sollte das funktionieren. Ich will aber nicht ausschließen, dass es in dem ein oder anderen Fall zu Verzögerungen und einer Abarbeitung der Skripte „in falscher Reihenfolge“ kommt, wenn sich etwas staut.

Warum fasst du nicht beide Punkte in einem Skript zusammen? Erst schreibst du den Verbrauch von heute in die Variable von gestern und wenn das erledigt ist, setzt du den Verbrauch zurück? Oder du rufst durch das Skript zum Schreiben des Verbrauchs von gestern das Skript für den Verbrauch von heute auf. Dann greift ja auch der ScriptTimer und es sollte spätestens um 00:01 Uhr passen.

PHP ist immer noch nicht mein Freund. :roll_eyes: Bin Froh das die Skripte die ich mir zusammen gesucht habe direkt funktioniert haben.

Das sind jetzt die aktuellen Skripte die ich verwende:

Verbrauch Heute:

<?php

$werteday = AC_GetAggregatedValues(13449, 44848, 1 /* täglich */, strtotime("today 00:00"), strtotime("now"), 0); // 13449 vom Archiv Control, 44848 ist die ID der Variable, 
print_r($werteday);  // Ganzes Array ausgeben
echo $werteday[0]['Avg']; // Den Wert möchte ich ausgeben

// Wenn das Skript durch den ScriptTimer aufgerufen wurde, den ScriptTimer deaktivieren
if (@$_IPS['EVENT'] === @IPS_GetObjectIDByName('ScriptTimer', $_IPS['SELF'])) {
    IPS_SetScriptTimer($_IPS['SELF'], 0);
}

// Wenn das Skript nicht durch den ScriptTimer aufgerufen wurde, ScriptTimer aktivieren
else {
    IPS_SetScriptTimer($_IPS['SELF'], 70);
}


// Veranlasst, dass das Skript alle 10 Sekunden ausgeführt wird        
//IPS_SetScriptTimer(24782, 10); // ID des Skriptes


// Hier die Daten aus dem Archiv abrufen und in Variable schreiben
SetValue(24483, $werteday[0]['Avg']); // Schreibt den Wert in die Variable

Verbrauch Gestern:

<?php

$werte = AC_GetAggregatedValues(13449, 44848, 1 /* täglich */, strtotime("yesterday 23:59"), time(), -1); // 13449 vom Archiv Control, 44848 ist die ID der Variable, 
foreach($werte as $wert) {
	echo date("d.m.Y H:i:s", $wert['TimeStamp']) . " -> " . $wert['Avg'] . PHP_EOL;
}
SetValue(23522, $wert['Avg']); // Schreibt den Wert in die Variable

Das ganze geht bestimmt besser, einfacher und schöner, wenn man weiß was man tut. :smiley:

Edit: Also heute Nacht um 0 Uhr hat es Mal reibungslos funktioniert. Zuerst wurde der gestrige Verbrauch aktualisiert und der heutige Verbrauch sprang dann auf 0,00 Wh.