import time
import ujson
import network
import json
import _thread
from time import sleep
from pump import PUMP
from environment_sensor import ENVIRONMENT_SENSOR
from cistern import CISTERN
from machine import Pin, PWM,
from oled import OLED
from ldr import LDR
from fan import FAN
from ground_sensor import GROUND_SENSOR
from mqtt_client import MQTT
#from umqtt.simple import MQTTClient
"""PARAMETERS DEFINITION"""
# MQTT Server parameters
MQTT_CLIENT_ID = "gruppo09"
MQTT_BROKER = "test.mosquitto.org"
MQTT_USER = ""
MQTT_PASSWORD = ""
#MQTT topic to witch the client must publish informations
MQTT_GROUND_HUMIDITY = "SmartGreenhouse/Ground/Humidity"
MQTT_ENVIRONMENT_TEMP = "SmartGreenhouse/Environment/Temp"
MQTT_ENVIRONMENT_HUMIDITY = "SmartGreenhouse/Environment/Humidity"
MQTT_CISTERN_LEVEL = "SmartGreenhouse/Irrigation/Cistern"
MQTT_OUTSIDE_LUX = "SmartGreenhouse/External/Lum"
MQTT_FAN_SPEED = "SmartGreenhouse/Ventilation/Fan"
MQTT_PUMP_STATE = "SmartGreenhouse/Irrigation/Pump"
#List of the keys of Json object to public
KEYS = ["humidity", "temp", "humidity", "cistern_level", "light", "fan", "pump"]
#MQTT topic to which the client must subscribe
MQTT_SUBSCRIBE_TOPIC = {
"MQTT_IRRIGATION_MANUALCONTROL" : b'SmartGreenhouse/Irrigation/ManualState',
"MQTT_IRRIGATION_MANUALPUMP" : b'SmartGreenhouse/Irrigation/ManualPump',
"MQTT_IRRIGATION_HUMIDITY" : b'SmartGreenhouse/Irrigation/Humidity',
"MQTT_FAN_MANUALSPEED" : b'SmartGreenhouse/Ventilation/ManualFan',
"MQTT_FAN_MANUALCONTROL" : b'SmartGreenhouse/Ventilation/ManualState',
"MQTT_FAN_ACTIVATIONTEMP" : b'SmartGreenhouse/Ventilation/Temp',
"MQTT_RESET_SYSTEM" : b'SmartGreenhouse/Restart'
}
#dict of value that comes from the sensors to publish on the respective topic: k = topic, v = value to publish on the topic
MQTT_PUBLISH_VALUE = {
MQTT_GROUND_HUMIDITY : None,
MQTT_ENVIRONMENT_TEMP : None,
MQTT_ENVIRONMENT_HUMIDITY : None,
MQTT_CISTERN_LEVEL: None,
MQTT_OUTSIDE_LUX : None,
MQTT_FAN_SPEED : None,
MQTT_PUMP_STATE : None
}
SENSORS_ACTUAL_VALUE = {
MQTT_GROUND_HUMIDITY : None,
MQTT_ENVIRONMENT_TEMP : None,
MQTT_ENVIRONMENT_HUMIDITY : None,
MQTT_CISTERN_LEVEL: None,
MQTT_OUTSIDE_LUX : None,
}
#dict of parameter that are setted based on the informations that comes from the broker and from the system computation
SYSTEM_PARAMS = {
"CRITICAL_CISTERN_LEVEL" : 10,
"HUMIDITY_CRITICAL_LEVEL" : 10,
"MANUAL_IRRIGATION_CONTROL" : False,
"MANUAL_IRRIGATION_PUMP": False,
"MANUAL_FAN_SPEED" : 0,
"MANUAL_FAN_CONTROL" : False,
"BLOCK_IRRIGATION_FOR_CRITICAL_CISTERN_LEVEL": False,
"RESTART_SYSTEM": False,
"FAN_ACTIVATION_TEMP": 30,
"PUMP_CICLE": False
}
#CISTERN parameters
CISTERN_TRIGGER_PIN = 26
CISTERN_ECHO_PIN = 25
CISTERN_HEIGHT = 30
#PUMP parameters
PUMP_PIN = 27
#ENVIRONMENT_SENSOR parameters
ENVIRONMENT_SENSOR_PIN = 4
#PHOTO_RESISTOR parameters
PHOTO_RESISTOR_PIN = 35
PHOTO_RESISTOR_MIN_VALUE = 0
PHOTO_RESISTOR_MAX_VALUE = 100
#LED_ZONE_1 parameters
LED_ZONE_1_PIN = 13
LED_ZONE_1_FREQ = 50
#FAN parameters
FAN_PIN = 14
FAN_MIN_SPEED = 0
FAN_MAX_SPEED = 80
FAN_MAX_SPEED_DASHBOARD = 100
FAN_FREQ_VALUE = 50
#GROUND_SENSOR parameters
GROUND_SENSOR_PIN = 33
GROUND_SENSOR_MAX_READ = 2093
GROUND_SENSOR_MIN_READ = 462
GROUND_SENSOR_MIN_VALUE = 0
GROUND_SENSOR_MAX_VALUE = 100
#OLED_DISPLAY parameters
OLED_WIDTH = 128
OLED_HEIGHT = 64
OLED_SLC_PIN = 22
OLED_SDA_PIN = 32
#RESET_BTN parameters
RESET_BTN_PIN = 15
#BOUNCING BTN VAR
LAST = 0
"""IMPLEMENTATION OF SYSTEM LOGIC"""
#INSTANTIATION OF THE SYSTEM OBJECTS
reset_btn = Pin(RESET_BTN_PIN, Pin.IN, Pin.PULL_DOWN)
cistern = CISTERN(CISTERN_TRIGGER_PIN, CISTERN_ECHO_PIN, CISTERN_HEIGHT)
pump = PUMP(PUMP_PIN)
environment_sensor = ENVIRONMENT_SENSOR(ENVIRONMENT_SENSOR_PIN)
photo_resistor = LDR(PHOTO_RESISTOR_PIN, PHOTO_RESISTOR_MIN_VALUE, PHOTO_RESISTOR_MAX_VALUE)
ground_sensor = GROUND_SENSOR(GROUND_SENSOR_PIN, GROUND_SENSOR_MIN_VALUE, GROUND_SENSOR_MAX_VALUE, GROUND_SENSOR_MAX_READ, GROUND_SENSOR_MIN_READ)
client = MQTT(MQTT_CLIENT_ID, MQTT_BROKER)
oled = OLED(OLED_WIDTH, OLED_HEIGHT, OLED_SLC_PIN, OLED_SDA_PIN)
fan = FAN(FAN_PIN, FAN_FREQ_VALUE, FAN_MAX_SPEED, FAN_MIN_SPEED)
led_zone_1 = PWM(Pin(LED_ZONE_1_PIN, Pin.OUT), freq=LED_ZONE_1_FREQ)
led_zone_1.duty(0)
#START THE CONNECTIVITY PROCEDURE
oled.print_booting_info()
#IMPORTED IN THE BOOT FILE
try:
shift_point = 0
print("Connecting to WiFi", end="")
oled.print_line("Connecting", 0, 1, 1)
oled.print_line_no_fill("to Wifi", 0, 10, 1)
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('Wokwi-GUEST', '')
while not sta_if.isconnected():
print(".", end="")
oled.print_line_no_fill(".", 53 + shift_point, 10, 1)
time.sleep(0.1)
shift_point = shift_point + 6
print(" Connected!")
oled.print_line_no_fill("Connected!", 0, 20, 1)
except OSError as ex:
print("Failure connecting to WiFi!!")
oled.print_line_no_fill("Not Connected!", 0, 20, 1)
#DEFINE THE CALLBACK PROCEDURE FOR THE RECIVED MSG FROM THE BROKER
def subCallback(topic, msg):
global SYSTEM_PARAMS, SYSTEM_PARAMS_BACKUP, MQTT_PUBLISH_VALUE_RESET, MQTT_PUBLISH_VALUE
print(topic, msg)
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_RESET_SYSTEM"]:
if msg == b'true':
SYSTEM_PARAMS["RESTART_SYSTEM"] = True
else:
SYSTEM_PARAMS["RESTART_SYSTEM"] = False
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_IRRIGATION_MANUALCONTROL"]:
if msg == b'true':
SYSTEM_PARAMS["MANUAL_IRRIGATION_CONTROL"] = True
elif msg == b'false':
SYSTEM_PARAMS["MANUAL_IRRIGATION_CONTROL"] = False
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_IRRIGATION_MANUALPUMP"]:
if msg == b'true':
SYSTEM_PARAMS["MANUAL_IRRIGATION_PUMP"] = True
elif msg == b'false':
SYSTEM_PARAMS["MANUAL_IRRIGATION_PUMP"] = False
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_IRRIGATION_HUMIDITY"]:
SYSTEM_PARAMS["HUMIDITY_CRITICAL_LEVEL"] = int(msg)
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_FAN_MANUALCONTROL"]:
if msg == b'true':
SYSTEM_PARAMS["MANUAL_FAN_CONTROL"] = True
elif msg == b'false':
SYSTEM_PARAMS["MANUAL_FAN_CONTROL"] = False
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_FAN_MANUALSPEED"]:
SYSTEM_PARAMS["MANUAL_FAN_SPEED"] = int(msg)
if topic == MQTT_SUBSCRIBE_TOPIC["MQTT_FAN_ACTIVATIONTEMP"]:
SYSTEM_PARAMS["FAN_ACTIVATION_TEMP"] = int(msg)
# PROCEDURE OF CONNECTION TO THE MQTT SERVER
print("Connecting to MQTT server", end="")
shift_point = 0
oled.print_line("Connecting to", 0, 1, 1)
oled.print_line_no_fill("MQTT server", 0, 10, 1)
client.connect(MQTT_SUBSCRIBE_TOPIC, subCallback)
while shift_point < 28:
print(".", end="")
oled.print_line_no_fill(".", 85 + shift_point, 10, 1)
time.sleep(0.1)
shift_point = shift_point + 6
if client.get_conn_state():
print(" Connected")
oled.print_line_no_fill("Connected!", 0, 20, 1)
oled.fill_clr()
else:
print("Failure connecting to MQTT server!!")
oled.print_line_no_fill("Not Connected!", 0, 20, 1)
oled.fill_clr()
raise OSException
#UTILITIES FUNCTIONS USED FOR THE TESTS
def print_dict(dic):
for k, v in dic.items():
if v != None:
print(k, ": ", v)
def pump_cicle():
while True:
if SYSTEM_PARAMS["PUMP_CICLE"]:
print(" Pump activated")
pump.pump_cicle(1)
sleep(1)
#MANAGE THE FAN ACTIVATION AND SPEED
def manage_fan():
global SYSTEM_PARAMS, MQTT_PUBLISH_VALUE
if SYSTEM_PARAMS["MANUAL_FAN_CONTROL"]:
oled.print_line_no_fill("Manual Fan: ON", 0, 20, 1)
fan.set_max_speed(FAN_MAX_SPEED_DASHBOARD) #BASED ON THE MAX VALUE OF THE DASHBOARD
if SYSTEM_PARAMS["MANUAL_FAN_SPEED"] != None and isinstance(SYSTEM_PARAMS["MANUAL_FAN_SPEED"], int):
oled.print_line_no_fill("Fan Speed: "+ str(SYSTEM_PARAMS["MANUAL_FAN_SPEED"]), 0, 30, 1)
MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED] = ujson.dumps({"fan" : SYSTEM_PARAMS["MANUAL_FAN_SPEED"]})
fan.set_speed(SYSTEM_PARAMS["MANUAL_FAN_SPEED"])
try:
client.publish(MQTT_FAN_SPEED, MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
else:
oled.print_line_no_fill("Fan Speed: "+ str(SYSTEM_PARAMS["MANUAL_FAN_SPEED"]), 0, 30, 1)
fan.set_speed(0)
MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED] = ujson.dumps({"fan" : SYSTEM_PARAMS["MANUAL_FAN_SPEED"] })
try:
client.publish(MQTT_FAN_SPEED, MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
else:
oled.print_line_no_fill("Manual Fan: OFF", 0, 20, 1)
actual_temp = environment_sensor.get_last_temperature()
if SYSTEM_PARAMS["FAN_ACTIVATION_TEMP"] != None and actual_temp > SYSTEM_PARAMS["FAN_ACTIVATION_TEMP"]:
fan.set_max_speed(FAN_MAX_SPEED) #BASED ON THE MAX VALUE OF THE ENVIRONMENT SENSOR
fan.set_speed(actual_temp)
oled.print_line_no_fill("Fan Speed: "+ str(FAN_MAX_SPEED_DASHBOARD * actual_temp / FAN_MAX_SPEED), 0, 30, 1)
MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED] = ujson.dumps({"fan" : FAN_MAX_SPEED_DASHBOARD * actual_temp / FAN_MAX_SPEED})
try:
client.publish(MQTT_FAN_SPEED, MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
else:
fan.set_speed(0)
oled.print_line_no_fill("Fan Speed: 0", 0, 30, 1)
MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED] = ujson.dumps({"fan": 0})
try:
client.publish(MQTT_FAN_SPEED, MQTT_PUBLISH_VALUE[MQTT_FAN_SPEED])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
def manage_irrigation():
global SYSTEM_PARAMS, MQTT_PUBLISH_VALUE, SENSORS_ACTUAL_VALUE
if json.loads(SENSORS_ACTUAL_VALUE[MQTT_CISTERN_LEVEL])["cistern_level"] < SYSTEM_PARAMS["CRITICAL_CISTERN_LEVEL"]:
print("Livello di cisterna critico, ricarica il serbatoio per proseguire l'irrigazione")
oled.print_line_no_fill("Cistern Level: " + str(json.loads(SENSORS_ACTUAL_VALUE[MQTT_CISTERN_LEVEL])["cistern_level"]), 0, 20, 1)
SYSTEM_PARAMS["BLOCK_IRRIGATION_FOR_CRITICAL_CISTERN_LEVEL"] = True
#SYSTEM_PARAMS["PUMP_CICLE"] = False
MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE] = ujson.dumps({"pump": 0})
try:
client.publish(MQTT_PUMP_STATE, MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
pump.stop_pump()
elif json.loads(SENSORS_ACTUAL_VALUE[MQTT_CISTERN_LEVEL])["cistern_level"] > SYSTEM_PARAMS["CRITICAL_CISTERN_LEVEL"] and SYSTEM_PARAMS["BLOCK_IRRIGATION_FOR_CRITICAL_CISTERN_LEVEL"]:
print("Sistema di irrigazione ripristinato")
SYSTEM_PARAMS["BLOCK_IRRIGATION_FOR_CRITICAL_CISTERN_LEVEL"] = False
elif SYSTEM_PARAMS["MANUAL_IRRIGATION_CONTROL"]:
oled.print_line_no_fill("Irrigation: Man", 0, 40, 1)
if SYSTEM_PARAMS["MANUAL_IRRIGATION_PUMP"]:
print("Starting pump...", end="")
oled.print_line_no_fill("Pump: ON", 0, 50, 1)
MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE] = ujson.dumps({"pump": 1})
try:
client.publish(MQTT_PUMP_STATE, MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
#SYSTEM_PARAMS["PUMP_CICLE"] = True
#pump_cicle()
pump.start_pump()
else:
oled.print_line_no_fill("Pump: OFF", 0, 50, 1)
MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE] = ujson.dumps({"pump": 0})
try:
client.publish(MQTT_PUMP_STATE, MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
#SYSTEM_PARAMS["PUMP_CICLE"] = False
pump.stop_pump()
else:
oled.print_line_no_fill("Irrigation: Aut", 0, 40, 1)
if int(json.loads(SENSORS_ACTUAL_VALUE[MQTT_GROUND_HUMIDITY])["humidity"]) < SYSTEM_PARAMS["HUMIDITY_CRITICAL_LEVEL"]:
print("Starting pump...", end="")
oled.print_line_no_fill("Pump: ON", 0, 50, 1)
MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE] = ujson.dumps({"pump": 1})
try:
client.publish(MQTT_PUMP_STATE, MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
#SYSTEM_PARAMS["PUMP_CICLE"] = True
#pump_cicle()
pump.start_pump()
else:
oled.print_line_no_fill("Pump: OFF", 0, 50, 1)
MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE] = ujson.dumps({"pump": 0})
try:
client.publish(MQTT_PUMP_STATE, MQTT_PUBLISH_VALUE[MQTT_PUMP_STATE])
except OSError as e:
print("Error during the sensors data pubblication: ", e)
#SYSTEM_PARAMS["PUMP_CICLE"] = False
pump.stop_pump()
#_thread.start_new_thread(pump_cicle, ())
def read_sensor_value():
global MQTT_PUBLISH_VALUE
print("Reading sensors values...")
oled.print_line("sensors: ", 0, 1, 1)
SENSORS_ACTUAL_VALUE[MQTT_ENVIRONMENT_TEMP] = environment_sensor.get_ujson_temp()
SENSORS_ACTUAL_VALUE[MQTT_ENVIRONMENT_HUMIDITY] = environment_sensor.get_ujson_humidity()
SENSORS_ACTUAL_VALUE[MQTT_OUTSIDE_LUX] = photo_resistor.get_ujson_value()
SENSORS_ACTUAL_VALUE[MQTT_CISTERN_LEVEL] = cistern.get_ujson_level()
SENSORS_ACTUAL_VALUE[MQTT_GROUND_HUMIDITY] = ground_sensor.get_ujson_value()
oled.print_line_no_fill("Read", 65, 1, 1)
def restart_procedure():
global MQTT_PUBLISH_VALUE, SYSTEM_PARAMS, SENSORS_ACTUAL_VALUE
global MQTT_GROUND_HUMIDITY
global MQTT_ENVIRONMENT_TEMP
global MQTT_ENVIRONMENT_HUMIDITY
global MQTT_CISTERN_LEVEL
global MQTT_OUTSIDE_LUX
global MQTT_FAN_SPEED
global MQTT_PUMP_STATE
oled.print_line("Restarting the", 0, 1, 1)
oled.print_line_no_fill("system", 0, 10, 1)
shift_point = 0
try:
client.publish(MQTT_GROUND_HUMIDITY, ujson.dumps({"humidity" : 0}))
client.publish(MQTT_ENVIRONMENT_TEMP, ujson.dumps({"temp" : 0}))
client.publish(MQTT_ENVIRONMENT_HUMIDITY, ujson.dumps({"humidity" : 0}))
client.publish(MQTT_CISTERN_LEVEL, ujson.dumps({"cistern_level" : 0}))
client.publish(MQTT_OUTSIDE_LUX, ujson.dumps({"light" : 0}))
client.publish(MQTT_FAN_SPEED, ujson.dumps({"fan" : 0}))
client.publish(MQTT_PUMP_STATE, ujson.dumps({"pump" : 0}))
except OSError as e:
print("Error during the sensors data pubblication: ", e)
while shift_point < 28:
oled.print_line_no_fill(".", 45 + shift_point, 10, 1)
time.sleep(0.1)
shift_point = shift_point + 6
fan.set_max_speed(FAN_MAX_SPEED)
SYSTEM_PARAMS = {
"CRITICAL_CISTERN_LEVEL" : 10,
"HUMIDITY_CRITICAL_LEVEL" : 10,
"MANUAL_IRRIGATION_CONTROL" : False,
"MANUAL_IRRIGATION_PUMP": False,
"MANUAL_FAN_SPEED" : 0,
"MANUAL_FAN_CONTROL" : False,
"BLOCK_IRRIGATION_FOR_CRITICAL_CISTERN_LEVEL": False,
"RESTART_SYSTEM": False,
"FAN_ACTIVATION_TEMP": 30,
"PUMP_CICLE": False
}
MQTT_PUBLISH_VALUE = {
MQTT_GROUND_HUMIDITY : None,
MQTT_ENVIRONMENT_TEMP : None,
MQTT_ENVIRONMENT_HUMIDITY : None,
MQTT_CISTERN_LEVEL: None,
MQTT_OUTSIDE_LUX : None,
MQTT_FAN_SPEED : None,
MQTT_PUMP_STATE : None
}
SENSORS_ACTUAL_VALUE = {
MQTT_GROUND_HUMIDITY : None,
MQTT_ENVIRONMENT_TEMP : None,
MQTT_ENVIRONMENT_HUMIDITY : None,
MQTT_CISTERN_LEVEL: None,
MQTT_OUTSIDE_LUX : None,
}
#DEFINING THE IRQ PROCEDURE FOR THE RESET BTN
def hard_reset(btn_reset):
global LAST, SYSTEM_PARAMS
current = time.ticks_ms()
delta = time.ticks_diff(current, LAST)
if delta < 200:
return
last = current
SYSTEM_PARAMS["RESTART_SYSTEM"] = True
reset_btn.irq(trigger=Pin.IRQ_RISING, handler=hard_reset)
#MAIN LOOP
while True:
if SYSTEM_PARAMS["RESTART_SYSTEM"]:
restart_procedure()
else:
try:
read_sensor_value()
except OSError as e:
print("Error while reading the sensors values:", e)
try:
MQTT_PUBLISH_VALUE = client.publish_new_sensor_value(MQTT_PUBLISH_VALUE, SENSORS_ACTUAL_VALUE)
except OSError as e:
print("Error during the sensors data pubblication: ", e)
try:
print("Checking messages from the broker...")
oled.print_line_no_fill("broker msg: ", 0, 10, 1)
client.check_msg()
oled.print_line_no_fill("Check", 87, 10, 1)
except OSError as e:
oled.print_line_no_fill("Fail", 60, 10, 1)
print("Checking masseges from the broker fail: ", e)
manage_fan()
manage_irrigation()