"""
MicroPython IoT Weather Station Example for Wokwi.com
# Combined with: SkySpringsSimple v2
print("SkySpringsSimple v2 starting up...")
To view the data:
1. Go to http://www.hivemq.com/demos/websocket-client/
2. Click "Connect"
3. Under Subscriptions, click "Add New Topic Subscription"
4. In the Topic field, type "wokwi-weather" then click "Subscribe"
Now click on the DHT22 sensor in the simulation,
change the temperature/humidity, and you should see
the message appear on the MQTT Broker, in the "Messages" pane.
Copyright (C) 2022, Uri Shaked
https://wokwi.com/arduino/projects/322577683855704658
"""
import math
import network
import time
from machine import Pin, WDT, deepsleep
import dht
import ds18x20
import onewire
import ujson
from umqtt.simple import MQTTClient
# MQTT Server Parameters
MQTT_CLIENT_ID = "micropython-weather-demo"
MQTT_BROKER = "broker.mqttdashboard.com"
MQTT_USER = ""
MQTT_PASSWORD = ""
MQTT_TOPIC = "wokwi-weather"
print("Connecting to WiFi", end="")
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('Wokwi-GUEST', '')
while not sta_if.isconnected():
print(".", end="")
time.sleep(0.1)
print(" Connected!")
print("Connecting to MQTT server... ", end="")
client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, user=MQTT_USER, password=MQTT_PASSWORD)
client.connect()
print("Connected!")
# SkySpringsSimple v2
print("SkySpringsSimple v2 starting up...")
# This script is designed to run on a microcontroller (e.g., ESP32)
# to monitor atmospheric humidity, drybulb temperature, and water temperature,
# and control a pump based on dew point calculation.
#Not necessary to setup the serial connection in the script, as the MicroPython environment automatically handles it:
#Default settings for ESP32/ESP8266:**
#- **Baud rate:** 115200
#- **Data bits:** 8
#- **Parity:** None
#- **Stop bits:** 1
# It uses DHT22 for air temperature and humidity, and DS18B20 for water temperature. Setup for sensors:
sensorTHair = dht.DHT22(Pin(15))
#connect a 4.7k Ohm pull-up resistor between the DHT22 data pin and VCC (3.3V or 5V).
ow = onewire.OneWire(Pin(4)) #pin 4 is used for the DS18B20 sensor
#connect a 4.7k Ohm pull-up resistor between the DS18B20 data pin and VCC (3.3V or 5V).
sensor_temp_water = ds18x20.DS18X20(ow)
roms = sensor_temp_water.scan()
print('found DS devices: ', roms)
sensor_temp_water.convert_temp()
time.sleep_ms(750)
for rom in roms:
print(rom)
print(sensor_temp_water.read_temp(rom))
time.sleep(5)
relay_pin = Pin(5, Pin.OUT)
# Initialize the relay pin to off
relay_pin.value(0) # Ensure the pump is off at startup
def dewpoint(temp, rh):
"""Magnus formula based on Dry Bulb and Relative Humidity from Wikipedia
Arguments: temp (Celsius), rh (Relative Humidity in %)
Returns: Dew Point in Celsius
Reference: https://en.wikipedia.org/wiki/Dew_point#Calculation
"""
b = 17.625
c = 243.04
gamma = math.log(rh/100) + (b*temp)/(c+temp)
return (c*gamma)/(b - gamma)
def pump(tw, dp):
"""Function to determine if the pump should be turned on or off based on water temperature (tw) and dewpoint (dp).
#Returns 0 if tw > dp (not interesting), and 1 if dp > tw (we can condense!).
#If return 1, turn on the pump.
"""
if tw is None:
print("No water temp sensor found.")
return 0
if dp is None:
print("No dewpoint calculated.")
return 0
return 1 if dp > tw else 0
def ctof(t):
"""takes Temp in C and returns Temp in F
"""
if t is None:
print("No temperature value provided.")
return None
else:
return t * (9/5) + 32.0
def check_sensors():
"""No arguments, checks the sensors and returns the values.
Reads DHT22 for air temperature and humidity, DS18B20 for water temperature.
Returns: Air Temperature (C), Air Humidity(%), dewpoint(C), waterTemp (C)
"""
try:
sensorTHair.measure()
temp = sensorTHair.temperature()
hum = sensorTHair.humidity()
except Exception as e:
print('Failed to read DHT22:', e)
temp = None
hum = None
if temp is not None and hum is not None:
temp_f = ctof(temp)
dp = dewpoint(temp, hum)
print('Temperature: %3.1f C' %temp)
print('Temperature: %3.1f F' %temp_f)
print('Humidity: %3.1f %%' %hum)
print('Dewpoint: %3.1f C' % dewpoint(temp, hum))
else:
temp_f = None
dp = None
print("Failed to read temperature or humidity.")
tw = read_temp()
# sensorTw.convert_temp()
# time.sleep_ms(750)
# roms = sensorTw.scan()
# tw = sensorTw.read_temp(roms[0]) if roms else None
print('WaterTemp: %3.1f C' % tw if tw is not None else "No DS18B20 found")
return (temp, hum, dp, tw)
# Function to read temperature from DS18B20
def read_temp():
roms = sensor_temp_water.scan()
if not roms:
print("No DS18B20 sensor found.")
return None
sensor_temp_water.convert_temp()
time.sleep_ms(750)
return sensor_temp_water.read_temp(roms[0]) if roms else None
# Configurable times (in ms)
SensorCheckTime = 5000 # 60000 = 60s = 1 min
# Enable the watchdog timer with a timeout in multiples of SensorCheckTime.
#WDT is not available on Wokwi Simulation. Enable for meat space.
#wdt = WDT(timeout=5 * SensorCheckTime) # 5 minutes
prev_weather = ""
while True:#Void Loop
# A simple true loop: sleep for pre-set time, check sensors, calculate DP,
# compare, if Tw<DP, start pump, else pump off.
#sleep for the configured time:
# deepsleep(SensorCheckTime)
time.sleep_ms(SensorCheckTime) # Use sleep instead of deepsleep for testing
time.sleep_ms(100) # Allow time for the system to wake up properly (have a cup of coffee)
#after wakeup, check sensors:
print("Measuring weather conditions... ", end="")
tair, rhair, dp, twater = check_sensors()
#Compare and start or stop pump:
pump_start = pump(twater, dp) #returns 0 or 1
relay_pin.value(pump_start) #set the relay_pin high if Tw<DP.
if pump_start: print('Pump started')
else: print('Pump stopped')
message = ujson.dumps({
"temp": tair,
"humidity": rhair,
"dewpoint": dp,
"water_temp": twater,
"pump_status": "on" if pump_start else "off"
})
try:
if message != prev_weather:
print("Updated!")
print("Reporting to MQTT topic {}: {}".format(MQTT_TOPIC, message))
client.publish(MQTT_TOPIC, message)
prev_weather = message
else:
print("No change")
time.sleep(1)
except Exception as e:
print("Failed to publish to MQTT:", e)
# wdt.feed() # Feed the watchdog timer to prevent reset
# End of the loop
# Note: The script will run indefinitely, checking sensorsLoading
ds18b20
ds18b20