from machine import Pin, I2C, PWM
import ssd1306
import time
import ntptime
import network
import utime
from mpu6050 import MPU6050
import urequests
import ujson
import face
import framebuf
from umqtt.simple import MQTTClient
# ======= MQTT Setup =======
MQTT_CLIENT_ID = "my_micropython_device" # change if you want
MQTT_BROKER = "broker.hivemq.com"
MQTT_PORT = 1883
WATER_TOPIC = "mico/water"
STEP_TOPIC = "mico/step"
# ======= OpenWeather Setup =======
API_KEY = "4ba73f0865cfcc26ca11333782899a57"
#CITY = "Nancy"
CITY = "Kuala+Lumpur"
# ======= WiFi Setup =======
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('Wokwi-GUEST', '')
while not wlan.isconnected():
time.sleep(1)
print("Connected to WiFi")
# ======= Fetch OpenWeather =======
def fetch_weather():
try:
url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"
response = urequests.get(url)
data = ujson.loads(response)
temp = data["main"]["temp"]
desc = data["weather"][0]["main"]
return f"{int(temp)}C {desc}"
except Exception as e:
print("Weather error:", e)
return " Error"
# ======= Time Formatter =======
def get_now():
utc_time = utime.time()
local_time = utime.localtime(utc_time + 8 * 3600) # +8 hours
return "{:02}:{:02}".format(local_time[3], local_time[4])
# ======= Buzzer Beep =======
def beep(frequency=1000, duration=200):
bzr.freq(frequency)
bzr.duty(512) # 50% duty (range is 0–1023)
utime.sleep_ms(duration)
bzr.duty(0)
# ======= Setup =======
weather_str = "Loading.."
weather_timer = utime.ticks_ms()
connect_wifi()
ntptime.settime()
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
button = Pin(13, Pin.IN, Pin.PULL_UP)
water_count = 0
last_button_state = 1
# MPU6050
mpu = MPU6050()
step_count = 0
step_threshold = 13 # Tune this value based on noise
last_step_time = utime.ticks_ms()
# Water Reminder
reminder_interval = 60_000 #10 seconds
last_reminder_time = utime.ticks_ms()
reminder_active = False
# Step Animation
step_act = False
step_ani = False
# Weather Faces
weather_str = fetch_weather()
weather_name = weather_str.split(" ", 1)[1]
# Buzzer
bzr = PWM(Pin(15))
bzr.duty(0)
# Reset Step
btnStep = Pin(12, Pin.IN, Pin.PULL_UP)
# Connect MQTT
mqtt_client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, port=MQTT_PORT)
mqtt_client.connect()
print("Connected to MQTT broker")
# ======= Main Loop =======
while True:
# Water Reminder
if not reminder_active and utime.ticks_diff(utime.ticks_ms(), last_reminder_time) > reminder_interval:
reminder_active = True
last_reminder_time = utime.ticks_ms()
# Handle water button
current_state = button.value()
if last_button_state == 1 and current_state == 0:
if reminder_active:
water_count += 1
print("Water taken during reminder:", water_count)
reminder_active = False # Dismiss reminder
mqtt_client.publish(WATER_TOPIC, str(water_count))
else:
water_count += 1
mqtt_client.publish(WATER_TOPIC, str(water_count))
time.sleep(0.2) # debounce
last_button_state = current_state
# Weather
# Every 60 seconds, update weather
if utime.ticks_diff(utime.ticks_ms(), weather_timer) > 60000:
weather_str = fetch_weather()
weather_timer = utime.ticks_ms()
weather_name = weather_str.split(" ", 1)[1]
# Read accelerometer
try:
gyro = mpu.read_accel_data()
x = gyro["x"]
y = gyro["y"]
z = gyro["z"]
magnitude = (x**2 + y**2 + z**2) ** 0.5
now = utime.ticks_ms()
if magnitude > step_threshold and utime.ticks_diff(now, last_step_time) > 300:
step_count += 1
last_step_time = now
print("Step count:", step_count)
mqtt_client.publish(STEP_TOPIC, str(step_count))
step_act = True
else:
step_act = False
except Exception as e:
print("MPU6050 error:", e)
if btnStep.value() == 0:
step_count = 0
water_count = 0
# Face lift
#weather_name = "Clouds"
#weather_name = "Thunderstorm"
#weather_name = "Clear"
#weather_name = "Snow"
#weather_name = "Rain"
# Display all info
oled.fill(0)
if reminder_active:
fb = framebuf.FrameBuffer(face.face_water, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
else:
if step_act:
if step_ani:
fb = framebuf.FrameBuffer(face.face_move1, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
step_ani = False
else:
fb = framebuf.FrameBuffer(face.face_move2, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
step_ani = True
else:
if weather_name == "Clouds":
fb = framebuf.FrameBuffer(face.face_cloud, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
elif weather_name == "Clear":
fb = framebuf.FrameBuffer(face.face_clear, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
elif weather_name == "Rain":
fb = framebuf.FrameBuffer(face.face_rain, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
elif weather_name == "Snow":
fb = framebuf.FrameBuffer(face.face_snow, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
elif weather_name == "Thunderstorm":
fb = framebuf.FrameBuffer(face.face_snow, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
elif weather_name == "Drizzle":
fb = framebuf.FrameBuffer(face.face_drizzle, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
else:
fb = framebuf.FrameBuffer(face.face_cloud, 128, 54, framebuf.MONO_HLSB)
oled.framebuf.blit(fb, 0, 10)
oled.text(get_now(), 0, 0)
oled.text(weather_str, 56, 0)
oled.text("WTR", 0, 56)
oled.text("STP", 104, 56)
oled.text(str(step_count), 112, 32)
if reminder_active:
oled.text("PLS", 0, 24)
oled.text("DRK", 0, 40)
beep(2000, 100)
else:
oled.text(str(water_count), 8, 32)
bzr.duty(0)
"""
# Create a FrameBuffer object (assumes 128x54 pixel image)
fb = framebuf.FrameBuffer(face.face_rain, 128, 54, framebuf.MONO_HLSB)
# Draw the image at position (0, 0)
oled.framebuf.blit(fb, 0, 10)
"""
oled.show()
time.sleep(0.2)
Drink Water
Reset Button