print("Smart Soil Moisture Monitoring System (Pico)")
print(" BY STAR BANU — IOT")
# STEP 1: IMPORTS
from machine import Pin, I2C, ADC, PWM
import time
from ssd1306 import SSD1306_I2C # make sure ssd1306.py is in the project
# STEP 2: PIN SETUP (Pico)
BUZZER_PIN = 0 # GP0
ADC_PIN = 26 # GP26 = ADC0
LED_YEL = 2 # yellow (mid/ideal)
LED_RED = 3 # red (dry)
LED_GRN = 6 # green (wet/ok)
I2C_SDA = 4 # GP4
I2C_SCL = 5 # GP5
OLED_ADDR = 0x3C
buzzer = PWM(Pin(BUZZER_PIN))
buzzer.duty_u16(0)
soil = ADC(ADC_PIN)
led_yellow = Pin(LED_YEL, Pin.OUT)
led_red = Pin(LED_RED, Pin.OUT)
led_green = Pin(LED_GRN, Pin.OUT)
i2c = I2C(0, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL), freq=400_000)
oled = SSD1306_I2C(128, 64, i2c, addr=OLED_ADDR)
# STEP 2.1: CALIBRATION
# read_u16 returns 0..65535. Set these after watching the log a few seconds.
CAL_MIN = 9000 # raw value when soil is VERY DRY (slide low)
CAL_MAX = 60000 # raw value when soil is VERY WET (slide high)
# Thresholds for bands (percent)
TH_DRY = 40
TH_WET = 60
def clamp(v, lo, hi):
return lo if v < lo else hi if v > hi else v
def raw_to_percent(raw):
if CAL_MAX <= CAL_MIN:
return 0
pct = int((raw - CAL_MIN) * 100 / (CAL_MAX - CAL_MIN))
return clamp(pct, 0, 100)
def beep(ms=120, freq=2000, duty=30000):
buzzer.freq(freq)
buzzer.duty_u16(duty)
time.sleep_ms(ms)
buzzer.duty_u16(0)
def set_leds(state):
# state: "DRY", "IDEAL", "WET"
led_red.value(1 if state == "DRY" else 0)
led_yellow.value(1 if state == "IDEAL" else 0)
led_green.value(1 if state == "WET" else 0)
def show_oled(raw, pct, state):
oled.fill(0)
oled.text("Soil Moisture", 0, 0)
oled.text("Raw: {}".format(raw), 0, 14)
oled.text("Moist: {}%".format(pct), 0, 26)
oled.text("State: {}".format(state), 0, 38)
# simple bar
bar_x, bar_y, bar_w, bar_h = 0, 50, 128, 12
oled.rect(bar_x, bar_y, bar_w, bar_h, 1)
fill_w = int((pct/100) * (bar_w - 2))
if fill_w > 0:
oled.fill_rect(bar_x + 1, bar_y + 1, fill_w, bar_h - 2, 1)
oled.show()
print("Move the Soil Moisture slider on the custom chip. Calibrate CAL_MIN/CAL_MAX if needed.")
while True:
raw = soil.read_u16() # 0..65535
pct = raw_to_percent(raw) # 0..100 mapped by calibration
# STEP 3: DECISION LOGIC (bands)
if pct < TH_DRY:
state = "DRY"
set_leds(state)
# alert for DRY
beep(ms=150, freq=2200)
elif pct > TH_WET:
state = "WET"
set_leds(state)
# optional wet alert (milder chirp)
beep(ms=60, freq=1200)
else:
state = "IDEAL"
set_leds(state)
buzzer.duty_u16(0) # ensure buzzer off
# Display
show_oled(raw, pct, state)
# Console log
print("Raw:", raw, "Moisture:", pct, "% ->", state)
time.sleep(0.3)