Project 5.9: "Early Warning System"
What you’ll learn
- ✅ Detect rain, soil moisture, and temperature: Read three sensors to monitor conditions.
- ✅ Create early warnings: Print app-friendly alerts like “ALERT:FLOOD_RISK” and “ALERT:DROUGHT”.
- ✅ Push-style notifications: Format messages for app to pop up warnings clearly.
- ✅ Protection actions: Print commands to cover/protect equipment when alerts trigger.
- ✅ Reliable thresholds: Prevent false alarms with confirmation windows.
Key ideas
- Short definition: Early warnings are fast messages sent when sensor values cross safety lines.
- Real-world link: Weather stations and smart farms warn about rain, floods, and droughts so we act in time.
Blocks glossary (used in this project)
- DHT11 temperature: Reads air temperature in Celsius from Pin 26.
- Analog input (ADC): Reads soil moisture as a raw number (0–4095) from Pin 32.
- Digital input (Pin): Reads raindrop sensor (1 = wet trigger, 0 = dry) from Pin 35.
- If / else: Decides when to trigger alerts.
- Serial println: Sends “KEY:VALUE” and “ALERT:…” messages to the app.
- Timing windows: Confirms events over short periods to avoid false alerts.
What you need
| Part | How many? | Pin connection |
|---|---|---|
| D1 R32 | 1 | USB cable (30 cm) |
| DHT11 | 1 | Signal → Pin 26, VCC, GND |
| Soil humidity sensor | 1 | Signal → Pin 32 (ADC), VCC, GND |
| Raindrop detection sensor | 1 | DO → Pin 35 (digital input), VCC, GND |
🔌 Wiring tip: Use Pin 35 for raindrop (input-only pins 34–39 are ideal), Pin 32 for soil (ADC), and Pin 26 for DHT11. Keep wires short to reduce noise.
📍 Pin map snapshot: Using 26 (DHT), 32 (soil ADC), 35 (rain DO). Others stay free for future actuators.
Before you start
- USB cable is plugged in
- Serial monitor is open
- Test print shows:
print("Ready!") # Confirm serial is working
Microprojects (5 mini missions)
Microproject 5.9.1 – Sensor triad: rain, soil, temperature
Goal: Read all three sensors and print clean values.
Blocks used:
- DHT11 temperature: Get temp in °C.
- Analog input (ADC): Read soil raw, map to percent.
- Digital input: Read rain state (1/0).
Block sequence:
- Setup DHT11 on Pin 26.
- Setup ADC on Pin 32 (12-bit).
- Setup raindrop input on Pin 35.
- Read and print values.
MicroPython code:
import dhtx # Import DHT11 library for temperature
import machine # Import machine for ADC and Pin control
sensor = dhtx.DHT11(26) # Create DHT11 on Pin 26
print("Microproject 5.9.1: DHT11 ready on Pin 26") # Status message
adc32 = machine.ADC(machine.Pin(32)) # Create ADC on Pin 32 for soil sensor
adc32.atten(machine.ADC.ATTN_11DB) # Set ADC attenuation for full-scale reading
adc32.width(machine.ADC.WIDTH_12BIT) # Use 12-bit resolution (0–4095)
print("ADC ready on Pin 32 (soil)") # Status message
rain = machine.Pin(35, machine.Pin.IN) # Digital input for raindrop on Pin 35
print("Raindrop input ready on Pin 35") # Status message
temp_c = sensor.temperature() # Read temperature in Celsius
print("TEMP:", temp_c) # App-friendly temperature print
raw = adc32.read() # Read raw soil moisture value
print("SOIL_RAW:", raw) # Show raw number for calibration
soil_pct = int((4095 - raw) * 100 / 4095) # Convert raw to % (higher=wet)
print("SOIL:", soil_pct) # App-friendly soil percent
rain_state = rain.value() # Read raindrop: 1=wet trigger, 0=dry
print("RAIN:", rain_state) # App-friendly rain state
Reflection: Now you can “feel” sky, ground, and air—perfect for early warnings.
Challenge:
- Easy: Print “PLACE:GARDEN” after the readings.
- Harder: Average soil from 3 samples before mapping.
Microproject 5.9.2 – Thresholds and base alerts
Goal: Define thresholds and print heat/dry/rain alerts.
Blocks used:
- Variables: temp_high, soil_low.
- If / else: Trigger alerts on crossing.
Block sequence:
- Set temp_high = 32°C, soil_low = 30%.
- If temp ≥ temp_high → ALERT:HEAT.
- If soil < soil_low → ALERT:DROUGHT.
- If rain_state == 1 → ALERT:RAIN.
MicroPython code:
temp_c = 31 # Example temperature for testing (replace with sensor)
soil_pct = 25 # Example soil moisture percent (replace with sensor)
rain_state = 1 # Example rain state (1=wet trigger)
temp_high = 32 # Temperature threshold in Celsius
soil_low = 30 # Soil dryness threshold in percent
print("Microproject 5.9.2: Thresholds ->", "TEMP_HIGH:", temp_high, "SOIL_LOW:", soil_low) # Show thresholds
if temp_c >= temp_high: # Check temperature threshold
print("ALERT:HEAT") # Alert for heat
if soil_pct < soil_low: # Check soil dryness threshold
print("ALERT:DROUGHT") # Alert for drought risk
if rain_state == 1: # Check rain detection
print("ALERT:RAIN") # Alert for rain
Reflection: Clear thresholds = clear alerts—set numbers that match your environment.
Challenge:
- Easy: Add ALERT:COLD when temp_c < 15.
- Harder: Add ALERT:WIND later if you add a wind sensor.
Microproject 5.9.3 – Flood and drought combined logic
Goal: Print stronger warnings when multiple conditions are met.
Blocks used:
- If / and: Combine conditions for risk levels.
- Serial println: Print “ALERT:FLOOD_RISK” or “ALERT:SEVERE_DROUGHT”.
Block sequence:
- If rain_state == 1 and soil_pct > 80 → FLOOD_RISK.
- If rain_state == 0 and soil_pct < 20 → SEVERE_DROUGHT.
- Else print STATUS:OK.
MicroPython code:
temp_c = 28 # Example temp (replace with sensor)
soil_pct = 85 # Example soil percent (replace with sensor)
rain_state = 1 # Example rain (1=wet trigger)
print("Microproject 5.9.3: Combined risk checks") # Status message
if (rain_state == 1) and (soil_pct > 80): # Rain and very wet soil
print("ALERT:FLOOD_RISK") # Strong flood warning
elif (rain_state == 0) and (soil_pct < 20): # No rain and very dry soil
print("ALERT:SEVERE_DROUGHT") # Strong drought warning
else: # Neither severe case
print("STATUS:OK") # Normal status
Reflection: Combining signals gives smarter warnings—context matters.
Challenge:
- Easy: Add ALERT:MUD if soil_pct > 90.
- Harder: Add multi-level severity (LOW/MID/HIGH) as separate prints.
Microproject 5.9.4 – Push-style notifications for the app
Goal: Format messages that the app can show as notifications.
Blocks used:
- Serial println: Print “NOTIFY:…” messages.
- Variables: Compose readable text.
Block sequence:
- Build text like “NOTIFY:RAIN_DETECTED”.
- Include “DETAIL:” lines with values.
- Print both.
MicroPython code:
temp_c = 30 # Example temp for message (replace with sensor)
soil_pct = 40 # Example soil percent (replace with sensor)
rain_state = 1 # Example rain state (replace with sensor)
notify = "NOTIFY:RAIN_DETECTED" # Short notification tag
print(notify) # Send notification tag to app
detail = "DETAIL:TEMP=" + str(temp_c) + ",SOIL=" + str(soil_pct) + ",RAIN=" + str(rain_state) # Compose details
print(detail) # Send details to app
Reflection: Short tag + details make notifications easy to pop and read.
Challenge:
- Easy: Change to NOTIFY:DRY_SOIL.
- Harder: Add “PLACE:GARDEN_A” and a timestamp.
Microproject 5.9.5 – Protection systems activation
Goal: Print protection commands when risks are high.
Blocks used:
- If / else: Decide protection.
- Serial println: Print “PROTECT:…” lines.
Block sequence:
- If FLOOD_RISK → PROTECT:COVER_ON.
- If SEVERE_DROUGHT → PROTECT:SHADE_ON.
- Else → PROTECT:OFF.
MicroPython code:
soil_pct = 18 # Example soil percent (replace with sensor)
rain_state = 0 # Example rain state (replace with sensor)
print("Microproject 5.9.5: Protection action planner") # Status message
if (rain_state == 1) and (soil_pct > 80): # Flood risk condition
print("PROTECT:COVER_ON") # Command to deploy covers (simulated)
elif (rain_state == 0) and (soil_pct < 20): # Severe drought condition
print("PROTECT:SHADE_ON") # Command to add shade or reduce evaporation (simulated)
else: # No strong risk
print("PROTECT:OFF") # No protection needed
Reflection: Protection commands are like safety switches—turn them on only when truly needed.
Challenge:
- Easy: Add PROTECT:ALERT_ONLY to notify without action.
- Harder: Add a cooldown (60 s) before changing protection state again.
Main project – Early warning system
Blocks steps (with glossary)
- DHT11 + soil + rain: Read all sensors and map soil to percent.
- Base alerts: Heat/drought/rain using thresholds.
- Combined risk: Flood or severe drought using multi-signal checks.
- Notifications: Print NOTIFY + DETAIL messages.
- Protection: Print PROTECT commands to simulate safety actions.
Block sequence:
- Setup sensors on 26, 32, 35.
- Read TEMP, SOIL(%), RAIN and print them.
- Trigger base alerts on thresholds.
- Trigger combined risk alerts.
- Print NOTIFY and PROTECT messages for the app.
MicroPython code (mirroring blocks)
# Project 5.9 – Early Warning System
import dhtx # Read DHT11 temperature sensor
import machine # Read ADC and digital inputs
import time # Add timing utilities for confirmation windows
sensor = dhtx.DHT11(26) # DHT11 on Pin 26
print("DHT11 ready on Pin 26") # Confirm sensor setup
adc32 = machine.ADC(machine.Pin(32)) # Soil sensor ADC on Pin 32
adc32.atten(machine.ADC.ATTN_11DB) # Configure ADC attenuation for full scale
adc32.width(machine.ADC.WIDTH_12BIT) # Use 12-bit resolution (0–4095)
print("ADC ready on Pin 32 (soil)") # Confirm ADC setup
rain = machine.Pin(35, machine.Pin.IN) # Raindrop DO input on Pin 35
print("Raindrop input ready on Pin 35") # Confirm raindrop input
temp_high = 32 # Temperature alert threshold (C)
soil_low = 30 # Soil dryness threshold (%)
print("Thresholds -> TEMP_HIGH:", temp_high, "SOIL_LOW:", soil_low) # Show thresholds
while True: # Continuous monitoring loop
temp_c = sensor.temperature() # Read temperature from DHT11
print("TEMP:", temp_c) # App-friendly temperature output
raw = adc32.read() # Read raw soil value
print("SOIL_RAW:", raw) # Print raw for calibration
soil_pct = int((4095 - raw) * 100 / 4095) # Map raw to percent (higher=wet)
print("SOIL:", soil_pct) # App-friendly soil percent
# Confirm rain using a short 200 ms window to reduce false alerts
confirm_hits = 0 # Start confirmation counter
start = time.ticks_ms() # Record window start time
while time.ticks_diff(time.ticks_ms(), start) < 200: # Sample for 200 ms
confirm_hits += rain.value() # Add 1 whenever sensor is HIGH
time.sleep(0.01) # Sample every 10 ms
rain_state = 1 if confirm_hits > 5 else 0 # Confirm rain if several highs
print("RAIN:", rain_state, "CONFIRM_HITS:", confirm_hits) # App-friendly rain state
# Base alerts
if temp_c >= temp_high: # Heat threshold
print("ALERT:HEAT") # Heat alert
if soil_pct < soil_low: # Dry soil threshold
print("ALERT:DROUGHT") # Drought alert
if rain_state == 1: # Rain detection
print("ALERT:RAIN") # Rain alert
# Combined risk alerts
if (rain_state == 1) and (soil_pct > 80): # Rain + very wet soil
print("ALERT:FLOOD_RISK") # Strong flood warning
print("NOTIFY:FLOOD_RISK") # Notification tag
print("DETAIL:TEMP=" + str(temp_c) + ",SOIL=" + str(soil_pct) + ",RAIN=" + str(rain_state)) # Details
print("PROTECT:COVER_ON") # Simulated protection action
elif (rain_state == 0) and (soil_pct < 20): # No rain + very dry soil
print("ALERT:SEVERE_DROUGHT") # Strong drought warning
print("NOTIFY:SEVERE_DROUGHT") # Notification tag
print("DETAIL:TEMP=" + str(temp_c) + ",SOIL=" + str(soil_pct) + ",RAIN=" + str(rain_state)) # Details
print("PROTECT:SHADE_ON") # Simulated protection action
else: # Normal status path
print("STATUS:OK") # Normal status
print("PROTECT:OFF") # No protection needed
time.sleep(2) # Wait 2 seconds before next cycle for readability
External explanation
- What it teaches: You built a real early warning flow: read sensors, decide risks, send notifications, and propose protective actions.
- Why it works: Temperature and soil map to human-friendly values; rain is confirmed in a short window to avoid false triggers; combined conditions produce stronger alerts; “NOTIFY” and “DETAIL” messages help the app display clear warnings.
- Key concept: “Sense → confirm → alert → notify → protect.”
Story time
Your robot is now a weather guardian. It spots rain, checks the ground, feels the air, and warns you with quick, clear messages—before trouble hits.
Debugging (2)
Debugging 5.9.A – Early warnings are not activated
Problem: Conditions hit thresholds but no alert appears.
Clues: Serial shows TEMP/SOIL/RAIN, but no “ALERT:…” lines.
Broken code:
if temp_c > temp_high: # Excludes equal
print("ALERT:HEAT") # Heat alert (may miss exact threshold)
Fixed code:
if temp_c >= temp_high: # Include equal case
print("ALERT:HEAT") # Heat alert fires reliably
Why it works: Including equality prevents missing the exact threshold value.
Avoid next time: Decide clearly whether equality should trigger alerts and code it.
Debugging 5.9.B – False alerts
Problem: Random rain spikes or noisy soil readings cause alerts.
Clues: Rain briefly prints 1, then 0; alerts flicker.
Broken code:
rain_state = rain.value() # Single read is too sensitive to spikes
print("RAIN:", rain_state) # May fluctuate
Fixed code:
confirm_hits = 0 # Count highs in a short window
start = time.ticks_ms() # Start timing
while time.ticks_diff(time.ticks_ms(), start) < 200: # 200 ms window
confirm_hits += rain.value() # Add HIGHs
time.sleep(0.01) # Small sampling interval
rain_state = 1 if confirm_hits > 5 else 0 # Confirm only if many highs
print("RAIN:", rain_state, "CONFIRM_HITS:", confirm_hits) # Explain confirmation
Why it works: A confirmation window smooths noise and reduces false positives.
Avoid next time: Sample over short windows and choose sensible confirmation thresholds.
Final checklist
- TEMP, SOIL(%), and RAIN printed clearly
- Base alerts fired at thresholds
- Combined risk alerts printed (FLOOD_RISK or SEVERE_DROUGHT)
- NOTIFY and DETAIL messages appeared for the app
- PROTECT commands printed when risks were high
Extras
- 🧠 Student tip: Add “ALERT:LOW_BAT” if you track battery later; keep formats short.
- 🧑🏫 Instructor tip: Have students test real wet/dry soil values to set practical thresholds.
- 📖 Glossary:
- Confirmation window: Short sampling period to verify an event before alerting.
- Combined risk: Alert triggered by multiple conditions together.
- Protection command: Printed action telling actuators what to do (simulated).
- 💡 Mini tips:
- Pace prints with small delays so the app doesn’t miss messages.
- Keep wiring steady—sensor noise creates false alerts.
- Label your station with PLACE to distinguish multiple setups.