import machine
import time
import random
import network
import urequests
# 1. I2C setup (LCD only)
i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)
LCD_ADDR = 0x27
# 2. LCD1602 driver
def write_word(data):
i2c.writeto(LCD_ADDR, bytearray([data | 0x08]))
def send_command(cmd):
write_word((cmd & 0xF0) | 0x04)
write_word((cmd & 0xF0))
write_word(((cmd << 4) & 0xF0) | 0x04)
write_word(((cmd << 4) & 0xF0))
def send_data(data):
write_word((data & 0xF0) | 0x05)
write_word((data & 0xF0) | 0x01)
write_word(((data << 4) & 0xF0) | 0x05)
write_word(((data << 4) & 0xF0) | 0x01)
def lcd_init():
time.sleep_ms(50)
for val in [0x30, 0x30, 0x30, 0x20]:
write_word(val | 0x04)
write_word(val)
time.sleep_ms(5)
send_command(0x28)
send_command(0x0C)
send_command(0x06)
send_command(0x01)
time.sleep_ms(5)
def lcd_clear():
send_command(0x01)
time.sleep_ms(2)
def lcd_move(col, row):
send_command(0x80 + col + (0x40 if row else 0x00))
def lcd_print(s):
for c in s:
send_data(ord(c))
def lcd_custom_char(location, charmap):
location &= 0x07
send_command(0x40 | (location << 3))
for i in range(8):
send_data(charmap[i])
send_command(0x80)
lcd_init()
# 5x8 custom characters
lock_char = bytearray([0x0E, 0x11, 0x11, 0x1F, 0x1B, 0x1B, 0x1F, 0x00])
shield_char = bytearray([0x1F, 0x11, 0x11, 0x11, 0x0A, 0x04, 0x00, 0x00])
lcd_custom_char(0, lock_char)
lcd_custom_char(1, shield_char)
# 3. Rotary encoder logic
clk = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
dt = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)
sw = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP)
menu_page = 0
max_pages = 3
last_clk = clk.value()
button_pressed = False
def encoder_callback(pin):
global menu_page, last_clk
current_clk = clk.value()
if current_clk != last_clk and current_clk == 1:
if dt.value() != current_clk:
menu_page = (menu_page + 1) % max_pages
else:
menu_page = (menu_page - 1) % max_pages
last_clk = current_clk
def button_callback(pin):
global button_pressed
button_pressed = True
clk.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=encoder_callback)
sw.irq(trigger=machine.Pin.IRQ_FALLING, handler=button_callback)
# 4. Sensor data
def get_measurements():
mpu_temp = random.uniform(22.0, 26.5)
accel_x = random.randint(-500, 500)
bmp_pressure = random.uniform(1010.0, 1015.5)
return mpu_temp, accel_x, bmp_pressure
#PART 1: ThingSpeak MQTT
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
THINGSPEAK_WRITE_API_KEY = "LF88EQVK0ROUM7N6"
THINGSPEAK_CHANNEL_ID = "3422776"
THINGSPEAK_URL = "https://api.thingspeak.com/update"
THINGSPEAK_PUBLISH_PERIOD_MS = 20000 # ThingSpeak free tier: >= 15s between updates
wifi_connected = False
last_thingspeak_send = time.ticks_ms()
def ts_connect_wifi():
sta = network.WLAN(network.STA_IF)
sta.active(True)
if not sta.isconnected():
print("Connecting to Wi-Fi", end="")
sta.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 20
while not sta.isconnected() and timeout > 0:
print(".", end="")
time.sleep(0.5)
timeout -= 1
if sta.isconnected():
print("\nWi-Fi connected:", sta.ifconfig())
return True
print("\nWi-Fi connection FAILED")
return False
def ts_publish(mpu_temp, accel_x, bmp_pressure):
url = "{}?api_key={}&field1={}&field2={}&field3={}".format(
THINGSPEAK_URL, THINGSPEAK_WRITE_API_KEY, mpu_temp, accel_x, bmp_pressure
)
try:
response = urequests.get(url)
# ThingSpeak returns the new entry ID as plain text (0 means failure)
print("Published -> entry ID:", response.text, " payload: field1={} field2={} field3={}".format(
mpu_temp, accel_x, bmp_pressure))
response.close()
except OSError as e:
print("HTTP publish failed:", e)
wifi_connected = ts_connect_wifi()
if not wifi_connected:
print("no Wi-Fi connection")
# 5. Main loop (with 1-second auto-refresh)
last_drawn_page = -1
last_update_time = time.ticks_ms()
while True:
current_time = time.ticks_ms()
# Auto-refresh the screen every 1000 ms (1 second) so the data updates
if time.ticks_diff(current_time, last_update_time) > 1000:
last_drawn_page = -1
last_update_time = current_time
# Handle button press
if button_pressed:
lcd_clear()
lcd_move(3, 0)
lcd_print("Selecting...")
time.sleep(0.5)
button_pressed = False
last_drawn_page = -1
# Redraw the UI
if menu_page != last_drawn_page:
lcd_clear()
if menu_page == 0:
lcd_move(2, 0)
lcd_print("SAIT Cyber")
lcd_move(2, 1)
send_data(0)
lcd_print(" Lab 3 Demo ")
send_data(1)
elif menu_page == 1:
mpu_temp, accel_x, _ = get_measurements()
lcd_move(0, 0)
lcd_print("MPU Temp: {:.1f}C".format(mpu_temp))
lcd_move(0, 1)
lcd_print("Accel X: {}".format(accel_x))
elif menu_page == 2:
_, _, bmp_pressure = get_measurements()
lcd_move(0, 0)
lcd_print("BMP180 Sensor")
lcd_move(0, 1)
lcd_print("Pres: {:.1f}hPa".format(bmp_pressure))
last_drawn_page = menu_page
#For PART 1: periodic ThingSpeak publish
if wifi_connected:
if time.ticks_diff(current_time, last_thingspeak_send) > THINGSPEAK_PUBLISH_PERIOD_MS:
mpu_temp, accel_x, bmp_pressure = get_measurements()
ts_publish(mpu_temp, accel_x, bmp_pressure)
last_thingspeak_send = current_time
time.sleep(0.05)