# This MicroPython project on ESP32 simulates water analysis for a polluted river.
# It uses a potentiometer to simulate pH, an HC-SR04 ultrasonic sensor for water depth,
# and an NTC analog temperature sensor for temperature monitoring.
# It displays the values on an OLED screen and activates LEDs based on critical thresholds.
# A buzzer sounds if all three parameters reach critical values simultaneously.
from machine import Pin, ADC, PWM, I2C
from ssd1306 import SSD1306_I2C
from hcsr04 import HCSR04
from time import sleep
# ----------------------------
# Project: Polluted River Monitoring
# Features: pH, Water Depth, Temperature
# Outputs: OLED display, 3 LEDs, Buzzer if all are critical
# ----------------------------
# Import required libraries
from machine import Pin, ADC, PWM, I2C # Hardware control: pins, analog/digital input/output, PWM, I2C
from ssd1306 import SSD1306_I2C # OLED display driver
from hcsr04 import HCSR04 # Ultrasonic distance sensor driver
from time import sleep # Delay function
# -------------------------------
# OLED setup (128x64 display over I2C)
# SCL on pin 22, SDA on pin 21
# -------------------------------
i2c = I2C(0, scl=Pin(22), sda=Pin(21)) # Initialize I2C bus
oled = SSD1306_I2C(128, 64, i2c) # Create OLED object using the I2C bus
# -------------------------------
# Sensor setup
# -------------------------------
ph_sensor = ADC(Pin(34)) # Simulated pH sensor using a potentiometer
ph_sensor.atten(ADC.ATTN_11DB) # Set ADC attenuation to read full 0–3.3V range
temp_sensor = ADC(Pin(35)) # Temperature sensor using an analog NTC thermistor
temp_sensor.atten(ADC.ATTN_11DB) # Full range reading for accurate conversion
ultrasonic = HCSR04(trigger_pin=4, echo_pin=5) # Ultrasonic sensor (HC-SR04) for water depth detection
# -------------------------------
# Output devices (LEDs and Buzzer)
# -------------------------------
led_ph = Pin(15, Pin.OUT) # Red LED for pH alert
led_depth = Pin(2, Pin.OUT) # Blue LED for low depth alert
led_temp = Pin(18, Pin.OUT) # Green LED for high temperature alert
buzzer = PWM(Pin(19), freq=1000) # Buzzer with PWM control (1kHz tone)
buzzer.duty(0) # Start with buzzer OFF
# -------------------------------
# Threshold values for alerts
# -------------------------------
PH_CRITICAL = 9.0 # If pH > 9.0, it's considered critical
DEPTH_LIMIT_CM = 5 # If water depth < 5 cm, it's too shallow
TEMP_CRITICAL_C = 18.0 # If temperature > 18°C, it's considered critical
# -------------------------------
# Function: Convert ADC to pH
# Returns pH value between 0 and 14
# -------------------------------
def read_ph():
raw = ph_sensor.read() # Read analog value (0–4095)
ph = (raw / 4095) * 14 # Map raw value linearly to pH scale
return round(ph, 2) # Round to 2 decimal places
# -------------------------------
# Function: Convert ADC to temperature
# Using a simplified linear approximation for NTC sensor
# -------------------------------
def read_temperature():
raw = temp_sensor.read() # Read analog value (0–4095)
temp = (raw / 4095) * 100 # Approximate 0–100°C scale
return round(temp, 1) # Round to 1 decimal place
# -------------------------------
# Function: Display sensor values on OLED
# Shows pH, depth, and temperature
# -------------------------------
def display(ph, depth, temp):
oled.fill(0) # Clear OLED screen
oled.text("pH: {}".format(ph), 0, 0) # Display pH value
oled.text("Depth: {:.1f} cm".format(depth), 0, 20) # Display depth in cm
oled.text("Temp: {} C".format(temp), 0, 40) # Display temperature in °C
oled.show() # Refresh the display
# -------------------------------
# Main program loop
# Continuously reads sensors, updates display,
# controls LEDs and buzzer based on thresholds
# -------------------------------
while True:
ph_val = read_ph() # Get current pH value
temp_val = read_temperature() # Get current temperature
try:
depth_cm = ultrasonic.distance_cm() # Measure water depth
except OSError:
depth_cm = -1 # Set to -1 if sensor fails
display(ph_val, depth_cm, temp_val) # Show all values on OLED
# -------------------------------
# Control LEDs based on critical thresholds
# Each LED turns ON if its condition is met
# -------------------------------
led_ph.value(ph_val > PH_CRITICAL) # Red LED on if pH is too high
led_depth.value(depth_cm >= 0 and depth_cm < DEPTH_LIMIT_CM) # Blue LED on if depth is too low
led_temp.value(temp_val > TEMP_CRITICAL_C) # Green LED on if temp is too high
# -------------------------------
# Control buzzer: alert only if ALL three conditions are critical
# -------------------------------
if (ph_val > PH_CRITICAL and
depth_cm >= 0 and depth_cm < DEPTH_LIMIT_CM and
temp_val > TEMP_CRITICAL_C):
buzzer.duty(512) # Turn buzzer ON
else:
buzzer.duty(0) # Turn buzzer OFF
sleep(1) # Wait 1 second before next loop