diff --git a/Logger.py b/Logger.py new file mode 100644 index 0000000..1b58462 --- /dev/null +++ b/Logger.py @@ -0,0 +1,150 @@ +import machine +import os +import TimeUtils + +class Logger(): + def __init__(self, hk_days): + self.hk_days = hk_days + self.TimeUtils = TimeUtils.TimeUtils() + self.tempLogFile = True + self.tempSoilFile = True + if not "logs" in os.listdir(): + os.mkdir("/logs") + if not "soil" in os.listdir(): + os.mkdir("/soil") + + def LogMessage(self, message): + print(message) + lfname = "/logs/temp.txt" + if not self.tempLogFile: + dt = machine.RTC().datetime() + lfname = ("/logs/%04d-%02d-%02d.txt" % (dt[0], dt[1], dt[2])) + dt = machine.RTC().datetime() + file = open(lfname, "a") + file.write(self.TimeUtils.DateTimeNow() + ";" + message + "\n") + file.close() + + def LogSoil(self, message): + print(message) + lfname = "/soil/temp.txt" + if not self.tempSoilFile: + dt = machine.RTC().datetime() + lfname = ("/soil/%04d-%02d-%02d.txt" % (dt[0], dt[1], dt[2])) + dt = machine.RTC().datetime() + file = open(lfname, "a") + file.write(self.TimeUtils.DateTimeNow() + ";" + str(message) + "\n") + file.close() + + def Housekeeping(self): + for file in os.listdir("/logs"): + if (file.endswith(".txt")) and not (file == "temp.txt"): + fd = file.split('.')[0].split('-') + if (self.TimeUtils.IsOlderThanDays(fd, self.hk_days)): + os.remove("/logs/" + file) + self.LogMessage("Housekeeping: deleted logfile " + file) + for file in os.listdir("/soil"): + if (file.endswith(".txt")) and not (file == "temp.txt"): + fd = file.split('.')[0].split('-') + if (self.TimeUtils.IsOlderThanDays(fd, self.hk_days)): + os.remove("/soil/" + file) + self.LogMessage("Housekeeping: deleted soilfile " + file) + + def LastLogs(self, lines): + logfilename = "/logs/temp.txt" + if not self.tempLogFile: + dt = machine.RTC().datetime() + logfilename = ("/logs/%04d-%02d-%02d.txt" % (dt[0], dt[1], dt[2])) + bufsize = 4096 + fsize = os.stat(logfilename)[6] + iter = 0 + with open(logfilename, "r") as logfile: + line_count = 0 + for line in logfile: + line_count += 1 + if (lines > line_count): + lines = line_count + #todo if lines from todays logfile are less than the number of requested lines, read missing lines from yesterdays logfile - only if not tempLogFile! + if bufsize > fsize: + bufsize = fsize - 1 + fetched_lines = [] + while True: + iter += 1 + try: + logfile.seek(fsize - bufsize * iter) + fetched_lines.extend(logfile.readlines()) + except: + return "eof" + break + if len(fetched_lines) >= lines or logfile.tell() == 0: + return "
".join(fetched_lines[-lines:]) + break + + def LastSoils(self, lines): + logfilename = "/soil/temp.txt" + if not self.tempLogFile: + dt = machine.RTC().datetime() + logfilename = ("/soil/%04d-%02d-%02d.txt" % (dt[0], dt[1], dt[2])) + bufsize = 4096 + fsize = os.stat(logfilename)[6] + iter = 0 + with open(logfilename, "r") as logfile2: + line_count = 0 + for line in logfile2: + line_count += 1 + if (lines > line_count): + lines = line_count + #todo if lines from todays logfile are less than the number of requested lines, read missing lines from yesterdays logfile - only if not tempLogFile! + if bufsize > fsize: + bufsize = fsize - 1 + fetched_lines = [] + while True: + iter += 1 + try: + logfile2.seek(fsize - bufsize * iter) + fetched_lines.extend(logfile2.readlines()) + except: + return "eof" + break + if len(fetched_lines) >= lines or logfile2.tell() == 0: + return "
".join(fetched_lines[-lines:]) + break + + def MergeTempLogfile(self): + if not self.tempLogFile: + tempLines = 0 + try: + with open("/logs/temp.txt", "r") as tempfile: + tlines = tempfile.readlines() + dt = machine.RTC().datetime() + with open(("/logs/%04d-%02d-%02d.txt" % (dt[0], dt[1], dt[2])), "a") as logfile: + for line in tlines: + tempLines += 1 + logfile.write(line) + os.remove("/logs/temp.txt") + self.LogMessage("Merged " + str(tempLines) + " lines from temp-logfile into this logfile") + except OSError: + pass + + def MergeTempSoilfile(self): + if not self.tempSoilFile: + tempLines = 0 + try: + with open("/soil/temp.txt", "r") as tempfile: + tlines = tempfile.readlines() + dt = machine.RTC().datetime() + with open(("/soil/%04d-%02d-%02d.txt" % (dt[0], dt[1], dt[2])), "a") as logfile: + for line in tlines: + tempLines += 1 + logfile.write(line) + os.remove("/soil/temp.txt") + self.LogMessage("Merged " + str(tempLines) + " lines from temp-soilfile into todays soilfile") + except OSError: + pass + + def DisableTempLogfile(self): + self.tempLogFile = False + self.MergeTempLogfile() + + def DisableTempSoilfile(self): + self.tempSoilFile = False + self.MergeTempSoilfile() \ No newline at end of file diff --git a/NTP.py b/NTP.py new file mode 100644 index 0000000..004e167 --- /dev/null +++ b/NTP.py @@ -0,0 +1,38 @@ +import utime as time +import socket +import ustruct as struct +import machine + +class NTP(): + def __init__(self, Logger): + self.Logger = Logger + + def SetRTCTimeFromNTP(self, host, gmt_offset, auto_summertime): + self.Logger.LogMessage("getting date and time from NTP " + host) + NTP_DELTA = 2208988800 + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(5) + res = s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + except Exception as err: + self.Logger.LogMessage("Error: " + str(err)) + return False + finally: + s.close() + ntp_time = struct.unpack("!I", msg[40:44])[0] + (3600 * gmt_offset) #gmt offset from config + tm = time.gmtime(ntp_time - NTP_DELTA) + if (auto_summertime): + self.Logger.LogMessage("performing auto_summertime adjustment") + #Time of March change for the current year + t1 = time.mktime((tm[0],3,(31-(int(5*tm[0]/4+4))%7),1,0,0,0,0)) + #Time of October change for the current year + t2 = time.mktime((tm[0],10,(31-(int(5*tm[0]/4+1))%7),1,0,0,0,0)) + t = time.mktime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) + if t >= t1 and t < t2: + tm = time.gmtime(ntp_time - NTP_DELTA + 3600) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) + return True \ No newline at end of file diff --git a/Networking.py b/Networking.py new file mode 100644 index 0000000..0b477b8 --- /dev/null +++ b/Networking.py @@ -0,0 +1,79 @@ +import network +import ubinascii +import Logger +import machine +import time + +wlan = network.WLAN(network.STA_IF) +led = machine.Pin('LED', machine.Pin.OUT) + +class Networking(): + def __init__(self, Logger, ssid, pw): + self.ssid = ssid + self.pw = pw + self.Logger = Logger + + def Connect(self, disable_wifi_powersavingmode): + global wlan + wlan.active(True) + #wlan.config(hostname=configs['hostname']) + if (disable_wifi_powersavingmode): + wlan.config(pm = 0xa11140) + self.Logger.LogMessage("mac = " + self.GetMACAddress()) + self.Logger.LogMessage("channel = " + str(wlan.config('channel'))) + self.Logger.LogMessage("essid = " + str(wlan.config('essid'))) + self.Logger.LogMessage("txpower = " + str(wlan.config('txpower'))) + wlan.connect(self.ssid, self.pw) + timeout = 30 + while timeout > 0: + if wlan.status() < 0 or wlan.status() >= 3: + break + timeout -= 1 + self.Logger.LogMessage('Waiting for connection...') + time.sleep(1) + + # Wlan Status on LED + # Handle connection error + # Error meanings + # 0 Link Down + # 1 Link Join + # 2 Link NoIp + # 3 Link Up + # -1 Link Fail + # -2 Link NoNet + # -3 Link BadAuth + def Status(self): + global wlan + wlan_status = wlan.status() + self.BlinkOnboardLED(wlan_status) + if wlan_status != 3: + #raise RuntimeError('Wi-Fi connection failed') + return False + else: + self.Logger.LogMessage('Connected') + status = wlan.ifconfig() + self.Logger.LogMessage('ip = ' + status[0]) + return True + + # Blinkfunktion der Onboard-LED für Errorcodes + def BlinkOnboardLED(self, num_blinks): + global led + for i in range(num_blinks): + led.on() + time.sleep(.2) + led.off() + time.sleep(.2) + + def GetMACAddress(self): + return ubinascii.hexlify(network.WLAN().config('mac'),':').decode() + + def GetIPAddress(self): + global wlan + return wlan.ifconfig()[0] + + def IsWifiConnected(self): + global wlan + if wlan.status() == 3: + return "W" + else: + return " " \ No newline at end of file diff --git a/TimeUtils.py b/TimeUtils.py new file mode 100644 index 0000000..f8a6f66 --- /dev/null +++ b/TimeUtils.py @@ -0,0 +1,16 @@ +import utime as time + +class TimeUtils(): + def __init__(self): + pass + + def DateTimeNow(self): + tm = time.gmtime() + return "%02d.%02d.%04d,%02d:%02d" % (tm[2], tm[1], tm[0], tm[3], tm[4]) + + def IsOlderThanDays(self, date, days): + fdate = time.mktime((int(date[0]), int(date[1]), int(date[2]), 0, 0, 0, 0, 0)) + if (fdate + (int(days) * 86400) <= time.time()): + return True + else: + return False \ No newline at end of file