from machine import Pin, ADC, PWM, I2C, time_pulse_us
import dht
import time
import network
import urequests
import json
# =========================================================
# IoT AGRICULTURAL MONITORING SYSTEM (V4.0 - PICO W)
# =========================================================
# Created by: RAJAS SUDUMBREKAR
#
# Features:
# 1. Soil Moisture Monitoring
# 2. Temperature Monitoring
# 3. Humidity Monitoring
# 4. Rain Detection
# 5. Automatic Irrigation
# 6. Rain-Pump Dependency
# 7. Soil-Pump Dependency
# 8. Water Tank Level Monitoring (Ultrasonic)
# 9. Water Level Safety Lock (Low AND High Level)
# 10. High Temp / High Humidity Alarm
# 11. Exhaust Fan Control (Relay)
# 12. Water Flow Monitoring (Interrupts)
# 13. CO2 Monitoring (Simulated via ADC)
# 14. LCD Display
# 15. Serial Monitoring
# 16. Wi-Fi / IoT Cloud Upload (ThingSpeak/Blynk)
# =========================================================
# =========================================================
# PIN CONFIGURATION
# =========================================================
SOIL_PIN = 26
DHT_PIN = 16
GREEN_LED_PIN = 15
RED_LED_PIN = 14
BUZZER_PIN = 13
RELAY_PIN = 12
PUMP_LED_PIN = 11
# Exhaust Fan
FAN_RELAY_PIN = 10
# Water Flow Sensor
FLOW_SENSOR_PIN = 19
# CO2 Sensor (Simulated via ADC in Wokwi)
CO2_PIN = 27
I2C_SDA = 4
I2C_SCL = 5
# Ultrasonic Sensor Pins
TRIG_PIN = 17
ECHO_PIN = 18
# =========================================================
# I2C ADDRESSES
# =========================================================
LCD_ADDR = 0x27
RAIN_I2C_ADDR = 0x30
# =========================================================
# THRESHOLDS
# =========================================================
MOISTURE_THRESHOLD = 40
RAIN_THRESHOLD = 50
# Environmental Alarm Thresholds
TEMP_THRESHOLD = 35
HUMIDITY_THRESHOLD = 80
CO2_THRESHOLD = 1000 # ppm
# =========================================================
# ULTRASONIC DISTANCE THRESHOLDS (in cm)
# =========================================================
# Distance > 200 cm -> Water is too LOW
# Distance < 50 cm -> Water is too HIGH
# Distance between 50 and 200 cm -> Normal Operation
DISTANCE_LOW_THRESHOLD = 200.0
DISTANCE_HIGH_THRESHOLD = 50.0
# =========================================================
# WIFI / IOT CONFIGURATION
# =========================================================
# Wokwi provides a virtual Wi-Fi network called Wokwi-GUEST
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASS = ""
# ThingSpeak API (Replace with your own to see data online)
THINGSPEAK_API_KEY = "YOUR_API_KEY_HERE"
THINGSPEAK_URL = "http://api.thingspeak.com/update"
# =========================================================
# COMPONENT SETUP
# =========================================================
soil_sensor = ADC(SOIL_PIN)
dht_sensor = dht.DHT22(
Pin(DHT_PIN)
)
green_led = Pin(
GREEN_LED_PIN,
Pin.OUT
)
red_led = Pin(
RED_LED_PIN,
Pin.OUT
)
buzzer = PWM(
Pin(BUZZER_PIN)
)
buzzer.duty_u16(0)
relay = Pin(
RELAY_PIN,
Pin.OUT
)
pump_led = Pin(
PUMP_LED_PIN,
Pin.OUT
)
# Fan Setup
fan_relay = Pin(
FAN_RELAY_PIN,
Pin.OUT
)
fan_relay.off()
# Flow Sensor Setup
flow_pin = Pin(
FLOW_SENSOR_PIN,
Pin.IN,
Pin.PULL_UP
)
flow_pulse_count = 0
flow_liters = 0.0
last_flow_time = time.ticks_ms()
# CO2 Sensor Setup (ADC)
co2_sensor = ADC(CO2_PIN)
# Ultrasonic Sensor Setup
trig = Pin(TRIG_PIN, Pin.OUT)
echo = Pin(ECHO_PIN, Pin.IN)
# =========================================================
# I2C SETUP
# =========================================================
i2c = I2C(
0,
scl=Pin(I2C_SCL),
sda=Pin(I2C_SDA),
freq=400000
)
print("I2C Devices:", i2c.scan())
# =========================================================
# FLOW SENSOR INTERRUPT HANDLER
# =========================================================
def flow_isr(pin):
global flow_pulse_count
flow_pulse_count += 1
flow_pin.irq(
trigger=Pin.IRQ_FALLING,
handler=flow_isr
)
# =========================================================
# LCD FUNCTIONS
# =========================================================
def lcd_write_byte(data):
i2c.writeto(
LCD_ADDR,
bytes([data])
)
def lcd_command(cmd):
high = cmd & 0xF0
low = (cmd << 4) & 0xF0
lcd_write_byte(
high | 0x04
)
lcd_write_byte(
high
)
lcd_write_byte(
low | 0x04
)
lcd_write_byte(
low
)
def lcd_data(data):
high = data & 0xF0
low = (data << 4) & 0xF0
lcd_write_byte(
high | 0x05
)
lcd_write_byte(
high | 0x01
)
lcd_write_byte(
low | 0x05
)
lcd_write_byte(
low | 0x01
)
def lcd_init():
time.sleep(0.05)
lcd_command(0x33)
lcd_command(0x32)
lcd_command(0x28)
lcd_command(0x0C)
lcd_command(0x06)
lcd_command(0x01)
time.sleep(0.01)
def lcd_clear():
lcd_command(0x01)
time.sleep(0.002)
def lcd_print(text, line):
if line == 0:
lcd_command(0x80)
else:
lcd_command(0xC0)
text = str(text)
text = text[:16]
for char in text:
lcd_data(ord(char))
remaining = 16 - len(text)
for i in range(remaining):
lcd_data(ord(" "))
# =========================================================
# BUZZER FUNCTIONS
# =========================================================
def buzzer_off():
buzzer.duty_u16(0)
def short_beep():
buzzer.freq(1000)
buzzer.duty_u16(15000)
time.sleep(0.2)
buzzer.duty_u16(0)
def alarm_beep():
buzzer.freq(2000)
buzzer.duty_u16(30000)
time.sleep(0.1)
buzzer.duty_u16(0)
# =========================================================
# SENSOR READING FUNCTIONS
# =========================================================
def get_soil_moisture():
raw = soil_sensor.read_u16()
# 0 ADC = 100% moisture
# 65535 ADC = 0% moisture
moisture = int(
(
(65535 - raw) * 100
+ 32767
) / 65535
)
if moisture < 0:
moisture = 0
if moisture > 100:
moisture = 100
return moisture, raw
def get_dht():
try:
dht_sensor.measure()
temperature = (
dht_sensor.temperature()
)
humidity = (
dht_sensor.humidity()
)
return (
temperature,
humidity
)
except:
return (
None,
None
)
def get_rain_level():
try:
data = i2c.readfrom(
RAIN_I2C_ADDR,
1
)
rain_level = data[0]
if rain_level < 0:
rain_level = 0
if rain_level > 100:
rain_level = 100
return rain_level
except Exception as e:
print(
"Rain Sensor Error:",
e
)
return 0
def get_water_distance():
trig.value(0)
time.sleep_us(2)
trig.value(1)
time.sleep_us(10)
trig.value(0)
try:
pulse_duration = time_pulse_us(
echo,
1,
30000
)
except OSError:
return None
if pulse_duration < 0:
return None
distance_cm = (
pulse_duration * 0.0343
) / 2
return round(distance_cm, 1)
def get_co2_level():
raw = co2_sensor.read_u16()
# Map 0-65535 to 400-2000 ppm
co2 = int(
400 + (raw / 65535) * 1600
)
return co2
def calculate_flow():
global flow_pulse_count
global flow_liters
global last_flow_time
current_time = time.ticks_ms()
if time.ticks_diff(
current_time,
last_flow_time
) >= 1000:
# YF-S401: 5880 pulses = 1 Liter
flow_liters += (
flow_pulse_count / 5880.0
)
flow_pulse_count = 0
last_flow_time = current_time
return round(flow_liters, 3)
# =========================================================
# ACTUATOR CONTROL
# =========================================================
def pump_on():
relay.on()
pump_led.on()
def pump_off():
relay.off()
pump_led.off()
def fan_on():
fan_relay.on()
def fan_off():
fan_relay.off()
# =========================================================
# WIFI CONNECTION
# =========================================================
def connect_wifi():
wlan = network.WLAN(
network.STA_IF
)
wlan.active(True)
if not wlan.isconnected():
print("Connecting to WiFi...")
wlan.connect(
WIFI_SSID,
WIFI_PASS
)
timeout = 10
while not wlan.isconnected() and timeout > 0:
print("Waiting for connection...")
time.sleep(1)
timeout -= 1
if wlan.isconnected():
print(
"WiFi Connected! IP:",
wlan.ifconfig()[0]
)
return True
else:
print("WiFi Connection Failed.")
return False
def send_to_thingspeak(
temp,
hum,
moist,
co2,
flow
):
try:
url = (
THINGSPEAK_URL
+ "?api_key="
+ THINGSPEAK_API_KEY
)
url += "&field1=" + str(temp)
url += "&field2=" + str(hum)
url += "&field3=" + str(moist)
url += "&field4=" + str(co2)
url += "&field5=" + str(flow)
response = urequests.get(url)
print(
"ThingSpeak Response:",
response.text
)
response.close()
except Exception as e:
print("IoT Upload Error:", e)
# =========================================================
# INITIALIZATION
# =========================================================
green_led.off()
red_led.off()
buzzer_off()
pump_off()
fan_off()
lcd_init()
lcd_clear()
# Connect to Wi-Fi on startup
connect_wifi()
# =========================================================
# STARTUP SEQUENCE
# =========================================================
lcd_print(
"RAJAS.S",
0
)
lcd_print(
"AGRI MONITORING",
1
)
time.sleep(2)
lcd_clear()
# =========================================================
# SERIAL HEADER
# =========================================================
print()
print("==========================================")
print(" IoT AGRICULTURAL MONITORING SYSTEM V4.0")
print("==========================================")
print("Created by: RAJAS SUDUMBREKAR")
print("==========================================")
print()
print("--- PIN MAPPING ---")
print("Soil Sensor : GP26")
print("DHT22 : GP16")
print("Rain Sensor : I2C (0x30)")
print("CO2 Sensor : GP27 (ADC)")
print("Ultrasonic : TRIG=GP17, ECHO=GP18")
print("Relay/Pump : GP12")
print("Fan Relay : GP10")
print("Flow Sensor : GP19")
print("Pump LED : GP11")
print("Green LED : GP15")
print("Red LED : GP14")
print("Buzzer : GP13")
print("LCD : SDA=GP4, SCL=GP5")
print()
print("--- THRESHOLDS ---")
print("Moisture Threshold :", MOISTURE_THRESHOLD, "%")
print("Rain Threshold :", RAIN_THRESHOLD, "%")
print("Water Level Low :", DISTANCE_LOW_THRESHOLD, "cm")
print("Water Level High :", DISTANCE_HIGH_THRESHOLD, "cm")
print("Temp Alarm :", TEMP_THRESHOLD, "C")
print("Humidity Alarm :", HUMIDITY_THRESHOLD, "%")
print("CO2 Alarm :", CO2_THRESHOLD, "ppm")
print("==========================================")
print()
# =========================================================
# LCD SCREEN CONTROL VARIABLES
# =========================================================
screen = 0
last_screen_change = time.ticks_ms()
SCREEN_TIME = 3000
# =========================================================
# BUZZER TIMERS
# =========================================================
last_beep = time.ticks_ms()
last_alarm_beep = time.ticks_ms()
# =========================================================
# IOT UPLOAD TIMER
# =========================================================
last_iot_upload = time.ticks_ms()
# =========================================================
# MAIN LOOP
# =========================================================
while True:
# =====================================================
# 1. READ ALL SENSORS
# =====================================================
moisture, raw_adc = get_soil_moisture()
temperature, humidity = get_dht()
rain_level = get_rain_level()
distance_cm = get_water_distance()
co2_level = get_co2_level()
total_flow = calculate_flow()
# =====================================================
# 2. ENVIRONMENTAL ALARM LOGIC
# =====================================================
high_temp_alarm = False
high_humidity_alarm = False
high_co2_alarm = False
if temperature is not None and temperature > TEMP_THRESHOLD:
high_temp_alarm = True
if humidity is not None and humidity > HUMIDITY_THRESHOLD:
high_humidity_alarm = True
if co2_level is not None and co2_level > CO2_THRESHOLD:
high_co2_alarm = True
if high_temp_alarm or high_humidity_alarm or high_co2_alarm:
current_time = time.ticks_ms()
if time.ticks_diff(
current_time,
last_alarm_beep
) >= 500:
alarm_beep()
last_alarm_beep = current_time
# =====================================================
# 3. EXHAUST FAN CONTROL
# =====================================================
if high_temp_alarm or high_humidity_alarm:
fan_on()
fan_status = True
else:
fan_off()
fan_status = False
# =====================================================
# 4. RAIN DECISION
# =====================================================
raining = (
rain_level >= RAIN_THRESHOLD
)
# =====================================================
# 5. WATER LEVEL STATUS
# =====================================================
water_too_low = False
water_too_high = False
if distance_cm is not None:
if distance_cm > DISTANCE_LOW_THRESHOLD:
water_too_low = True
elif distance_cm < DISTANCE_HIGH_THRESHOLD:
water_too_high = True
# =====================================================
# 6. PUMP DECISION (WITH SAFETY LOCK)
# =====================================================
pump_status = False
if distance_cm is not None:
if not water_too_low and not water_too_high:
if (
moisture < MOISTURE_THRESHOLD
or rain_level < RAIN_THRESHOLD
):
pump_on()
pump_status = True
else:
pump_off()
else:
pump_off()
else:
pump_off()
# =====================================================
# 7. SERIAL MONITORING OUTPUT
# =====================================================
print("------------------------------------------")
print(
"RAJAS SUDUMBREKAR - SYSTEM STATUS"
)
print("------------------------------------------")
print(
"Soil Moisture :",
moisture,
"% (Raw ADC:",
raw_adc,
")"
)
print(
"Rain Level :",
rain_level,
"%"
)
if distance_cm is not None:
print(
"Water Dist :",
distance_cm,
"cm"
)
else:
print(
"Water Dist : SENSOR ERROR"
)
if temperature is not None:
print(
"Temperature :",
temperature,
"C"
)
print(
"Humidity :",
humidity,
"%"
)
else:
print(
"DHT22 : READING ERROR"
)
if co2_level is not None:
print(
"CO2 Level :",
co2_level,
"ppm"
)
else:
print(
"CO2 Sensor : READING ERROR"
)
print(
"Water Used :",
total_flow,
"Liters"
)
print("--- STATUS ---")
print(
"Rain Status :",
"RAIN DETECTED" if raining else "NO RAIN"
)
print(
"Pump Status :",
"ON" if pump_status else "OFF"
)
print(
"Fan Status :",
"ON" if fan_status else "OFF"
)
if water_too_low:
print(
"PUMP SAFETY : WATER LEVEL TOO LOW! PUMP LOCKED"
)
if water_too_high:
print(
"PUMP SAFETY : WATER LEVEL TOO HIGH! PUMP LOCKED"
)
if high_temp_alarm:
print(
"ALARM : HIGH TEMPERATURE DETECTED!"
)
if high_humidity_alarm:
print(
"ALARM : HIGH HUMIDITY DETECTED!"
)
if high_co2_alarm:
print(
"ALARM : HIGH CO2 DETECTED!"
)
print("------------------------------------------")
# =====================================================
# 8. IOT CLOUD UPLOAD (Every 30 seconds)
# =====================================================
current_time = time.ticks_ms()
if time.ticks_diff(
current_time,
last_iot_upload
) >= 30000:
send_to_thingspeak(
temperature,
humidity,
moisture,
co2_level,
total_flow
)
last_iot_upload = current_time
# =====================================================
# 9. LCD SCREEN ROTATION
# =====================================================
if time.ticks_diff(
current_time,
last_screen_change
) >= SCREEN_TIME:
screen += 1
if screen > 7:
screen = 0
last_screen_change = current_time
lcd_clear()
# =====================================================
# SCREEN 0: SOIL & PUMP
# =====================================================
if screen == 0:
lcd_print(
"Moist:" + str(moisture) + "%",
0
)
if pump_status:
lcd_print(
"PUMP: ON",
1
)
else:
if water_too_low:
lcd_print(
"PUMP: NO WATER",
1
)
elif water_too_high:
lcd_print(
"PUMP: TANK FULL",
1
)
else:
lcd_print(
"PUMP: OFF",
1
)
# =====================================================
# SCREEN 1: TEMPERATURE & HUMIDITY
# =====================================================
elif screen == 1:
if temperature is not None:
lcd_print(
"Temp:" + str(temperature) + "C",
0
)
lcd_print(
"Hum:" + str(humidity) + "%",
1
)
else:
lcd_print(
"DHT22 ERROR",
0
)
lcd_print(
"CHECK SENSOR",
1
)
# =====================================================
# SCREEN 2: RAIN & PUMP
# =====================================================
elif screen == 2:
lcd_print(
"Rain:" + str(rain_level) + "%",
0
)
if pump_status:
lcd_print(
"PUMP: ON",
1
)
else:
lcd_print(
"PUMP: OFF",
1
)
# =====================================================
# SCREEN 3: MOISTURE & RAIN
# =====================================================
elif screen == 3:
lcd_print(
"Moist:" + str(moisture) + "%",
0
)
lcd_print(
"Rain:" + str(rain_level) + "%",
1
)
# =====================================================
# SCREEN 4: WATER TANK LEVEL
# =====================================================
elif screen == 4:
if distance_cm is not None:
lcd_print(
"TANK DISTANCE",
0
)
lcd_print(
str(distance_cm) + " cm",
1
)
else:
lcd_print(
"TANK SENSOR",
0
)
lcd_print(
"ERROR",
1
)
# =====================================================
# SCREEN 5: CO2 LEVEL
# =====================================================
elif screen == 5:
if co2_level is not None:
lcd_print(
"CO2 LEVEL",
0
)
lcd_print(
str(co2_level) + " ppm",
1
)
else:
lcd_print(
"CO2 SENSOR",
0
)
lcd_print(
"ERROR",
1
)
# =====================================================
# SCREEN 6: WATER FLOW
# =====================================================
elif screen == 6:
lcd_print(
"WATER USED",
0
)
lcd_print(
str(total_flow) + " L",
1
)
# =====================================================
# SCREEN 7: ALARM STATUS
# =====================================================
elif screen == 7:
if high_temp_alarm or high_humidity_alarm or high_co2_alarm:
lcd_print(
"!! ALARM !!",
0
)
if high_temp_alarm and high_humidity_alarm:
lcd_print(
"TEMP & HUMID",
1
)
elif high_temp_alarm:
lcd_print(
"HIGH TEMP",
1
)
elif high_humidity_alarm:
lcd_print(
"HIGH HUMIDITY",
1
)
elif high_co2_alarm:
lcd_print(
"HIGH CO2",
1
)
else:
lcd_print(
"SYSTEM NORMAL",
0
)
lcd_print(
"NO ALARMS",
1
)
# =====================================================
# LOOP DELAY
# =====================================================
time.sleep(1)