Python-Script zum Erzeugen der Sensordaten in Form einer Javaschript-Datei die zusammen mit den HTML-Dateinen des Ziel-Servers die Sensordaten
graphisch darstellt. Es werden aus den Rohdaten (Aufzeichnungsdichte ca. 10 Sekunden) jeweils nur die Minutenwerte übernommen. D.h. max. 1440 Werte (bzw. Pixel).
#------------------------------------------------------------------------------- # Name: vrc.py # Purpose: build javascript file of data records to be displayed # # Author: Michael Gries (griemide) # Copyright: (c) 2014, Michael Gries # # History: # 2014-11-09 first creation # 2014-11-27 support for neg. outdoor values - def getFloatSigned() # 2015-02-19 Var objects added (to be independent # to SSI support on hosted web sites) # 2015-02-20 filling lines (for pixels) if empty data records identified # 2015-03-15 calculation total heating time per day # 2015-03-17 calculation total heating periods per day #------------------------------------------------------------------------------- def main(): pass if __name__ == '__main__': main() version = "15.3.17" sourcefilename = "vrc_2014-11-07.log" # default destinationfilename = "vrc2008day.txt" # standard output file ftpTransferScript = "vrc2ftp.py" datagramSize = 67 import sys cntArgv = len(sys.argv) if (cntArgv > 1): sourcefilename = str(sys.argv[1]) print("argv[1]: " + sourcefilename) else: print("argv[1]: n/a \n") print("Source : " + sourcefilename) posStatus = 18 posSekunde = 22 posMinute = 23 posStunde = 24 posAussen = 32 posWasser = 35 posKessel = 38 posHeiz_k = 47 posBetrieb = 65 lastMinuteHex = "FF" h1hhmmss = "24:59:59" # 24 h Format t1Aussen = 10 t2Wasser = 50 t3Kessel = 80 t4Heiz_k = 99 s1Status = 00 b1Betrieb = 99 # calculation globals c1Seconds = 10 # sample rate of monitoring system in seconds c1Totals = 0 # totals of heading time per sample rate in seconds c2PeriodTotals = 0 # totals of heading period per day c2PeriodStatus = False # status of new checked sample (0-no heating / 1-heating) c2PeriodLast = False # status of last checked sample (0-no heating / 1-heating) # heating period: count on rising edge of c1PeriodStatus^c1PeriodLast (NOR gate) headerTxt = "// H[1]=Zeitstempel; T[1]=Aussentemp; T[2]=Wassertemp; T[3]=Kesseltemp; T[4]=Heizkurve; S[1]=B.-Status; // line hhmm\n" layoutOld = "T[1][i] =10.0; T[2][i] =50.0; T[3][i] =80.0; T[4][i] =99.0; S[1][i] =0; " layoutNew = "H[1][iiii]='24:59:59'; T[1][iiii]=+ 9.9; T[2][iiii]=50.0; T[3][iiii]=80.0; T[4][iiii]=99.0; S[1][iiii]=0000; // zzzz hhmm" # Attention: usage of array index iiii only with non leading zeros to avoid misalignments within the array # use Javascript Debugger of IE9 (F12 Entwicklertools) for array debugging iHHMM = "0000" # Function definition def checkHeatingTime(datagram, pos): "extract status value out of dataset" result = False datagramRawDataLength = 203 if ( len(datagram) == datagramRawDataLength): dataset = datagram.split() wordHex = dataset[pos] + dataset[pos +1] print wordHex intHex = int(wordHex) intMask = intHex & 3 if (intMask != 0): result = True return result def checkNextMinute(datagram, pos): "extract minute value out of dataset" result = False datagramRawDataLength = 203 if ( len(datagram) == datagramRawDataLength): dataset = datagram.split() global lastMinuteHex minuteHex = dataset[pos] print minuteHex if (minuteHex != lastMinuteHex): result = True lastMinuteHex = minuteHex return result def getTimestamp(dataset, posSekunde, posMinute, posStunde): intHex = dataset[posSekunde] intSekunde = int(intHex, base=16) intHex = dataset[posMinute] intMinute = int(intHex, base=16) intHex = dataset[posStunde] intStunde = int(intHex, base=16) Timestamp = "%02d" % intStunde + ":" + "%02d" % intMinute + ":" + "%02d" % intSekunde return Timestamp def getByte(dataset, pos): "build integer string out of one datagram bytes" byteHex = dataset[pos] integerValue = int(byteHex, base=16) return "%02d" % integerValue def getWord(dataset, pos): "build integer string out of two datagram bytes" wordHex = dataset[pos] + dataset[pos +1] integerValue = int(wordHex, base=16) return "%04d" % integerValue def getFloat(dataset, pos): "build float string out of two datagram bytes" wordHex = dataset[pos] + dataset[pos +1] integerValue = int(wordHex, base=16) floatValue = float(float(integerValue) / 16) floatValueString = "%04.1f" % floatValue return floatValueString def getFloatSigned(dataset, pos): "build float string out of two datagram bytes" wordHex = dataset[pos] + dataset[pos +1] integerValue = int(wordHex, base=16) if ((integerValue & 0x8000) > 0 ): integerValue = integerValue - 0x10000 floatValue = float(float(integerValue) / 16) floatValueString = "%+ 5.1f" % floatValue return floatValueString def aggregateData(noOfTimestamps, recordNo, datagram): " build aggregated dat out of datagram" global b1Betrieb # for last record in destination file global iHHMM # record position in array H[1][iHHMM] datagramRawDataLength = 203 if ( len(datagram) == datagramRawDataLength): dataset = datagram.split() h1hhmmss = getTimestamp(dataset, posSekunde, posMinute, posStunde) iHHMM = h1hhmmss[:2] + h1hhmmss[3:5] # nur Stunde und Minute ohne Trennzeichen h1Timestamp = "H[1][" + "%04d" % noOfTimestamps + "]='" + h1hhmmss + "'; " t1Aussen = getFloatSigned(dataset, posAussen) t1AussenText = "T[1][" + "%04d" % noOfTimestamps + "]=" + t1Aussen + "; " t2Wasser = getFloat(dataset, posWasser) t2WasserText = "T[2][" + "%04d" % noOfTimestamps + "]=" + t2Wasser + "; " t3Kessel = getFloat(dataset, posKessel) t3KesselText = "T[3][" + "%04d" % noOfTimestamps + "]=" + t3Kessel + "; " t4Heiz_k = getFloat(dataset, posHeiz_k) t4Heiz_kText = "T[4][" + "%04d" % noOfTimestamps + "]=" + t4Heiz_k + "; " s1Status = getWord(dataset, posStatus) s1StatusText = "S[1][" + "%04d" % noOfTimestamps + "]=" + s1Status + "; " commentText = "// %4d" % recordNo + " %4s" % iHHMM aggregatedRow = h1Timestamp + t1AussenText + t2WasserText + t3KesselText + t4Heiz_kText + s1StatusText + commentText b1Betrieb = getByte(dataset, posBetrieb) # for last record in destination file else: aggregatedRow = "Error" return aggregatedRow; def aggregateFillingData(noOfTimestamps, pseudoRecordNo, pseudotimestamp): " build aggregated filling data with out of Spec values" if (True): h1hhmmss = pseudotimestamp[:2] + ":" + pseudotimestamp[2:4] + ":00" h1Timestamp = "H[1][" + "%04d" % noOfTimestamps + "]='" + h1hhmmss + "'; " t1Aussen = " +0.0" t1AussenText = "T[1][" + "%04d" % noOfTimestamps + "]=" + t1Aussen + "; " t2Wasser = " 0.0" t2WasserText = "T[2][" + "%04d" % noOfTimestamps + "]=" + t2Wasser + "; " t3Kessel = " 0.0" t3KesselText = "T[3][" + "%04d" % noOfTimestamps + "]=" + t3Kessel + "; " t4Heiz_k = " 0.0" t4Heiz_kText = "T[4][" + "%04d" % noOfTimestamps + "]=" + t4Heiz_k + "; " s1Status = "0000" s1StatusText = "S[1][" + "%04d" % noOfTimestamps + "]=" + s1Status + "; " commentText = "// %4s" % pseudoRecordNo + " %4s" % pseudotimestamp aggregatedRow = h1Timestamp + t1AussenText + t2WasserText + t3KesselText + t4Heiz_kText + s1StatusText + commentText else: aggregatedRow = "Error" return aggregatedRow; def increaseCount(countervalue): "counts 24 hour and 60 minutes in format 'hhmm' " hh = countervalue/100 mm = countervalue%100 mm = mm +1 if(mm > 59): mm = 0 hh = hh + 1 if(hh > 23): hh = 0 countervalue = hh * 100 + mm return countervalue; # main fobj_in = open(sourcefilename) fobj_out = open(destinationfilename,"w") from datetime import datetime import time timestamp = datetime.now() timeStarted = time.time() vrcSource = "// Sourcefile: %s \n" % sourcefilename vrcStamp1 = "// generation: %s started \n" % timestamp.strftime('%Y-%m-%d %H:%M:%S') vrcProgNo = "// Python 2.7.6.1 script 'vrc.py' version %s \n" % version vrcAuthor = "// (c) 2014-2015, Michael Gries \n" vrcBlank0 = "// \n" vrcHeader = vrcSource + vrcStamp1 + vrcProgNo + vrcAuthor + vrcBlank0 fobj_out.write(vrcHeader) vrcRefNo1 = "// http://de.selfhtml.org/javascript/objekte/array.htm#assoziative_arrays \n" vrcRefNo2 = "// Anm.1: in eckiger Klammer nur Zahlen oder Strings in Hochkommas. \n" vrcRefNo3 = "// Anm.2: verschiedene Arrays m?glich (hier T[] und V[] \n" vrcReference = vrcRefNo1 + vrcRefNo2 + vrcRefNo3 fobj_out.write(vrcReference) vrcVar_B_ = "var B = new Array(); // Betriebsart des letzten Datensatzes \n" vrcNew_B1 = " B[1] = new Object(); // Beispiel '00'=Sommerbetrieb, '01'=Winterbetrieb \n" vrcVar_C_ = "var C = new Array(); // Kalkulierte Werte aus Datensaetzen\n" vrcNew_C1 = " C[1] = new Object(); // Kummulierte Brennerdauer in Sekunden\n" vrcNew_C2 = " C[2] = new Object(); // Anzahl Brennerstarts \n" vrcVar_N_ = "var N = new Array(); // Dateiname der Quelldatensaetze \n" vrcNew_N1 = " N[1] = new Object(); // Beispiel vrc_2014-09-30.log \n" vrcVar_H_ = "var H = new Array(); // Zeitstempel \n" vrcNew_H1 = " H[1] = new Object(); // hh:mm:ss \n" vrcVarXXX = vrcVar_B_ + vrcNew_B1 + vrcVar_C_ + vrcNew_C1 + vrcNew_C2 + vrcVar_N_ + vrcNew_N1 + vrcVar_H_ + vrcNew_H1 fobj_out.write(vrcVarXXX) vrcVar_T_ = "var T = new Array(); // Temperaturwerte \n" vrcNew_T1 = " T[1] = new Object(); // Aussentemperatur \n" vrcNew_T2 = " T[2] = new Object(); // Wassertemperatur \n" vrcNew_T3 = " T[3] = new Object(); // Kesseltemperatur \n" vrcNew_T4 = " T[4] = new Object(); // Heizkurve \n" vrcVar_S_ = "var S = new Array(); // Statuswerte \n" vrcNew_S1 = " S[1] = new Object(); // Betriebszustand \n" vrcVarXXX = vrcVar_T_ + vrcNew_T1 + vrcNew_T2 + vrcNew_T3 + vrcNew_T4 + vrcVar_S_ + vrcNew_S1 fobj_out.write(vrcVarXXX) vrcBlank1 = "// Allgemeiner Parameter zur Darstellung der Quelldatendatei \n" vrcN1Para = " N[1][1]='%s'; // Name der Quelldatei auf Server\n" % sourcefilename vrcHeader = vrcBlank1 + vrcN1Para + headerTxt fobj_out.write(vrcHeader) print(vrcStamp1) marker = "-" noOfTimestamps = 1000 RecordID = 0 count = 0 for line in fobj_in: RecordID = RecordID + 1 debugLine = "\n" + str(RecordID) + ": "+ line.rstrip() print(debugLine) firstRow = line.split(' ', datagramSize) if checkHeatingTime(line, posStatus): c1Totals = c1Totals + c1Seconds if (not (c2PeriodStatus or c2PeriodLast)): # NOR gate c2PeriodStatus = True # starts heating period c2PeriodTotals = c2PeriodTotals + 1 else: c2PeriodStatus = False # ends heating period if checkNextMinute(line, posMinute): vrcData = aggregateData(noOfTimestamps, RecordID, line) countRecord = int(iHHMM) while(count < countRecord): countTimestamp = "%04d" % count vrcFillingData = aggregateFillingData(noOfTimestamps, marker, countTimestamp) print(vrcFillingData) fobj_out.write(vrcFillingData + "\n") noOfTimestamps = noOfTimestamps + 1 count = increaseCount(count) debugVRCdata = str(RecordID) + ": "+ vrcData print(debugVRCdata) vrcRecord = vrcData + "\n" fobj_out.write(vrcRecord) noOfTimestamps = noOfTimestamps + 1 count = increaseCount(count) vrcBlank2 = "// Betriebsart auf Basis des letzten Datensatzes darstellen \n" vrcB1Para = " B[1][1]='%s'; // Betriebsart: '00'=Sommerbetrieb; '01'=Winterbetrieb \n" % b1Betrieb vrcC1text = "// Kalkulierte Brennerdauer aus allen relevanten Status Datensatz berechnen \n" vrcC1Para = " C[1][1]='%s'; // Kalkulierte Brennerdauer (in Sekunden) \n" % c1Totals vrcC2text = "// Anzahl Brennerstarts aus allen relevanten Status Datensatz berechnen \n" vrcC2Para = " C[2][1]='%s'; // Anzahl Brennerstarts \n" % c2PeriodTotals timestamp = datetime.now() timeEnded = time.time() timeTotal = timeEnded - timeStarted vrcStamp2 = "// generation: %s ended " % timestamp.strftime('%Y-%m-%d %H:%M:%S') + "(%.1f seconds)\n" % timeTotal vrcEOFdef = "// EOF \n" vrcFooter = vrcBlank2 + vrcB1Para + vrcC1text + vrcC1Para + vrcC2text + vrcC2Para + vrcStamp2 + vrcEOFdef fobj_out.write(vrcFooter) fobj_in.close() fobj_out.close() print("\n") vrcStatus = vrcStamp2 + "// %s " % sourcefilename + "-> vrc2008day.txt \n" print(vrcStatus) vrcScript = "start transfering 'vrc2008day.txt' via script '" + ftpTransferScript + "' ...\n" print(vrcScript) execfile("vrc2ftp.py")
Python-Script zum übertragen der erzeugten Javascript-Datei
mittels ftp auf den Ziel-Server.
Zusätzlich Kopie der Datei auf die SD-Karte des lokalen Servers.
# /usr/bin/ftpTransferDataViaArgv1.py # 2014-11-14 # Michael Gries sourcefile = "vrc2008day.txt" import sys # sys.path.insert(0, '/usr/lib/python2.7/bridge/') #csys.path.append ('/usr/lib/python2.7/bridge/') # filenameArgv1 = str(sys.argv[1]) # print("argv[1]: " + filenameArgv1) command = "STOR " + sourcefile print("ftp: " + command) fobj_in = open(sourcefile) from ftplib import FTP ftp=FTP("www.gries.name") ftp.login("3376-227","45780176") ftp.cwd("/VRC") ftp.storlines(command, fobj_in) ftp.close() print("ftp: done") fobj_in.close()
Achtung:
Datei nur im LINUX-System editieren und nicht z.B. mit Notepad unter Windows,
da sonst 'ˆM' am Ende einer jeweiligen Zeile angehangen wird.
# /usr/bin # 2014-11-14 creaion # 2015-02-19 copy result to 'txt' folder on local sd-card pwd cd /mnt/sda1/arduino/www/vrc # dateOfLogfile=$(date +%Y-%m-%d) echo $dateOfLogfile # # filename="vrc_"$dateOfLogfile".log" textfile="txt/vrc_"$dateOfLogfile".txt" echo $filename # python vrc.py $filename # cp vrc2008day.txt txt/vrc2008day.txt cp vrc2008day.txt $textfile echo $textfile #
Das script liegt im vrc-Verzeichnis der SD-Karte
Es kann mittels linux soft-link unter /usr/bin von überall angesprochen werden
Einrichtung mittel PuTTY: 'ln -s /mnt/sda1/arduino/www/vrc/vrc /usr/bin/vrc'