#!/usr/bin/env python import urllib, math, time, threading, os from ftplib import FTP import RPi.GPIO as GPIO import LCD, hp03s, ds18s20 #Einstellungen fuer externen FTP-Server: URL = "" # Adresse USER = "" # Benutzername PWD = "" # Passwort DIR = "www/pi/tempdata" # Verzeichnis auf externen Server LOCALDIR = "/var/www/pi/tempdata/" # Verzeichnis auf Pi FDLY = 30*60 # Zeit zur naechsten Sync (sec) # Einstellungen fuer Messung TSENSOR = "10-000802d9d249" # One-Wire Adresse fuer Temperatursensor PXCLR = 17 # PIN XCLR PBUS = 1 # I2C-Bus TDLY = 10 # Zeit zur naechsten Messung # Einstellungen fuer Datenversand LOCALURL = "http://localhost/pi/sendtemp.php" # URL fuer PHP-Skript zum Speichern LOCALPWD = "" # Passwort fuer Speicherskript SDLY = 5*60 # Zeit zur naechsten Datenversand def timestr(): # Funktion fuer print zum Anzeigen der Zeit return time.strftime("%m%d%H%M ") class TempFTP(threading.Thread): # Klasse zur Sync mit externen Server def __init__(self, event): # Konstrukter mit event-Uebergabe fuer Multitasking threading.Thread.__init__(self) self.stopped = event def FileExists(self, ftp, file): # Ueberprueft ob Datei auf FTP-Server existiert filelist = [] ftp.retrlines('LIST',filelist.append) for f in filelist: if file in f: return True return False def SizeLocal(self,file): # Gibt Dateigroesse einer lokalen Datei aus return os.path.getsize(LOCALDIR + file) def SizeFTP(self,ftp, file): # Gibt Dateigroesse einer externen Datei aus return ftp.size(file) def run(self): # Hauptprogramm while not self.stopped.wait(FDLY): # While-Schleife mit Abbruch-Event try: ftp = FTP(URL) # Initialisiere FTP-Verbindung ftp.login(USER, PWD) # Login ftp.cwd(DIR) # Aendere aktuelles Verzeichnis ftp.sendcmd("TYPE i") for file in os.listdir(LOCALDIR): if file.endswith(".txt") and file.startswith(time.strftime("%y")): print (timestr()+"[FTP] Check: "+file) # Ueberpruefe Dateien aus aktuellen Jahr und .txt datei = open(LOCALDIR + file, "r") # Oeffne lokale Datei txt = datei.read() # Lese lokale Datei sizeLocal1 = len(txt) # Groesse 1 aus Zeichenkettenlaenge sizeLocal2 = self.SizeLocal(file) # Groesse 2 aus Funktion (beide Abfragen loesen Problem mit doppelten Zeilenumbruch) sizeFTP = 0 datei.close() # Datei schliessen if (self.FileExists(ftp, file)): # Lese Groesse der externen Datei, wenn existiert sizeFTP = self.SizeFTP(ftp, file) print(timestr()+"[FTP] Size: "+str(sizeLocal1) + ","+str(sizeLocal2)+ ","+str(sizeFTP)) if (sizeLocal2 != sizeFTP and sizeLocal1 != sizeFTP): # Vergleiche externen Groesse mit beiden internen ftp.storbinary("STOR "+file, open(LOCALDIR + file, "rb")) # Lade neue Datei hoch print (timestr()+"[FTP] Refresh: "+file) print timestr()+("[FTP] End") except: print (timestr()+"[FTP] Error") ftp.close() # Schliesse FTP-Instanz class RingStorage: # Klasse fuer Ringspeicher zum Glaetten der Messwerte def __init__(self, n): # Konstrukter: Groesse des Ringspeichers self.n = n self.c = 0 # aktuelle Position self.filled = 0 # aktueller Fuellstand self.list = list(0 for i in range(n)) # erstelle leere Liste def addContent(self, z): # Funktion um Daten hinzuzufuegen self.list[self.c]=z # Wert in Liste speichern self.c = (self.c+1) % self.n # Aktuelle Position aendern self.filled = self.filled + 1 # Aktueller Fuellstand ueberpruefen if (self.filled > self.n): self.filled = self.n def getMedium(self): # Funktion um Mittelwert abzurufen sum = 0 for i in range(self.n): # Summe aller Werte bestimmen sum = sum + self.list[i] if (self.filled > 0): return sum / self.filled # MW ausgeben falls Werte vorhanden else: return -99 # bei leere Liste Fehlerzahl -99 ausgeben class WeatherMgr(threading.Thread): # Klasse fuer Messung und LCD-Anzeige def __init__(self, event): # Konstrukter threading.Thread.__init__(self) # even-Uebergabe fuer Multitasking self.stopped = event self.temps = RingStorage(60) # Erstelle Ringspeicher fuer Temperatur und Luftdruck self.press = RingStorage(60) self.ds = ds18s20.DS18S20(TSENSOR) # Temperatursensor-Instanz aus Bibliothek self.hp = hp03s.hp03s(PBUS, PXCLR) # Luftdrucksensor-Instanz aus Bibliothek GPIO.setup(7, GPIO.OUT) # Pins fuer LCD als Ausgang definieren GPIO.setup(8, GPIO.OUT) GPIO.setup(25, GPIO.OUT) GPIO.setup(24, GPIO.OUT) GPIO.setup(23, GPIO.OUT) GPIO.setup(18, GPIO.OUT) self.lcd = LCD.LCD() # LCD-Instanz aus Bibliothek self.lcd.display_init() # LCD initialisieren def run(self): # Hauptprogramm while not self.stopped.wait(TDLY): # While-Schleife mit Abbruch-Event t = self.ds.readTemp()/1000. # Lese Temperatur aus self.temps.addContent(t) # Zum Ringspeicher hinzuzufuegen p = self.hp.getPressure()*1.0124 #Lese Luftdruck aus Hoehenfaktor: rechneronline.de/barometer/ self.press.addContent(p) # Zum Ringspeicher hinzuzufuegen print timestr()+"[WTH] "+str(t)+"|"+str(p) self.updateDisp() # Starte Funktion Display aktualisieren def updateDisp(self): # Funktion LCD aktualisieren tm = time.strftime("%H:%M") # Zeit-Zeichenkette t = str(round(self.temps.getMedium(),1)) # Temperatur-Zeichenkette aus Ringspeicher p = str(int(self.press.getMedium())) # Luftdruck-Zeichenkette self.lcd.goto_line(1) # LCD-Anzeige schreiben self.lcd.lcd_string(tm) self.lcd.goto_line(2) self.lcd.lcd_string(p+"hPa "+t+chr(223)+"C") # chr(223) ist das Grad-Zeichen (siehe Datenblatt LCD) class SendMgr(threading.Thread): # Klasse fuer Datenversand def __init__(self, event): # Konstrukter mit event-Uebergabe fuer Multitasking threading.Thread.__init__(self) self.stopped = event def run(self): # Hauptprogramm while not self.stopped.wait(SDLY): # While-Schleife mit Abbruch-Event t = whmgr.temps.getMedium() # Mittelwerte aus Ringspeicher p = whmgr.press.getMedium() if (t != -99 and p!=-99): # Sende Daten wenn Ringspeicher nicht leer tm = str(int(time.time())) # aktuelle UNIX-Zeit abrufen file = time.strftime("%y-%W") # aktuelle Wochenzahl und Jahr um Datei zum Speichern auszuwaehlen data = tm + "_" + str(round(t,1))+ "_" + str(round(p,1)) print (timestr()+"[SND] "+data) response = urllib.urlopen(LOCALURL+"?data="+data+"&file="+file+"&code="+LOCALPWD) # Daten via PHP-POST senden stop = threading.Event() # Erstelle Event-Instanz um Programm zu stoppen ftpmgr = TempFTP(stop) # Erstelle Instanzen der jew. Klassen ftpmgr.start() # und starte Multitasking (run() wird ausgefuehrt) whmgr = WeatherMgr(stop) whmgr.start() sndmgr = SendMgr(stop) sndmgr.start() def main(): # Hauptprogramm try: while True: # Halte Programm am laufen time.sleep(1) stop.set() except KeyboardInterrupt: # Ctrl-C set Event und Multitasks werden beendet stop.set() if __name__ == '__main__': main() # starte Hauptprogramm