print("Soil + DHTxx + MQTT | ESP32 | OLED")
print("BY FADZILAH (modified by ChatGPT for MQTT + DHT)")
from machine import Pin, I2C, ADC, PWM
import network, time, json
import ssd1306
import dht
from umqtt.simple import MQTTClient
# --- WIFI / MQTT ---
WIFI_SSID = "Wokwi-GUEST" # <--- exact case for Wokwi
WIFI_PSWD = ""
# Use a public broker for Wokwi testing:
MQTT_BROKER = "broker.hivemq.com" # or "test.mosquitto.org"
CLIENT_ID = "esp32-soil-dht-01"
BASE = "campus/greenhouse1"
TOPIC_PUB = f"{BASE}/state"
TOPIC_CMD = f"{BASE}/cmd"
TOPIC_RAW = f"{BASE}/raw"
# --- Soil calibration (tune for your sensor) ---
SOIL_RAW_DRY = 3135
SOIL_RAW_WET = 2165
# --- Pins ---
buzzer = PWM(Pin(26), freq=1, duty=0)
soil = ADC(Pin(34))
try: soil.atten(ADC.ATTN_11DB)
except: pass
orange = Pin(32, Pin.OUT)
yellow = Pin(33, Pin.OUT)
green = Pin(25, Pin.OUT)
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# Picture shows DHT22; use DHT22 here. If you use DHT11 hardware, change this line:
dhtx = dht.DHT22(Pin(27))
def wifi_connect():
wlan = network.WLAN(network.STA_IF)
if not wlan.active():
wlan.active(True)
if not wlan.isconnected():
print("Connecting to Wi-Fi:", WIFI_SSID)
wlan.connect(WIFI_SSID, WIFI_PSWD)
t0 = time.ticks_ms()
while not wlan.isconnected():
if time.ticks_diff(time.ticks_ms(), t0) > 20000:
print("Status:", wlan.status())
raise RuntimeError("Wi-Fi connect timeout")
time.sleep(0.2)
print("Wi-Fi OK:", wlan.ifconfig())
return wlan
mqtt = None
def on_mqtt_msg(topic, msg):
try:
data = json.loads(msg)
if str(data.get("green_led", "")).lower() == "on":
green.on()
elif str(data.get("green_led", "")).lower() == "off":
green.off()
except Exception as e:
print("MQTT cmd parse error:", e)
def mqtt_connect():
global mqtt
mqtt = MQTTClient(CLIENT_ID, MQTT_BROKER, keepalive=30)
mqtt.set_callback(on_mqtt_msg)
mqtt.connect()
mqtt.subscribe(TOPIC_CMD)
print("MQTT connected →", MQTT_BROKER, "| subscribed:", TOPIC_CMD)
def map_to_percent(raw, dry=SOIL_RAW_DRY, wet=SOIL_RAW_WET):
if dry == wet: return 0
r = max(min(raw, dry), wet)
pct = int((dry - r) * 100 / (dry - wet)) # wet→100, dry→0
return max(0, min(100, pct))
def show_oled(soil_pct, tC, h, status):
oled.fill(0)
oled.text("Soil Monitor", 0, 0)
oled.text("Soil: {:>3}%".format(soil_pct), 0, 16)
oled.text("Temp: {:>2}C".format("-" if tC is None else int(tC)), 0, 32)
oled.text("Hum : {:>2}%".format("-" if h is None else int(h )), 0, 48)
oled.text(status, 80, 0)
oled.show()
def set_outputs(status):
if status == "WET":
orange.on(); yellow.off(); green.off()
buzzer.init(freq=400, duty=50); time.sleep(0.5)
buzzer.init(freq=1, duty=0)
elif status == "DRY":
orange.off(); yellow.off(); green.on()
buzzer.init(freq=2000, duty=50); time.sleep(0.5)
buzzer.init(freq=1, duty=0)
else:
orange.off(); yellow.on(); green.off()
buzzer.init(freq=1, duty=0)
def main():
wifi_connect()
mqtt_connect()
while True:
raw = soil.read()
soil_pct = map_to_percent(raw)
tC = None; h = None
try:
dhtx.measure()
tC = dhtx.temperature()
h = dhtx.humidity()
except Exception as e:
print("DHT read err:", e)
status = "WET" if soil_pct < 40 else ("DRY" if soil_pct > 60 else "IDEAL")
set_outputs(status)
show_oled(soil_pct, tC, h, status)
payload = {
"soil_percent": soil_pct,
"soil_raw": raw,
"status": status,
"temp_c": tC,
"humidity": h,
"ts": time.time()
}
try:
mqtt.check_msg()
mqtt.publish(TOPIC_PUB, json.dumps(payload))
mqtt.publish(TOPIC_RAW, str(raw))
except Exception as e:
print("MQTT publish error:", e)
try: mqtt.disconnect()
except: pass
time.sleep(1)
mqtt_connect()
time.sleep(2)
try:
main()
except Exception as e:
print("Fatal error:", e)
buzzer.init(freq=1, duty=0)