Logo

    

    

 

 

| Konzept | Javascript | Script Banner | CGI SunnyData-fake | CGI SunnyWeb |
CGI-Script für .SUO-Dateien
von webmaster, Freitag, 22. Februar 2013


#!Pfad.../bin/perl -w

#=================================================================================
#Dateiname: fakesd.pl
#Author: K. O.
#Date: 26.03.2013
#Version: 1.2.1
#Bearbeitet mit Notepad++
#Bearbeitet .suo-Dateien von SunnyData, wenn der Wechselrichter wg. EEPROM-Fehlers 
#den gespeicherten Gesamtertrag verliert. Damit SunnyWeb die richtigen Statistiken 
#erzeugt, ist die Manipulation notwendig. Jeweils am ersten eines Monats wird die 
#aufgelaufene Differenz zwischen Wechselrichter und dem #wirklichen Ertrag in der 
#entsprechenden .ini-Datei von SunnyWeb korrigiert. Der Wechselrichter, die
#.suo-Dateien und die SunyWeb-Statistiken werden dadurch wieder stringent.
#Zusätzlich wird täglich der Energiewert in SunnyWeb (Profilexx.ini) korrigiert (ab 1.1.0)
#Ab 1.2.0: SunnyWeb starten und beenden, sobald Wechselrichter Daten liefert
#Ab 1.2.1: Bildschirmschoner beenden und SW-Symbol in Infoleiste entfernen
#==================================================================================

use CGI::Carp "fatalsToBrowser";
use strict;
		#Fehlerausgabe in Logdatei
open STDERR, ">>Pfad.../skript.log" or die $!;
		#gibt Warnungen an Browser
use warnings;
$SIG{__WARN__} = sub {die 'WARN: '.shift};
use Win32::Process;
use Win32::GuiTest qw(MouseMoveAbsPix);

#==================Dateinamen berechnen===============================
		# Für Pfad x date berechnen
my ($Monatstag, $Monat, $Jahr) = (localtime(time))[3,4,5];
$Monat +=1;
$Jahr -= 100;
$Monat = $Monat < 10 ? $Monat = "0".$Monat : $Monat;
$Monatstag = $Monatstag < 10 ? $Monatstag = "0".$Monatstag : $Monatstag;
my $DFile = "Pfad../test/".$Monatstag.$Monat.$Jahr."00.SUO";   #Pfad Tagesfile .suo

		# Für Pfad x-1 u. x-2 date berechnen
my ($Dm1_Monatstag, $Dm1_Monat, $Dm1_Jahr) = (localtime(time - 86400))[3,4,5];
my ($Dm2_Monatstag, $Dm2_Monat, $Dm2_Jahr) = (localtime(time - 172800))[3,4,5];
$Dm1_Monat += 1;
$Dm2_Monat += 1;
$Dm1_Jahr -= 100;
$Dm2_Jahr -= 100;
$Dm1_Monat = $Dm1_Monat < 10 ? $Dm1_Monat = "0".$Dm1_Monat : $Dm1_Monat;
$Dm2_Monat = $Dm2_Monat < 10 ? $Dm2_Monat = "0".$Dm2_Monat : $Dm2_Monat;
$Dm1_Monatstag = $Dm1_Monatstag < 10 ? $Dm1_Monatstag = "0".$Dm1_Monatstag : $Dm1_Monatstag;
$Dm2_Monatstag = $Dm2_Monatstag < 10 ? $Dm2_Monatstag = "0".$Dm2_Monatstag : $Dm2_Monatstag;
        #Pfad  x-1.suo
my $Dm1File = "Pfad../Data/".$Dm1_Monatstag.$Dm1_Monat.$Dm1_Jahr."00.SUO";  
        #Pfad  x-2.suo
my $Dm2File = "Pfad../Data/".$Dm2_Monatstag.$Dm2_Monat.$Dm2_Jahr."00.SUO";  

		#Abbrechen, wenn keine x-1.suo - Datei vorhanden
unless (-e $Dm1File) { goto ENDE; }
		#Testausgabe
		#print "Content-type: text/html\n\n";
		#===================x-2.suo lesen=========================================
my $Dm2LZ;
my $Dm2LZenergy;
my $Dm1FZenergy;
my $Dm1LZenergy = "0";
my $Dm1LZenergyNew = "0";
my $zeilen;
my $LZ;
my $i = 0;
		
		#Letzte Zeile x-2 auslesen und Energiewert ermitteln
open (TXTFILE, "+<$Dm2File") or die "Err $!\n";
	while (<TXTFILE>){
		$Dm2LZ = $_;
		$LZ = $.;
	}
close TXTFILE;

		#zu OFFSET02, wenn weniger als 2 Datenzeilen (eigentlich nicht möglich)
if ( $LZ > 4 ) { 
	$Dm2LZenergy = (split/\t/,$Dm2LZ)[10];
}
else { goto OFFSET02; }

#********************************Fall 1: keine Abweichung******************************
#=======================x-1.suo lesen und bewerten=====================================
        #File x-1 einlesen und vorerst Energie Anfang (Z5) und Ende (letze Zeile) auslesen
open (FILE, "+<$Dm1File") or die "Err $!\n";
	my @tempDm1File = <FILE>;
close FILE;
$zeilen = @tempDm1File - 1;  
        #nach Fehler "EEPROM" während Betrieb WR suchen
        #nur suchen, wenn EEPROM-Fehler >15 Datenzeilen nach Start WR
        #letzter oder einziger EEPROM Fehler des Tages wird erfasst
my $EepromLine = "-1";
my $EEPROMm1Energy = "0";
foreach ( @tempDm1File ) {
	if ($i > 15 && index($_,"EEPROM") != -1) {    
		$EepromLine = $i;                         
	}
$i++;
}
        #letzten Energiestand des WR vor EEPROM Fehler ermitteln
if ( $EepromLine > 15) {$EEPROMm1Energy = (split/\t/,$tempDm1File[$EepromLine - 1])[10];} 
        #mindestens>=2 Datenzeilen
if ( $zeilen > 4 ) {  
	$Dm1FZenergy = (split/\t/,$tempDm1File[4])[10];   
	$Dm1LZenergy = (split/\t/,$tempDm1File[$zeilen])[10];
		#Energiewert für OFFSET02 speichern
	$Dm1LZenergyNew = $Dm1LZenergy;
		#Falls keine Abweichung, alles ok und zu OFFSET02
	if ($Dm1FZenergy eq $Dm2LZenergy && $EEPROMm1Energy eq "0") { goto OFFSET02; }
}

#***********************************Fall 3: fehlende Datenzeilen****************************
#==========================x-1.suo bei fehlenden Datenzeilen bearbeiten=====================
        #wenn nur eine oder keine Datezeile vorhanden ist, werden zwei neue Zeilen eingefügt
		#und die Energy Start/Ende auf Wert von x-2 gesetzt
else { 
	$Dm1FZenergy = $Dm2LZenergy;
	$Dm1LZenergy = $Dm2LZenergy;
		#Energiewert für OFFSET02 speichern
	$Dm1LZenergyNew = $Dm2LZenergy;
	    #Datum/Zeit für die neuen Datenzeilen berechnen
	my $DTm1FZ = $Dm1_Monatstag.".".$Dm1_Monat.".".($Dm1_Jahr + 2000)." 08:00:00";
	my $DTm1LZ = $Dm1_Monatstag.".".$Dm1_Monat.".".($Dm1_Jahr + 2000)." 18:00:00";
	my $Dm1FZ = $Dm2LZ;
	my $Dm1LZ = $Dm2LZ;
	    #Datum/zeit setzen
	my $SEDate = (split/\t/,$Dm2LZ)[0];
	$Dm1FZ =~ s/$SEDate/$DTm1FZ/;
	$Dm1LZ =~ s/$SEDate/$DTm1LZ/;
	    #Falls nur eine Datenzeile vorhanden, diese löschen
	if ( $zeilen == 4 ) { pop(@tempDm1File); } 
	    #neue Zeilen in Array einfügen
	push(@tempDm1File,$Dm1FZ);
	push(@tempDm1File,$Dm1LZ);
	    #.suo neu schreiben
	open (FILE3, ">$Dm1File") or die "Err $!\n";
		print FILE3 @tempDm1File;
	close FILE3;
	goto OFFSET02;
}

        #wegen Berechnung "," gegen "." tauschen
$Dm2LZenergy =~ s/\,/\./g;
$Dm1FZenergy =~ s/\,/\./g;
$Dm1LZenergy =~ s/\,/\./g;
$EEPROMm1Energy =~ s/\,/\./g;

#*************************Fall 4: Monatsanfang und negative Abweichung*************************
#===================profile.ini in SunnyWeb bearbeiten und Daten konsolidieren=================
my $OffsetLine0;
my $OffsetLine0nr;
my $OffsetLine1;
my $OffsetLine1nr;
my $OffsetValue0;
my $OffsetValue1;
my $OffsetValue0New;
my $OffsetValue1New;
my $OffsetDate1;
my $OffsetDate1nr;
my $OffsetD1New;

if ( $Monatstag == "01" ) {
	open (INIFILE, "+<Pfad.. /profile01.ini") or die "Err $!\n";
		my @tempINI = <INIFILE>;
	close INIFILE;
	$i = 0;
	foreach ( @tempINI ) {
		if (index($_,"OffsetCounter01") != -1) {
			$OffsetLine1 = $_;
			$OffsetLine1nr = $i;
		}
		elsif (index($_,"OffsetCounter00") != -1) {
			$OffsetLine0 = $_;
			$OffsetLine0nr = $i;
		}
		elsif (index($_,"OffsetDate01") != -1) {
			$OffsetDate1 = $_;
			$OffsetDate1nr = $i;
		}
		$i++;
	}

	$OffsetValue0 = (split/\=/,$OffsetLine0)[1];
	$OffsetValue1 = (split/\=/,$OffsetLine1)[1];
	$OffsetValue0 =~ s/\,/\./g;
	$OffsetValue1 =~ s/\,/\./g;
	$OffsetValue0New = $OffsetValue0 + $OffsetValue1;
	$OffsetValue1New = $Dm2LZenergy + $EEPROMm1Energy - $Dm1FZenergy;
			#OffsetCounter darf nie leer sein
	if ( $OffsetValue1New eq "" ) { $OffsetValue1New = "0"; }
	$OffsetValue0New =~ s/\./\,/g;
	$OffsetValue1New =~ s/\./\,/g;
	$OffsetValue0New = $OffsetValue0New."\n";
	$OffsetValue1New = $OffsetValue1New."\n";
	$OffsetD1New = "OffsetDate01=".$Dm1_Monatstag.".".$Dm1_Monat.".".($Dm1_Jahr + 2000)."\n";
	$OffsetValue0 =~ s/\./\,/g;
	$OffsetValue1 =~ s/\./\,/g;
		#Offset 0, Offset 1 und Offset Date 1 ersetzen
	$tempINI[$OffsetLine0nr] =~ s/$OffsetValue0/$OffsetValue0New/;  
	$tempINI[$OffsetLine1nr] =~ s/$OffsetValue1/$OffsetValue1New/; 
	$tempINI[$OffsetDate1nr] =~ s/$OffsetDate1/$OffsetD1New/;  

	    #profile.ini neu schreiben
	open (INIFILE, ">Pfad.../profile01.ini") or die "Err $!\n"; 
		print INIFILE @tempINI;
	close INIFILE;
	goto OFFSET02;  #am letzten des Monats keine .suo-Korrektur
}

#************************************Fall 2: negative Abweichung**************************
#================aufgelaufene Abweichungen in x-1.suo erste/letzte Zeile korrigieren======
		#Energy x-1 Anfang kleiner als x-2 Ende oder EEPROM-Fehler 
if (($Dm2LZenergy - $Dm1FZenergy) > 0 || $EEPROMm1Energy > 0) {         
        #neuer Energy-Wert Tagesende x-1
	$Dm1LZenergyNew = $Dm1LZenergy + $Dm2LZenergy - $Dm1FZenergy + $EEPROMm1Energy;
		#bei Integer .0 anhängen
	if ( index($Dm1LZenergyNew,".") == -1 ) {    
		$Dm1LZenergyNew = $Dm1LZenergyNew.".0";
	}
	    #Rücktausch '.' gegen ','
	$Dm1LZenergyNew =~ s/\./\,/g;
	$Dm2LZenergy =~ s/\./\,/g;
	$Dm1FZenergy =~ s/\./\,/g;
	$Dm1LZenergy =~ s/\./\,/g;
		#ersetzen Energiewerte erste und letzte Zeile
	$tempDm1File[4] =~ s/$Dm1FZenergy/$Dm2LZenergy/;      
	$tempDm1File[$zeilen] =~ s/$Dm1LZenergy/$Dm1LZenergyNew/; 
		#x-1.suo neu schreiben
	open (FILE3, ">$Dm1File") or die "Err $!\n";	      
		print FILE3 @tempDm1File;
	close FILE3;

}
OFFSET02:
#*************tägliche Korrektur des Ertrags in SunnyWeb, sobald der WR Messwerte liefert*****
my $TimeActual;
my $ActualRoot = "Pfad../Sunny Data/Plant01/ACTUAL.TXT";
my $OffsetLine2;
my $OffsetLine2nr;
my $OffsetDate2;
my $OffsetDate2nr;
my $StartTime = time;	
	
		#auf erste Messwerte von SunnyData warten (alle 120 sek. schauen)
do {
	sleep(120);
	$TimeActual = (stat("$ActualRoot"))[9];
	if ((time - $StartTime) > 25200) { goto ENDE; } #Abbruch nach 7h
}
while((time - $TimeActual) > 90);  #90 s  >= 1,5 x Aufzeichn.-Zyklus SunnyData

		#2 sek. warten, dann actual.txt lesen
sleep (2);
open(ACTUALFILE, "<$ActualRoot") or die "Err $!\n";
	my $ActualCont = <ACTUALFILE>;
close(ACTUALFILE);
		#für test
		#my $jetzt = time - $TimeActual;
		#print " Differenz: $jetzt  \n<br>";
		
		#Datensätze trennen und Energiewert WR auslesen
my $ActualEnergy = (split/\t/,$ActualCont)[10];
$ActualEnergy =~ s/\,/\./g;
$Dm1LZenergyNew =~ s/\,/\./g;
		#Offset 02 berechnen
my $OffsetValue2New = $Dm1LZenergyNew - $ActualEnergy;
		#OffsetCounter darf nie leer sein
if ( $OffsetValue2New eq "" ) { $OffsetValue2New = "0"; }
$OffsetValue2New =~ s/\./\,/g;
$OffsetValue2New = $OffsetValue2New."\n";
		
		#Testausgabe
		#print "Aktuell: $ActualEnergy \n<br>";
		#print "Dm1 LZ: $Dm1LZenergyNew \n<br>";
		#print "Tagesoffset: $OffsetValue2New<br>";

		#profilexx.ini lesen
open (INIFILE, "+<Pfad... /SunnyWeb/profile01.ini") or die "Err $!\n";
	my @INIArray = <INIFILE>;
close INIFILE;
		
		#Offset 02 lesen (Content, Zeilen)
$i = 0;
foreach ( @INIArray  ) {
	if (index($_,"OffsetCounter02") != -1) {
		$OffsetLine2 = $_;
		$OffsetLine2nr = $i;
	}
	elsif (index($_,"OffsetDate02") != -1) {
		$OffsetDate2 = $_;
		$OffsetDate2nr = $i;
	}
$i++;
}
my $OffsetValue2 = (split/\=/,$OffsetLine2)[1];

		#Datum berechnen 
my $OffsetD2New = "OffsetDate02=".$Monatstag.".".$Monat.".".($Jahr + 2000)."\n";
		
		#Offset und Datum in Array schreiben
$INIArray [$OffsetLine2nr] =~ s/$OffsetValue2/$OffsetValue2New/;
$INIArray[$OffsetDate2nr] =~ s/$OffsetDate2/$OffsetD2New/;
		
		#profile.ini neu schreiben
open (INIFILE, ">Pfad../SunnyWeb/profile01.ini") or die "Err $!\n"; 
	print INIFILE @INIArray;
close INIFILE;

#***************Daten refresh: 2te Instanz von SunnyWeb starten und wieder beenden****************
		
		#SW  verarbeitet die Korrekturen in der profilexx.ini entweder bei Neustart oder bei
		#Zuwachs des Ertrags um 0,1 kWh. Daher: Neustart einer weiteren Instanz, Verarbeitung der Daten
		#und schließen der 2ten SW-Instanz. Dadurch stehen die neuen Daten sofort zur Verfügung
		
my $command = "Pfad...\\sunnyweb\\sunnyweb.exe";
my $args = "";
my $process; # Prozess-Objekt
my $CTimeStart = localtime(time);
		#Prozess starten
Win32::Process::Create($process, $command, $args, 0, NORMAL_PRIORITY_CLASS, '.');
		#Prozess-ID ermitteln und 75 sec. warten
my $pid = $process -> GetProcessID();
sleep(75);
		#dann Prozess beenden
if (kill 0 => $pid){	#läuft der Process noch?
kill 9, $pid;
}
		#Wg. Bug in SunnyWeb:
		#Maus auf SunnyWeb-Symbol in Infoleiste stellen, damit SW-Symbol entfernt wird
		#px-Position ist von Anzeige-Auflösung abhängig, hier 800x600
#MouseMoveAbsPix(100, 100); #Bildschirmschoner beenden (optional)
MouseMoveAbsPix(746, 588);
my $CTimeStop = localtime(time);
		#Prozessstart und -ende in Logdatei schreiben
warn("SW Start: $CTimeStart Stop: $CTimeStop\n");

ENDE:
		#Testausgabe
		#print "ENDE</BODY></HTML>\n";
1;

Darstellung des Codes erfolgt mit:
SyntaxHighlighter version 3.0.83 (July 02 2010)
http://alexgorbatchev.com/SyntaxHighlighter