from machine import Pin, UART, I2C
import time
# ==========================================
# HARDWARE & INLINE LCD INITIALIZATION
# ==========================================
I2C_ADDR = 0x27
i2c = I2C(0, sda=Pin(22), scl=Pin(21), freq=400000)
class InlineLCD:
def __init__(self, i2c, addr=0x27):
self.i2c = i2c
self.addr = addr
self.backlight = 0x08
time.sleep_ms(20)
for val in [0x33, 0x32, 0x28, 0x0C, 0x06, 0x01]:
self.write_cmd(val)
time.sleep_ms(5)
def write_cmd(self, cmd):
b1 = (cmd & 0xF0) | self.backlight
b2 = ((cmd << 4) & 0xF0) | self.backlight
self.i2c.writeto(self.addr, bytes([b1 | 0x04, b1, b2 | 0x04, b2]))
def write_data(self, data):
b1 = (data & 0xF0) | self.backlight | 0x01
b2 = ((data << 4) & 0xF0) | self.backlight | 0x01
self.i2c.writeto(self.addr, bytes([b1 | 0x04, b1, b2 | 0x04, b2]))
def clear(self):
self.write_cmd(0x01)
time.sleep_ms(2)
def move_to(self, x, y):
"""Moves cursor to explicit column (x) and row (y)."""
addr = x & 0x3F
if y == 1:
addr += 0x40
self.write_cmd(0x80 | addr)
def putstr(self, string):
for char in string:
if char == '\n':
self.move_to(0, 1)
else:
self.write_data(ord(char))
def show_reading_format(self, temp, hum, door, gas_val):
"""Clean formatting matching your preferred style."""
self.clear()
if gas_val == 0:
self.move_to(0, 0)
self.putstr("GAS ALERT!")
self.move_to(0, 1)
self.putstr("Ventilate NOW")
else:
self.move_to(0, 0)
self.putstr(f"T:{temp:.1f}C H:{hum:.1f}%")
self.move_to(0, 1)
self.putstr(f"Door: {door}")
lcd = InlineLCD(i2c, I2C_ADDR)
uart = UART(1, baudrate=9600, tx=Pin(17), rx=Pin(16))
# ==========================================
# DISPLAY FUNCTIONS
# ==========================================
def show_waiting():
"""Initial boot screen while waiting for UART stream."""
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Waiting for data")
lcd.move_to(6, 1)
lcd.putstr("(^_^)")
def process_uart_data(rx_buffer, last_payload):
if uart.any():
raw_bytes = uart.read()
if raw_bytes:
rx_buffer += raw_bytes.decode('utf-8', 'ignore')
while "\n" in rx_buffer:
line, rx_buffer = rx_buffer.split("\n", 1)
line = line.strip().strip(',')
if line:
parts = [p.strip() for p in line.split(',')]
if len(parts) >= 4:
try:
temp = float(parts[0]) if parts[0] else 25.0
hum = float(parts[1]) if parts[1] else 0.0
door = parts[3]
gas_val = int(parts[4]) if len(parts) >= 5 and parts[4].isdigit() else 1
current_payload = (temp, hum, door, gas_val)
# Only update if data changed (stops flickering)
if current_payload != last_payload:
lcd.show_reading_format(temp, hum, door, gas_val)
last_payload = current_payload
except Exception as e:
print("Parse error:", e)
return rx_buffer, last_payload
# ==========================================
# MAIN LOOP
# ==========================================
def main():
show_waiting()
time.sleep(1)
rx_buffer = ""
last_payload = None
while True:
rx_buffer, last_payload = process_uart_data(rx_buffer, last_payload)
time.sleep(0.01)
if __name__ == "__main__":
main()