from machine import Pin, ADC, I2C, time_pulse_us
from time import sleep
import dht
import network
from umqtt.simple import MQTTClient
from i2c_lcd import I2cLcd
# ================= WIFI + MQTT =================
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASS = ""
MQTT_BROKER = "test.mosquitto.org"
CLIENT_ID = "esp32-iot-demo"
TOPIC_SOIL = b"iot/demo/soil"
TOPIC_TEMP = b"iot/demo/temp"
TOPIC_WATER = b"iot/demo/water"
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASS)
while not wlan.isconnected():
sleep(0.5)
mqtt = MQTTClient(CLIENT_ID, MQTT_BROKER)
mqtt.connect()
# ================= HARDWARE =================
# DHT22
dht_sensor = dht.DHT22(Pin(23))
# Soil sensor (potentiometer)
soil_adc = ADC(Pin(36))
soil_adc.atten(ADC.ATTN_11DB)
soil_adc.width(ADC.WIDTH_12BIT)
# Ultrasonic
trig = Pin(33, Pin.OUT)
echo = Pin(32, Pin.IN)
# Relay
relay = Pin(13, Pin.OUT)
relay.value(0)
# Water alarm LED
led_water = Pin(22, Pin.OUT)
led_water.value(0)
# LCD1602 I2C
i2c = I2C(0, scl=Pin(18), sda=Pin(19), freq=400000)
lcd = I2cLcd(i2c, 0x27, 2, 16)
# ================= PARAMETERS =================
SOIL_THRESHOLD = 30
WATER_LEVEL_MAX_CM = 25
READ_INTERVAL = 5
# ================= FUNCTIONS =================
def read_soil():
return round((soil_adc.read() / 4095) * 100, 1)
def read_ultrasonic():
trig.value(0)
sleep(0.000002)
trig.value(1)
sleep(0.00001)
trig.value(0)
try:
t = time_pulse_us(echo, 1, 30000)
return (t * 0.0343) / 2
except OSError:
return None
# ================= MAIN LOOP =================
while True:
try:
dht_sensor.measure()
temp = dht_sensor.temperature()
hum = dht_sensor.humidity()
except OSError:
temp = hum = None
soil = read_soil()
dist = read_ultrasonic()
water_low = True if dist is None else dist > WATER_LEVEL_MAX_CM
# Control logic
if water_low:
relay.value(0)
led_water.value(1)
mqtt.publish(TOPIC_WATER, b"LOW")
else:
led_water.value(0)
mqtt.publish(TOPIC_WATER, b"OK")
relay.value(1 if soil < SOIL_THRESHOLD else 0)
# LCD update
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Soil:{:>4.1f}%".format(soil))
lcd.move_to(0, 1)
if temp is not None:
lcd.putstr("T:{:>4.1f}C".format(temp))
mqtt.publish(TOPIC_TEMP, str(temp))
else:
lcd.putstr("DHT Error")
mqtt.publish(TOPIC_SOIL, str(soil))
print("Soil:", soil, "Temp:", temp, "Water low:", water_low)
sleep(READ_INTERVAL)