Es werden immer wieder mal Doppelte Archiv Einträge eingetragen

Hi,
ich möchte gerne meine Werte aus einer Wh Zähler Variable, in eine andere kWh Variable schreiben und archivieren. Ich nutze dieses Skript dafür:

<?php

$debug = TRUE;
$SourceID = 51246 ; //Variable mit Zählerwert "Gesamt - PV Ertrag Eingänge A+B" vom Wechselrichter
$TargetID = 56722; //Zielvariable 
$ArchiveList = IPS_GetInstanceListByModuleID("{43192F0B-135B-4CE7-A0A7-1475603F3060}"); //Archivinstanzen abrufen
$ArchiveID = $ArchiveList[0]; // !!! Es wird die erste gefundene Archivinstanz verwendet

$StartDate="24.03.2022";
$EndDate = "27.03.2022";

if ($debug){$beginn = microtime(true); };
$d = 0;
$timestamp = 0;
$end = new DateTimeImmutable($EndDate);
$endtime = strtotime($end->format('Y-m-d H:i:s'));
$start = new DateTimeImmutable($StartDate);
$starttime = strtotime($start->format('Y-m-d H:i:s'));

//AC_DeleteVariableData($ArchiveID, $TargetID, 0, 0); //bei Aktivierung kann man die Archiv Ziel Variable löschen
AC_SetLoggingStatus($ArchiveID , $TargetID, true);

while ($starttime < $endtime){

    $datetime = $start->modify('+'.$d.' day');
    $starttime = strtotime($datetime->format('Y-m-d H:i:s'));
    $datetime = $datetime->modify('+1 day');
    $endarchive = strtotime($datetime->format('Y-m-d H:i:s'));

    if ($debug){echo "Starttime: ".date('d.m.Y H:i:s', $starttime).PHP_EOL;};

    $logData = AC_GetLoggedValues($ArchiveID, $SourceID,  $starttime, $endarchive, 0); //Datensätze abfragen

    $entries = count($logData); //Anzahl der Werte

    if ($debug){echo "Einträge: ".$entries.PHP_EOL;};

    
    
if ($entries >0) {
        for ($i = $entries; $i > 0; $i--){

                $value = $logData[$i-1]['Value']/1000;
                $timestamp = $logData[$i-1]['TimeStamp'];
                AC_AddLoggedValues ($ArchiveID, $TargetID, [['TimeStamp' => $timestamp,'Value' => $value]]);
        }
    }
    

    $d++;

}

//AC_SetAggregationType ($ArchiveID, $TargetID, 1);
//AC_ReAggregateVariable ($ArchiveID, $TargetID);
if ($debug){
$dauer = round(microtime(true) - $beginn,2); 
echo "Verarbeitung des Skripts: $dauer Sek.";
    }

Es ist zwar mühselig diese Umwandlung da ich immer nur ein paar Tage schreiben kann, da es ziemlich das System belastet. Jetzt habe ich schon des Öfteren festgestellt das er mir plötzlich bei manchem umwandeln bzw. Skript ausführen die Daten doppelt archiviert. Muss dann immer wieder von vorne anfangen, was mir allmählich die Lust raubt.

Weiß auch nicht warum das so ist, bei dem letzten mal ist mir aufgefallen das der Bildschirm auf Ruhemodus geschaltet hat und wie ich ihn wieder aktiviert habe war auch die Pro Konsole neu gestartet, also konnte nicht mehr ablesen wie lange das Skript gebraucht hat. Vielleicht ist es auch nur Zufall und hat nichts damit zu tun.

Gibt es den nicht die Möglichkeit diese doppelten Einträge zu löschen oder auch die Tage die es betrifft und das ich nicht wieder von vorne anfangen muss?

LG
Stefan

Wenn ich mir das Skript so anschaue, dann könnte es sein, dass Werte, die exakt auf 00:00 Uhr liegen doppelt geschrieben werden können, da du diese Zeit je einmal als Start- und einmal als Endzeit hast, da du immer von 00:00 Uhr bis 00:00 Uhr abfragst. Falls das zu deinem Fehler passt, dann müsstest du einfach die Endzeit auf 23:59:59 anpassen.

Darüber hinaus würde ich dir empfehlen, ein Array mit neuen Werten zu füllen und diese gebündelt als Eingabe von AC_AddLoggedValues zu verwenden. Führst du für jeden Wert einzeln die Funktion aus, treibt das die Ausführungszeit ungemein in die Höhe. Falls du mit sehr vielen Werten arbeitest, müsstest du vielleicht aber dennoch manches mal zwischendurch die Werte reinschieben, da der Speicher, den PHP nutzt nicht ausreichen könnte. Mehrere Tausend Werte sollten kein Problem darstellen, wenn du jetzt aber sekündlich geloggte Werte über mehrere Jahre übertragen möchtest, dann könnte es eng werden.

Hi,
Die Werte die er doppelt schreibt sind über die ganze Tageszeit verteilt und exakt immer zweimal vorhanden. Pro Tag sind es immer so ca. 3200 Werte.

VG
Stefan

@Dr.Niels
Das Skript ist jetzt abgeändert, aber ich bekomme jetzt die Memory Meldung wenn ich das Skript ausführe.

<?php

$debug = TRUE;
$SourceID = 51246 ; //Variable mit Zählerwert "Gesamt - PV Ertrag Eingänge A+B" vom Wechselrichter
$TargetID = 56722; //Zielvariable 
$ArchiveList = IPS_GetInstanceListByModuleID("{43192F0B-135B-4CE7-A0A7-1475603F3060}"); //Archivinstanzen abrufen
$ArchiveID = $ArchiveList[0]; // !!! Es wird die erste gefundene Archivinstanz verwendet

$StartDate="23.04.2022";
$EndDate = "24.04.2022";

if ($debug){$beginn = microtime(true); };
$d = 0;
$timestamp = 0;
$end = new DateTimeImmutable($EndDate);
$endtime = strtotime($end->format('Y-m-d H:i:s'));
$start = new DateTimeImmutable($StartDate);
$starttime = strtotime($start->format('Y-m-d H:i:s'));

//AC_DeleteVariableData($ArchiveID, $TargetID, 0, 0); //bei Aktivierung kann man die Archiv Ziel Variable die Werte löschen
AC_SetLoggingStatus($ArchiveID , $TargetID, true);

while ($starttime < $endtime){

    $datetime = $start->modify('+'.$d.' day');
    $starttime = strtotime($datetime->format('Y-m-d H:i:s'));
    $datetime = $datetime->modify('+1 day');
    $endarchive = strtotime($datetime->format('Y-m-d H:i:s'));

    if ($debug){echo "Starttime: ".date('d.m.Y H:i:s', $starttime).PHP_EOL;};

    $logData = AC_GetLoggedValues($ArchiveID, $SourceID,  $starttime, $endarchive, 0); //Datensätze abfragen

    $entries = count($logData); //Anzahl der Werte

    if ($debug){echo "Einträge: ".$entries.PHP_EOL;};

    
    
if ($entries >0) {
for ($i = $entries; $i > 0; $i--){

            $value = $logData[$i-1]['Value']/1000;
            $timestamp = $logData[$i-1]['TimeStamp'];
            $data_array[] = ['TimeStamp' => $timestamp,'Value' => $value];
            //AC_AddLoggedValues ($ArchiveID, $TargetID, [['TimeStamp' => $timestamp,'Value' => $value]]);

    }
    //print_r($data_array);
    AC_AddLoggedValues ($ArchiveID, $TargetID, $data_array);
    unset($data_array);
}
//break;

$d++;

}

//AC_SetAggregationType ($ArchiveID, $TargetID, 1);
//AC_ReAggregateVariable ($ArchiveID, $TargetID);
if ($debug){
$dauer = round(microtime(true) - $beginn,2); 
echo "Verarbeitung des Skripts: $dauer Sek.";
    }
Starttime: 23.04.2022 00:00:00
Einträge: 3932

Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 4194312 bytes) in /var/lib/symcon/scripts/57226.ips.php on line 45
Abort Processing during Fatal-Error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 4194312 bytes)
   Error in Script /var/lib/symcon/scripts/57226.ips.php on Line 45

Ich habe in den Spezialschalter das Limit in ServerHardQueueBytesLimit schon um das doppelte erhöht.

VG
Stefan

Kann man den Memory Limit Wert in der php.ini auf 128M schrauben um das Problem zu umgehen oder sollte man da eher die Finger davon lassen.

Moin Stefan,

ich habe den Wert auf memory_limit=128M gesetzt. Das läuft seit Jahren ohne Probleme allerdings unter Win 10.

Gruß
Hans

Hallo Hans,
ich hatte mal eben schon mal auf 64M gesetzt, aber auch dort bekomme ich diese Memory Meldung. Ich versuche mal gleich die 128M Variante.

LG
Stefan

Ne, hat leider nichts gebracht und bekomme jetzt die Meldung, dann ist das Skript so für die vielen Werte nicht zu gebrauchen:

Starttime: 23.04.2022 00:00:00
Einträge: 3932

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /var/lib/symcon/scripts/57226.ips.php on line 45

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes) in /var/lib/symcon/scripts/IPSLibrary/app/core/IPSLogger/IPSLogger_Output.inc.php on line 28

Ok, es sind scheinbar zu viele Werte für ein einzelnes Array. Du könntest in deiner Schleife prüfen, ob du mittlerweile 5000 Werte (oder so) zusammen hast. Falls ja, schreibst du diese via AC_AddLoggedValues in die Datei und setzt dein Wertearray zurück auf ein leeres Array.

Gerade mit @Stefan71 den Fehler gefunden. War wohl ein Fehler beim Kopieren, da es von mir nicht in ein Code-Block gesetzt wurde. Falsch:

for ($i = $entries; $i > 0; $i–){

Richtig:

for ($i = $entries; $i > 0; $i--){

Da muss der Speicher Überlaufen :wink:

Habe das Skript oben geändert, Danke an @steppe und @Dr.Niels