1
0
Fork 0

main.py aktualisiert

This commit is contained in:
Manuel Kamper 2024-04-16 18:29:19 +02:00
parent c70beab5f4
commit 3dbda1a293
1 changed files with 404 additions and 404 deletions

808
main.py
View File

@ -1,405 +1,405 @@
import rp2, re, os import rp2, re, os
import TimeUtils, Logger, Networking, NTP, OTA import TimeUtils, Logger, Networking, NTP, OTA
import uasyncio as asyncio import uasyncio as asyncio
import utime as time import utime as time
import usocket as socket import usocket as socket
from machine import ADC, Pin, Timer from machine import ADC, Pin, Timer
from secrets import secrets from secrets import secrets
from configs import configs from configs import configs
rp2.country(configs['country']) rp2.country(configs['country'])
version = "0.8" version = "0.9"
TimeUtils = TimeUtils.TimeUtils() TimeUtils = TimeUtils.TimeUtils()
Logger = Logger.Logger(configs['log_housekeeping_days']) Logger = Logger.Logger(configs['log_housekeeping_days'])
Networking = Networking.Networking(Logger, secrets['ssid'], secrets['pw']) Networking = Networking.Networking(Logger, secrets['ssid'], secrets['pw'])
NTP = NTP.NTP(Logger) NTP = NTP.NTP(Logger)
ota_host = configs['ota_host'] ota_host = configs['ota_host']
project_name = "watering" project_name = "watering"
filenames = ["configs.py", "Logger.py", "main.py", "Networking.py", "NTP.py", "OTA.py", "secrets.py", "TimeUtils.py"] filenames = ["configs.py", "Logger.py", "main.py", "Networking.py", "NTP.py", "OTA.py", "secrets.py", "TimeUtils.py"]
boottime = time.time() boottime = time.time()
pumpRelais = Pin(15, Pin.OUT, value=0) #gpio15 pumpRelais = Pin(15, Pin.OUT, value=0) #gpio15
heartbeatLed = Pin(0, Pin.OUT, value=0) #gpio0 heartbeatLed = Pin(0, Pin.OUT, value=0) #gpio0
wifiLed = Pin(1, Pin.OUT, value=0) #gpio1 wifiLed = Pin(1, Pin.OUT, value=0) #gpio1
autoLed = Pin(2, Pin.OUT, value=0) #gpio2 autoLed = Pin(2, Pin.OUT, value=0) #gpio2
pumpLed = Pin(3, Pin.OUT, value=0) #gpio3 pumpLed = Pin(3, Pin.OUT, value=0) #gpio3
tempSensor = ADC(4) #internal temperature sensor tempSensor = ADC(4) #internal temperature sensor
soilSensor1 = ADC(0) #gpio26 soilSensor1 = ADC(0) #gpio26
soilSensor2 = ADC(1) #gpio27 soilSensor2 = ADC(1) #gpio27
soilSensor3 = ADC(2) #gpio28 soilSensor3 = ADC(2) #gpio28
waterLevelSensor = Pin(5, Pin.IN, Pin.PULL_UP) #gpio5 waterLevelSensor = Pin(5, Pin.IN, Pin.PULL_UP) #gpio5
pumpState = False pumpState = False
autoState = False autoState = False
soilDry = False soilDry = False
waterLevel = False waterLevel = False
wateringPulseState = False wateringPulseState = False
temperature = 0.0 temperature = 0.0
lastSoil1 = 0 lastSoil1 = 0
lastSoil2 = 0 lastSoil2 = 0
lastSoil3 = 0 lastSoil3 = 0
lastWateringPulse = 0 lastWateringPulse = 0
# Checks if string is integer # Checks if string is integer
def IsInt(possibleint): def IsInt(possibleint):
try: try:
int(possibleint) int(possibleint)
except: except:
return False return False
else: else:
return True return True
# Reboots the Pico W (f.e. in case of an error) # Reboots the Pico W (f.e. in case of an error)
def Reboot(): def Reboot():
Logger.LogMessage("Performing Reboot") Logger.LogMessage("Performing Reboot")
machine.reset() machine.reset()
# Calculates the uptime in hours and minutes # Calculates the uptime in hours and minutes
def Uptime(): def Uptime():
global boottime global boottime
seconds = (time.time() - boottime) % (24 * 3600) seconds = (time.time() - boottime) % (24 * 3600)
hours = seconds // 3600 hours = seconds // 3600
seconds %= 3600 seconds %= 3600
minutes = seconds // 60 minutes = seconds // 60
seconds %= 60 seconds %= 60
return "%d:%02d" % (hours, minutes) return "%d:%02d" % (hours, minutes)
# Turns on the watering pump # Turns on the watering pump
def WateringOn(): def WateringOn():
global pumpState, waterLevel global pumpState, waterLevel
if (waterLevel): if (waterLevel):
pumpRelais.on() pumpRelais.on()
pumpLed.on() pumpLed.on()
pumpState = True pumpState = True
Logger.LogMessage("Pump turned on") Logger.LogMessage("Pump turned on")
else: else:
pumpRelais.off() pumpRelais.off()
pumpLed.off() pumpLed.off()
pumpState = False pumpState = False
Logger.LogMessage("Could not turn on the pump - water level low!") Logger.LogMessage("Could not turn on the pump - water level low!")
# Turns off the watering pump # Turns off the watering pump
def WateringOff(value = ""): def WateringOff(value = ""):
global pumpState, wateringPulseState global pumpState, wateringPulseState
pumpRelais.off() pumpRelais.off()
pumpLed.off() pumpLed.off()
pumpState = False pumpState = False
wateringPulseState = False wateringPulseState = False
Logger.LogMessage("Pump turned off") Logger.LogMessage("Pump turned off")
# Returns the state of the watering pump # Returns the state of the watering pump
def WateringState(): def WateringState():
global pumpState global pumpState
if (pumpState): if (pumpState):
return "on" return "on"
else: else:
return "off" return "off"
# Reads the onboard temperature sensor's value # Reads the onboard temperature sensor's value
def ReadTemp(): def ReadTemp():
global temperature global temperature
temperature = 27 - ((tempSensor.read_u16() * (3.3 / (65535))) - 0.706) / 0.001721 temperature = 27 - ((tempSensor.read_u16() * (3.3 / (65535))) - 0.706) / 0.001721
# Turns on the automatic watering mode and writes file to set automode on reboot # Turns on the automatic watering mode and writes file to set automode on reboot
def AutoModeOn(): def AutoModeOn():
global autoState global autoState
if not "auto" in os.listdir(): if not "auto" in os.listdir():
file = open("auto","w") file = open("auto","w")
file.write("auto") file.write("auto")
file.close() file.close()
autoLed.on() autoLed.on()
autoState = True autoState = True
Logger.LogMessage("Automatic mode turned on") Logger.LogMessage("Automatic mode turned on")
# Turns off the automatic watering mode and removes file for automode on reboot # Turns off the automatic watering mode and removes file for automode on reboot
def AutoModeOff(): def AutoModeOff():
global autoState global autoState
if "auto" in os.listdir(): if "auto" in os.listdir():
os.remove("auto") os.remove("auto")
autoLed.off() autoLed.off()
autoState = False autoState = False
Logger.LogMessage("Automatic mode turned off") Logger.LogMessage("Automatic mode turned off")
# Returns the state of the automatic watering mode # Returns the state of the automatic watering mode
def AutoModeState(): def AutoModeState():
global autoState global autoState
if (autoState): if (autoState):
return "on" return "on"
else: else:
return "off" return "off"
# Turns on the watering pump for pulse_duration seconds and turns it off after that # Turns on the watering pump for pulse_duration seconds and turns it off after that
def WateringPulse(): def WateringPulse():
global waterLevel, wateringPulseState, lastWateringPulse global waterLevel, wateringPulseState, lastWateringPulse
if (waterLevel): if (waterLevel):
WateringOn() WateringOn()
lastWateringPulse = time.time() lastWateringPulse = time.time()
wateringPulseState = True wateringPulseState = True
timer3 = Timer(period=(1000 * configs["pulse_duration"]), mode=Timer.ONE_SHOT, callback=WateringOff) timer3 = Timer(period=(1000 * configs["pulse_duration"]), mode=Timer.ONE_SHOT, callback=WateringOff)
Logger.LogMessage("Triggered watering pulse") Logger.LogMessage("Triggered watering pulse")
else: else:
Logger.LogMessage("Could not trigger watering pulse - Water level low!") Logger.LogMessage("Could not trigger watering pulse - Water level low!")
# Reads the soil moisture sensors and triggers watering pulse if automatic mode is enabled # Reads the soil moisture sensors and triggers watering pulse if automatic mode is enabled
def ReadSoil(): def ReadSoil():
global soilDry, autoState, lastSoil1, lastSoil2, lastSoil3 global soilDry, autoState, lastSoil1, lastSoil2, lastSoil3
read1 = soilSensor1.read_u16() read1 = soilSensor1.read_u16()
read2 = soilSensor2.read_u16() read2 = soilSensor2.read_u16()
read3 = soilSensor3.read_u16() read3 = soilSensor3.read_u16()
Logger.LogSoil(str(read1) + "," + str(read2) + "," + str(read3) + ",") Logger.LogSoil(str(read1) + "," + str(read2) + "," + str(read3) + ",")
lastSoil1 = read1 lastSoil1 = read1
lastSoil2 = read2 lastSoil2 = read2
lastSoil3 = read3 lastSoil3 = read3
# eliminate false readings # eliminate false readings
if (lastSoil1 > 25000): if (lastSoil1 > 25000):
lastSoil1 = 100 lastSoil1 = configs["soil_dry_value"]
if (lastSoil2 > 25000): if (lastSoil2 > 25000):
lastSoil2 = 100 lastSoil2 = configs["soil_dry_value"]
if (lastSoil3 > 25000): if (lastSoil3 > 25000):
lastSoil3 = 100 lastSoil3 = configs["soil_dry_value"]
if ((read1 + read2 + read3) / 3 <= configs["soil_dry_value"]): if ((lastSoil1 + lastSoil2 + lastSoil3) / 3 <= configs["soil_dry_value"]):
soilDry = False soilDry = False
Logger.LogMessage("Soil is wet") Logger.LogMessage("Soil is wet")
else: else:
soilDry = True soilDry = True
Logger.LogMessage("Soil is dry!") Logger.LogMessage("Soil is dry!")
if (autoState): if (autoState):
Logger.LogMessage("Triggering watering pulse due to automatic mode") Logger.LogMessage("Triggering watering pulse due to automatic mode")
WateringPulse() WateringPulse()
# Returns if soil is dry or wet # Returns if soil is dry or wet
def SoilState(): def SoilState():
global soilDry global soilDry
if (soilDry): if (soilDry):
return "dry" return "dry"
else: else:
return "wet" return "wet"
# Returns the water level state # Returns the water level state
def WaterLevelState(): def WaterLevelState():
global waterLevel, pumpState global waterLevel, pumpState
if (waterLevel): if (waterLevel):
return "full" return "full"
else: else:
return "empty" return "empty"
# Reads the water level sensor # Reads the water level sensor
def ReadWaterLevel(): def ReadWaterLevel():
global waterLevel global waterLevel
if (waterLevelSensor.value() == 0): if (waterLevelSensor.value() == 0):
waterLevel = True waterLevel = True
else: else:
waterLevel = False waterLevel = False
if (pumpState): if (pumpState):
Logger.LogMessage("Water level low - protecting the pump") Logger.LogMessage("Water level low - protecting the pump")
WateringOff() WateringOff()
# This function makes sure, the watering pulse got turned off by the timer (can happen that it fails) # This function makes sure, the watering pulse got turned off by the timer (can happen that it fails)
def CheckWateringPulseOff(): def CheckWateringPulseOff():
global pumpState, lastWateringPulse global pumpState, lastWateringPulse
if (pumpState): if (pumpState):
if (lastWateringPulse + 1 + configs["pulse_duration"] <= time.time()): if (lastWateringPulse + 1 + configs["pulse_duration"] <= time.time()):
Logger.LogMessage("Turning watering pump off, because pulse timer failed to do so") Logger.LogMessage("Turning watering pump off, because pulse timer failed to do so")
WateringOff() WateringOff()
##################################################################### #####################################################################
# Helper-method to allow error handling and output in asyncio # Helper-method to allow error handling and output in asyncio
def set_global_exception(): def set_global_exception():
def handle_exception(loop, context): def handle_exception(loop, context):
Logger.LogMessage("Fatal error: " + str(context["exception"])) Logger.LogMessage("Fatal error: " + str(context["exception"]))
import sys import sys
sys.print_exception(context["exception"]) sys.print_exception(context["exception"])
sys.exit() sys.exit()
Reboot() Reboot()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
loop.set_exception_handler(handle_exception) loop.set_exception_handler(handle_exception)
# Main method for all the Watering-handling # Main method for all the Watering-handling
async def WateringHandling(): async def WateringHandling():
Logger.LogMessage("Watering handling started") Logger.LogMessage("Watering handling started")
while True: while True:
ReadTemp() ReadTemp()
ReadWaterLevel() ReadWaterLevel()
CheckWateringPulseOff() CheckWateringPulseOff()
#todo any super cool action here #todo any super cool action here
heartbeatLed.toggle() heartbeatLed.toggle()
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
# Main method for the API # Main method for the API
html = """<!DOCTYPE html> html = """<!DOCTYPE html>
<html> <html>
<head> <title>Bew&auml;sserung</title> </head> <head> <title>Bew&auml;sserung</title> </head>
<body> <h1>Bew&auml;sserung</h1> <body> <h1>Bew&auml;sserung</h1>
<p>%s</p> <p>%s</p>
</body> </body>
</html>""" </html>"""
json = """{ "Watering": { "%s" } }""" json = """{ "Watering": { "%s" } }"""
async def APIHandling(reader, writer): async def APIHandling(reader, writer):
request_line = await reader.readline() request_line = await reader.readline()
while await reader.readline() != b"\r\n": while await reader.readline() != b"\r\n":
pass pass
request = str(request_line) request = str(request_line)
try: try:
request = request.split()[1] request = request.split()[1]
except IndexError: except IndexError:
pass pass
client_ip = writer.get_extra_info('peername')[0] client_ip = writer.get_extra_info('peername')[0]
if request != "/favicon.ico": if request != "/favicon.ico":
Logger.LogMessage("API request: " + request + " - from client IP: " + client_ip) Logger.LogMessage("API request: " + request + " - from client IP: " + client_ip)
if (configs['api_client_ip'] != "") and (configs['api_client_ip'] != client_ip): if (configs['api_client_ip'] != "") and (configs['api_client_ip'] != client_ip):
Logger.LogMessage("Unauthorized client! Aborting API Handling now.") Logger.LogMessage("Unauthorized client! Aborting API Handling now.")
stateis = "<b>Error 401:</b> Client '" + client_ip + "' is not authorized to use the API!<br><br>Set authorized client IP in configs.py!" stateis = "<b>Error 401:</b> Client '" + client_ip + "' is not authorized to use the API!<br><br>Set authorized client IP in configs.py!"
response = html % stateis response = html % stateis
writer.write('HTTP/1.0 401 Unauthorized\r\nContent-type: text/html\r\n\r\n') writer.write('HTTP/1.0 401 Unauthorized\r\nContent-type: text/html\r\n\r\n')
else: else:
req = request.split('/') req = request.split('/')
stateis = "" stateis = ""
if (len(req) == 3 or len(req) == 4 or len(req) == 5): if (len(req) == 3 or len(req) == 4 or len(req) == 5):
if (req[1] == secrets['api']): if (req[1] == secrets['api']):
if (req[2] == "wateron"): if (req[2] == "wateron"):
Logger.LogMessage("Watering turned on") Logger.LogMessage("Watering turned on")
stateis = "Watering turned: on" stateis = "Watering turned: on"
WateringOn() WateringOn()
elif (req[2] == "wateroff"): elif (req[2] == "wateroff"):
Logger.LogMessage("Watering turned off") Logger.LogMessage("Watering turned off")
stateis = "Watering turned: off" stateis = "Watering turned: off"
WateringOff() WateringOff()
elif (req[2] == "waterstate"): elif (req[2] == "waterstate"):
Logger.LogMessage("Watering is turned " + WateringState()) Logger.LogMessage("Watering is turned " + WateringState())
stateis = "Watering is turned: " + WateringState() stateis = "Watering is turned: " + WateringState()
elif (req[2] == "waterpulse"): elif (req[2] == "waterpulse"):
Logger.LogMessage("Watering Pulse activated") Logger.LogMessage("Watering Pulse activated")
stateis = "Watering Pulse: activated" stateis = "Watering Pulse: activated"
WateringPulse() WateringPulse()
elif (req[2] == "autoon"): elif (req[2] == "autoon"):
Logger.LogMessage("Automatic-Mode turned on") Logger.LogMessage("Automatic-Mode turned on")
stateis = "Automatic-Mode turned: on" stateis = "Automatic-Mode turned: on"
AutoModeOn() AutoModeOn()
elif (req[2] == "autooff"): elif (req[2] == "autooff"):
Logger.LogMessage("Automatic-Mode turned off") Logger.LogMessage("Automatic-Mode turned off")
stateis = "Automatic-Mode turned: off" stateis = "Automatic-Mode turned: off"
AutoModeOff() AutoModeOff()
elif (req[2] == "autostate"): elif (req[2] == "autostate"):
Logger.LogMessage("Automatic-Mode is turned " + AutoModeState()) Logger.LogMessage("Automatic-Mode is turned " + AutoModeState())
stateis = "Automatic-Mode is turned: " + AutoModeState() stateis = "Automatic-Mode is turned: " + AutoModeState()
elif (req[2] == "forcesoilread"): elif (req[2] == "forcesoilread"):
ReadSoil() ReadSoil()
Logger.LogMessage("Forced Soil Measurement Readings: " + str(lastSoil1) + ", " + str(lastSoil2) + ", " + str(lastSoil3)) Logger.LogMessage("Forced Soil Measurement Readings: " + str(lastSoil1) + ", " + str(lastSoil2) + ", " + str(lastSoil3))
stateis = "Forced Soil Measurement Readings: now<br>soil1: " + str(lastSoil1) + "<br>soil2: " + str(lastSoil2) + "<br>soil3: " + str(lastSoil3) stateis = "Forced Soil Measurement Readings: now<br>soil1: " + str(lastSoil1) + "<br>soil2: " + str(lastSoil2) + "<br>soil3: " + str(lastSoil3)
elif (req[2] == "waterlevel"): elif (req[2] == "waterlevel"):
Logger.LogMessage("Water level is: " + WaterLevelState()) Logger.LogMessage("Water level is: " + WaterLevelState())
stateis = "Water level is: " + WaterLevelState() stateis = "Water level is: " + WaterLevelState()
elif (req[2] == "ping"): elif (req[2] == "ping"):
stateis = "ping: OK" stateis = "ping: OK"
elif (req[2] == "stats"): elif (req[2] == "stats"):
stateis = "IP address: " + Networking.GetIPAddress() + "<br>MAC address: " + Networking.GetMACAddress() + "<br>Hostname: " + configs['hostname'] + "<br>API Port: " + str(configs['api_port']) + "<br>Uptime (h:m): " + Uptime() + "<br>Date/Time: " + TimeUtils.DateTimeNow() + "<br>Version: " + version + "<br>GMT Timezone Offset (hours): " + str(configs['gmt_offset']) + "<br>Auto summertime: " + str(configs['auto_summertime']) + "<br>Housekeep logfiles after days: " + str(configs['log_housekeeping_days']) + "<br>CPU frequency (MHz): " + str(machine.freq()/1000000) + "<br>Temperature (&#176;C): " + "%.2f" % temperature + "<br>Pulse duration (seconds): " + str(configs["pulse_duration"]) + "<br>Soil moisture measurement interval (minutes): " + str(configs["soil_moisture_measure_interval"]) + "<br>Soil is: " + SoilState() + "<br>Soil moisture 1: " + str(lastSoil1) + "<br>Soil moisture 2: " + str(lastSoil2) + "<br>Soil moisture 3: " + str(lastSoil3) + "<br>Automatic watering Mode: " + AutoModeState() + "<br>Water level status: " + WaterLevelState() + "<br>Check for updates (minutes): " + str(configs["check_for_update"]) stateis = "IP address: " + Networking.GetIPAddress() + "<br>MAC address: " + Networking.GetMACAddress() + "<br>Hostname: " + configs['hostname'] + "<br>API Port: " + str(configs['api_port']) + "<br>Uptime (h:m): " + Uptime() + "<br>Date/Time: " + TimeUtils.DateTimeNow() + "<br>Version: " + version + "<br>GMT Timezone Offset (hours): " + str(configs['gmt_offset']) + "<br>Auto summertime: " + str(configs['auto_summertime']) + "<br>Housekeep logfiles after days: " + str(configs['log_housekeeping_days']) + "<br>CPU frequency (MHz): " + str(machine.freq()/1000000) + "<br>Temperature (&#176;C): " + "%.2f" % temperature + "<br>Pulse duration (seconds): " + str(configs["pulse_duration"]) + "<br>Soil moisture measurement interval (minutes): " + str(configs["soil_moisture_measure_interval"]) + "<br>Soil is: " + SoilState() + "<br>Soil moisture 1: " + str(lastSoil1) + "<br>Soil moisture 2: " + str(lastSoil2) + "<br>Soil moisture 3: " + str(lastSoil3) + "<br>Automatic watering Mode: " + AutoModeState() + "<br>Water level status: " + WaterLevelState() + "<br>Check for updates (minutes): " + str(configs["check_for_update"])
elif (req[2] == "reboot"): elif (req[2] == "reboot"):
stateis = "Rebooting device: now..." stateis = "Rebooting device: now..."
Reboot() Reboot()
elif (req[2] == "logs"): elif (req[2] == "logs"):
if (len(req) >= 4 and req[3] != "json"): if (len(req) >= 4 and req[3] != "json"):
if (IsInt(req[3])): if (IsInt(req[3])):
stateis = Logger.LastLogs(int(req[3])) stateis = Logger.LastLogs(int(req[3]))
else: else:
stateis = "<b>Error:</b> Parameter for log length not an integer!" stateis = "<b>Error:</b> Parameter for log length not an integer!"
else: else:
stateis = Logger.LastLogs(10) stateis = Logger.LastLogs(10)
elif (req[2] == "soils"): elif (req[2] == "soils"):
if (len(req) >= 4 and req[3] != "json"): if (len(req) >= 4 and req[3] != "json"):
if (IsInt(req[3])): if (IsInt(req[3])):
stateis = Logger.LastSoils(int(req[3])) stateis = Logger.LastSoils(int(req[3]))
else: else:
stateis = "<b>Error:</b> Parameter for soil length not an integer!" stateis = "<b>Error:</b> Parameter for soil length not an integer!"
else: else:
stateis = Logger.LastSoils(6) stateis = Logger.LastSoils(6)
else: else:
stateis = "<b>Error:</b> Unknown command!" stateis = "<b>Error:</b> Unknown command!"
else: else:
stateis = "<b>Error:</b> API key is invalid!" stateis = "<b>Error:</b> API key is invalid!"
if ((len(req) == 4 and req[3] == "json") or (len(req) == 5 and req[4] == "json")): if ((len(req) == 4 and req[3] == "json") or (len(req) == 5 and req[4] == "json")):
if (req[2] != "logs" and req[2] != "soils"): if (req[2] != "logs" and req[2] != "soils"):
stateis = stateis.replace(": ", "\":\"") stateis = stateis.replace(": ", "\":\"")
stateis = stateis.replace("<br>", "\", \"") stateis = stateis.replace("<br>", "\", \"")
stateis = stateis.replace("&#176;", "°") stateis = stateis.replace("&#176;", "°")
else: else:
stateis = stateis.replace(";", "\":\"") stateis = stateis.replace(";", "\":\"")
stateis = stateis.replace("<br>", "\", \"") stateis = stateis.replace("<br>", "\", \"")
stateis = stateis.replace("\n", "").replace("\r", "") stateis = stateis.replace("\n", "").replace("\r", "")
response = json % stateis response = json % stateis
writer.write('HTTP/1.0 200 OK\r\nContent-type: text/json\r\n\r\n') writer.write('HTTP/1.0 200 OK\r\nContent-type: text/json\r\n\r\n')
else: else:
response = html % stateis response = html % stateis
writer.write('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') writer.write('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
else: else:
stateis = "<b>Error 400:</b> Invalid usage of API!<br><br><u>Usage:</u> http://servername/api_key/command[/json]<br><br><u>Commands:</u><ul><li>wateron</li><li>wateroff</li><li>waterstate</li><li>waterpulse</li><li>autoon</li><li>autooff</li><li>autostate</li><li>waterlevel</li><li>ping</li><li>stats</li><li>reboot</li><li>logs</li><li>soils</li></ul><br><u>API Key:</u> set 'api' in secrets.py file." stateis = "<b>Error 400:</b> Invalid usage of API!<br><br><u>Usage:</u> http://servername/api_key/command[/json]<br><br><u>Commands:</u><ul><li>wateron</li><li>wateroff</li><li>waterstate</li><li>waterpulse</li><li>autoon</li><li>autooff</li><li>autostate</li><li>waterlevel</li><li>ping</li><li>stats</li><li>reboot</li><li>logs</li><li>soils</li></ul><br><u>API Key:</u> set 'api' in secrets.py file."
response = html % stateis response = html % stateis
writer.write('HTTP/1.0 400 Bad Request\r\nContent-type: text/html\r\n\r\n') writer.write('HTTP/1.0 400 Bad Request\r\nContent-type: text/html\r\n\r\n')
writer.write(response) writer.write(response)
await writer.drain() await writer.drain()
await writer.wait_closed() await writer.wait_closed()
# Main method for daily housekeeping # Main method for daily housekeeping
async def Housekeeper(): async def Housekeeper():
Logger.LogMessage("Housekeeper started") Logger.LogMessage("Housekeeper started")
while True: while True:
Logger.LogMessage("Housekeeper is performing actions") Logger.LogMessage("Housekeeper is performing actions")
Logger.Housekeeping() Logger.Housekeeping()
Logger.LogMessage("Housekeeper is performing NTP sync") Logger.LogMessage("Housekeeper is performing NTP sync")
NTP.SetRTCTimeFromNTP(configs['ntp_host'], configs['gmt_offset'], configs['auto_summertime']) NTP.SetRTCTimeFromNTP(configs['ntp_host'], configs['gmt_offset'], configs['auto_summertime'])
Logger.LogMessage("Housekeeper has finished its jobs") Logger.LogMessage("Housekeeper has finished its jobs")
await asyncio.sleep(86400) await asyncio.sleep(86400)
# Main entry point after booting # Main entry point after booting
async def Main(): async def Main():
global autoState global autoState
set_global_exception() set_global_exception()
Logger.LogMessage("Entering MainLoop") Logger.LogMessage("Entering MainLoop")
boottime = time.time() boottime = time.time()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
Logger.LogMessage("Setting up API on port " + str(configs['api_port']) + " with key " + secrets['api']) Logger.LogMessage("Setting up API on port " + str(configs['api_port']) + " with key " + secrets['api'])
loop.create_task(asyncio.start_server(APIHandling, Networking.GetIPAddress(), configs['api_port'])) loop.create_task(asyncio.start_server(APIHandling, Networking.GetIPAddress(), configs['api_port']))
Logger.LogMessage("API started") Logger.LogMessage("API started")
Logger.LogMessage("Booting complete with Firmware " + version) Logger.LogMessage("Booting complete with Firmware " + version)
ReadSoil() ReadSoil()
timer = Timer(period=(1000 * 60 * configs["soil_moisture_measure_interval"]), mode=Timer.PERIODIC, callback=lambda t:ReadSoil()) timer = Timer(period=(1000 * 60 * configs["soil_moisture_measure_interval"]), mode=Timer.PERIODIC, callback=lambda t:ReadSoil())
Logger.LogMessage("Started timer for soil moisture measurement every " + str(configs["soil_moisture_measure_interval"]) + " minutes") Logger.LogMessage("Started timer for soil moisture measurement every " + str(configs["soil_moisture_measure_interval"]) + " minutes")
if "auto" in os.listdir(): if "auto" in os.listdir():
autoState = True autoState = True
autoLed.on() autoLed.on()
Logger.LogMessage("Turned Automatic mode on from previous state") Logger.LogMessage("Turned Automatic mode on from previous state")
loop.create_task(WateringHandling()) loop.create_task(WateringHandling())
loop.create_task(Housekeeper()) loop.create_task(Housekeeper())
loop.run_forever() loop.run_forever()
# Booting the device # Booting the device
def Boot(): def Boot():
Networking.Connect(configs['disable_wifi_powersavingmode']) Networking.Connect(configs['disable_wifi_powersavingmode'])
if (Networking.Status()): if (Networking.Status()):
wifiLed.on() wifiLed.on()
if (NTP.SetRTCTimeFromNTP(configs['ntp_host'], configs['gmt_offset'], configs['auto_summertime'])): if (NTP.SetRTCTimeFromNTP(configs['ntp_host'], configs['gmt_offset'], configs['auto_summertime'])):
Logger.DisableTempLogfile() Logger.DisableTempLogfile()
Logger.DisableTempSoilfile() Logger.DisableTempSoilfile()
if (ota_host != ""): if (ota_host != ""):
OTA.ota_update(ota_host, project_name, filenames, use_version_prefix=False, hard_reset_device=True, soft_reset_device=False, timeout=5) OTA.ota_update(ota_host, project_name, filenames, use_version_prefix=False, hard_reset_device=True, soft_reset_device=False, timeout=5)
timer2 = Timer(period=(1000 * 60 * configs["check_for_update"]), mode=Timer.PERIODIC, callback=lambda t:OTA.check_for_ota_update(ota_host, project_name, soft_reset_device=False, timeout=5)) timer2 = Timer(period=(1000 * 60 * configs["check_for_update"]), mode=Timer.PERIODIC, callback=lambda t:OTA.check_for_ota_update(ota_host, project_name, soft_reset_device=False, timeout=5))
else: else:
wifiLed.off() wifiLed.off()
time.sleep(3) time.sleep(3)
Reboot() Reboot()
##################################################################### #####################################################################
Boot() Boot()
try: try:
asyncio.run(Main()) asyncio.run(Main())
except KeyboardInterrupt: except KeyboardInterrupt:
Logger.LogMessage("Shutdown.") Logger.LogMessage("Shutdown.")
pumpRelais.off() pumpRelais.off()
pumpLed.off() pumpLed.off()
autoLed.off() autoLed.off()
heartbeatLed.off() heartbeatLed.off()
wifiLed.off() wifiLed.off()
finally: finally:
asyncio.new_event_loop() asyncio.new_event_loop()