"""
This IoT model automatically feeds fish and monitors water parameters
such as pH, turbidity, temperature, dissolved oxygen and ammonia.
The system uploads environmental data to ThingSpeak and estimates
the survivability index of the fish population.
"""
import urequests
import network
import time
import gc
from machine import Pin, PWM, ADC, I2C
from pico_i2c_lcd import I2cLcd
import urandom
# ================= WIFI =================
SSID = "Wokwi-GUEST"
PASSWORD = ""
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
def connect_wifi():
print("Connecting WiFi", end="")
wifi.connect(SSID, PASSWORD)
retry = 0
while not wifi.isconnected() and retry < 40:
print(".", end="")
time.sleep(0.5)
retry += 1
if wifi.isconnected():
print("\nConnected:", wifi.ifconfig()[0])
return True
else:
print("\nWiFi Failed")
return False
def ensure_wifi():
if not wifi.isconnected():
print("Reconnecting WiFi...")
wifi.active(False)
time.sleep(2)
wifi.active(True)
wifi.connect(SSID, PASSWORD)
retry = 0
while not wifi.isconnected() and retry < 20:
time.sleep(1)
retry += 1
if wifi.isconnected():
print("WiFi Restored")
if not connect_wifi():
raise SystemExit("WiFi required")
# ================= THINGSPEAK =================
THINGSPEAK_API_KEY = "6TIYXRSA6LZDKCOI"
def send_to_thingspeak(temp, ph, level, turb, do, nh3, pop, S):
if not wifi.isconnected():
return
url = (
"http://api.thingspeak.com/update?"
"api_key={}&field1={}&field2={}&field3={}&field4={}"
"&field5={}&field6={}&field7={}&field8={}"
).format(
THINGSPEAK_API_KEY,
temp, ph, level, turb, do, nh3, pop, S
)
try:
ensure_wifi()
response = urequests.get(url)
response.close()
print("ThingSpeak upload OK")
except:
print("ThingSpeak upload failed")
# ================= HARDWARE =================
ph_sensor = ADC(Pin(26))
turbidity_sensor = ADC(Pin(27))
do_sensor = ADC(Pin(28))
nh3_sensor = ADC(Pin(29))
fish_feeder = PWM(Pin(17))
heater = PWM(Pin(14))
water_pump = PWM(Pin(15))
aerator = Pin(13, Pin.OUT)
fish_feeder.freq(50)
heater.freq(50)
water_pump.freq(50)
# ================= LCD =================
i2c = I2C(0, sda=Pin(4), scl=Pin(5))
lcd = I2cLcd(i2c, 0x27, 2, 20)
lcd.putstr("Catfish IoT System")
time.sleep(2)
lcd.clear()
# ================= POPULATION =================
INITIAL_POPULATION = 1000
population = INITIAL_POPULATION
# ================= RANDOM SENSOR =================
def rand_float(a,b):
return a + (urandom.getrandbits(16)/65535)*(b-a)
def extreme_event():
return urandom.getrandbits(8) < 4
# ================= OTHER MORTALITY =================
def other_mortality():
return urandom.getrandbits(8) < 8
# ================= ACTUATORS =================
def feed_fish():
print("Feeding Fish")
fish_feeder.duty_u16(5000)
time.sleep(2)
fish_feeder.duty_u16(0)
def control_heater(temp):
if temp < 26:
heater.duty_u16(5000)
print("Heater ON")
else:
heater.duty_u16(0)
def control_aerator(do):
if do < 5:
aerator.value(1)
print("Aerator ON")
else:
aerator.value(0)
def control_water_pump(nh3, level):
if nh3 > 1 or level < 7:
print("Water Pump Activated")
water_pump.duty_u16(5000)
time.sleep(3)
water_pump.duty_u16(0)
# ================= EXTREME WATER CONDITIONS =================
def extreme_death(temp,do,nh3,turb,level,ph):
if temp > 35 or temp < 20:
print("Extreme Parameter: Temperature")
return True
if do < 3:
print("Extreme Parameter: Dissolved Oxygen")
return True
if nh3 > 0.05:
print("Extreme Parameter: Ammonia")
return True
if turb > 150:
print("Extreme Parameter: Turbidity")
return True
if level < 60:
print("Extreme Parameter: Water Level")
return True
if ph < 5.5 or ph > 9:
print("Extreme Parameter: pH")
return True
return False
# ================= RECOVERY =================
def recovery(temp, do, nh3, turb, level):
recovering = False
if temp < 26:
temp += 0.3
recovering = True
elif temp > 30:
temp -= 0.3
recovering = True
if do < 5:
do += 0.3
recovering = True
if nh3 > 0.05:
nh3 -= 0.02
recovering = True
if turb > 150:
turb -= 2
recovering = True
if level < 70:
level += 1
recovering = True
return temp, do, nh3, turb, level, recovering
# ================= MAIN LOOP =================
last_feed = time.time()
extreme_start_time = None
while True:
try:
# ===== NORMAL SENSOR SIMULATION =====
temperature = rand_float(26,30)
ph = rand_float(6.5,8.5)
turbidity = rand_float(20,80)
water_level = rand_float(80,120)
do = rand_float(5,9)
nh3 = rand_float(0.00,0.02)
# ===== EXTREME EVENT =====
if extreme_event():
print("⚠ EXTREME EVENT")
if urandom.getrandbits(1):
temperature = rand_float(0,20)
else:
temperature = rand_float(35,40)
do = rand_float(0,3)
nh3 = rand_float(0.06,2)
water_level = rand_float(20,60)
if urandom.getrandbits(1):
ph = rand_float(3,5.5)
else:
ph = rand_float(9,11)
turbidity = rand_float(120,200)
# ===== SURVIVABILITY INDEX =====
pop_factor = population / INITIAL_POPULATION
do_factor = do / 8
nh3_factor = 1 - (nh3 / 2)
turb_factor = 1 - (turbidity / 200)
level_factor = water_level / 100
S = pop_factor * do_factor * nh3_factor * turb_factor * level_factor
S = max(0, min(S,1))
# ===== RECOVERY =====
temperature, do, nh3, turbidity, water_level, recovering = recovery(
temperature, do, nh3, turbidity, water_level
)
# ===== DISPLAY =====
print("---------------")
print("Temp:", temperature)
print("pH:", ph)
print("Turbidity:", turbidity)
print("DO:", do)
print("NH3:", nh3)
print("Water Level:", water_level)
print("Population:", population)
print("Survivability:", S)
lcd.clear()
lcd.move_to(0,0)
lcd.putstr("T:{:.1f} DO:{:.1f}".format(temperature,do))
lcd.move_to(0,1)
lcd.putstr("Pop:{} S:{:.2f}".format(population,S))
# ===== ACTUATORS =====
control_heater(temperature)
control_aerator(do)
control_water_pump(nh3,water_level)
now = time.time()
if now - last_feed > 60:
feed_fish()
last_feed = now
# ===== EXTREME MORTALITY =====
if extreme_death(temperature, do, nh3, turbidity, water_level, ph):
if extreme_start_time is None:
extreme_start_time = now
elif now - extreme_start_time >= 120:
deaths = int(population * 0.03)
population -= deaths
population = max(0, population)
print("ALERT: Extreme water condition")
print("Deaths:", deaths)
extreme_start_time = now
else:
extreme_start_time = None
# ===== OTHER MORTALITY =====
if other_mortality() and population > 0:
deaths_other = int(population * 0.005)
population -= deaths_other
population = max(0, population)
print("Other mortality event occurred")
print("Deaths from disease/stress:", deaths_other)
# ===== SEND DATA =====
send_to_thingspeak(
temperature, ph, water_level, turbidity, do, nh3, population, S
)
time.sleep(60)
except Exception as e:
print("Runtime error:", e)
time.sleep(5)