171 lines
6.4 KiB
Python
171 lines
6.4 KiB
Python
import time
|
|
import network
|
|
import machine
|
|
from machine import Pin, SPI, I2C
|
|
import rlcd
|
|
|
|
# Import our utility classes
|
|
from shtc3_util import SHTC3
|
|
from rtc_util import PCF85063
|
|
from battery_util import BatteryMonitor
|
|
from button_util import BoardButtons
|
|
from rgb_led_util import BoardLED
|
|
from ble_util import BLEUART
|
|
from mcp_server import MCPServer
|
|
|
|
# LED mode options for manual cycling
|
|
led_modes = [
|
|
("Red (Breathing)", lambda led: led.set_color(40, 0, 0), "breath"),
|
|
("Green (Breathing)", lambda led: led.set_color(0, 40, 0), "breath"),
|
|
("Blue (Breathing)", lambda led: led.set_color(0, 0, 40), "breath"),
|
|
("Cyan (Breathing)", lambda led: led.set_color(0, 30, 30), "breath"),
|
|
("Magenta (Breathing)", lambda led: led.set_color(30, 0, 30), "breath"),
|
|
("Rainbow Cycle", lambda led: led.set_color(30, 30, 30), "rainbow"),
|
|
("LED Off", lambda led: led.off(), "off")
|
|
]
|
|
local_led_mode_idx = 1 # Green breathing
|
|
|
|
def main():
|
|
global local_led_mode_idx
|
|
print("=== Starting ESP32-S3-RLCD-4.2 Main Boot ===")
|
|
|
|
# 1. Initialize shared buses and peripherals
|
|
i2c = I2C(0, sda=Pin(13), scl=Pin(14))
|
|
|
|
spi = SPI(1, baudrate=20000000, polarity=0, phase=0, sck=Pin(11), mosi=Pin(12))
|
|
display = rlcd.RLCD(spi, cs=Pin(40), dc=Pin(5), rst=Pin(41))
|
|
|
|
# Configure Audio Amp control pin to save power
|
|
amp_pin = Pin(46, Pin.OUT, value=0)
|
|
|
|
# 2. Initialize utility objects
|
|
sensor = SHTC3(i2c)
|
|
rtc_chip = PCF85063(i2c)
|
|
battery = BatteryMonitor()
|
|
led = BoardLED(38)
|
|
buttons = BoardButtons()
|
|
ble_uart = BLEUART(name="ESP32-S3-RLCD")
|
|
|
|
# Sync system clock from RTC chip
|
|
rtc_chip.sync_to_system()
|
|
|
|
# 3. Connect to Wi-Fi status check (boot.py already attempted connection)
|
|
wlan = network.WLAN(network.STA_IF)
|
|
ip_addr = wlan.ifconfig()[0] if wlan.isconnected() else "Disconnected"
|
|
|
|
# 4. Start MCP Server
|
|
mcp = MCPServer(display, led, battery, sensor, rtc_chip, ble_uart)
|
|
mcp.start(port=80)
|
|
|
|
# Default to Green Breathing
|
|
led_modes[local_led_mode_idx][1](led)
|
|
mcp.active_led_mode = led_modes[local_led_mode_idx][2]
|
|
|
|
# Last user actions
|
|
last_action_str = "Boot finished."
|
|
force_dashboard_redraw = True
|
|
|
|
# 5. Register Button Handlers
|
|
def on_key_click():
|
|
global local_led_mode_idx
|
|
local_led_mode_idx = (local_led_mode_idx + 1) % len(led_modes)
|
|
mode_name, color_fn, mode_type = led_modes[local_led_mode_idx]
|
|
color_fn(led)
|
|
mcp.active_led_mode = mode_type
|
|
print(f"Local Button: Cycle LED -> {mode_name}")
|
|
nonlocal last_action_str, force_dashboard_redraw
|
|
last_action_str = f"Local Button: {mode_name}"
|
|
# Disable override when manual button is pressed
|
|
mcp.override_active = False
|
|
force_dashboard_redraw = True
|
|
|
|
def on_boot_click():
|
|
print("Local Button: Force Dashboard refresh.")
|
|
nonlocal last_action_str, force_dashboard_redraw
|
|
last_action_str = "Dashboard Refreshed"
|
|
# Disable override when manual button is pressed
|
|
mcp.override_active = False
|
|
force_dashboard_redraw = True
|
|
|
|
buttons.key.on_click(on_key_click)
|
|
buttons.boot.on_click(on_boot_click)
|
|
|
|
# Loop state
|
|
last_dashboard_update = 0
|
|
dashboard_update_interval_ms = 5000
|
|
|
|
print("ESP32 MCP loop running...")
|
|
|
|
# 6. Main execution loop
|
|
while True:
|
|
now = time.ticks_ms()
|
|
|
|
# A. Handle non-blocking MCP client connection updates
|
|
mcp.update()
|
|
|
|
# B. Check if custom draw text override has expired
|
|
if mcp.override_active and time.ticks_diff(now, mcp.override_timeout) > 0:
|
|
print("MCP Screen override expired. Returning to status dashboard...")
|
|
mcp.override_active = False
|
|
force_dashboard_redraw = True
|
|
|
|
# C. Draw local dashboard (if not overridden by MCP draw text commands)
|
|
if not mcp.override_active:
|
|
if force_dashboard_redraw or time.ticks_diff(now, last_dashboard_update) >= dashboard_update_interval_ms:
|
|
force_dashboard_redraw = False
|
|
last_dashboard_update = now
|
|
|
|
# Fetch sensor data
|
|
t, h = sensor.read_sensor()
|
|
t_str = f"{t} C" if t is not None else "Error"
|
|
h_str = f"{h} %" if h is not None else "Error"
|
|
|
|
# Fetch battery status
|
|
bat_v = battery.read_voltage()
|
|
bat_p = battery.read_percentage()
|
|
bat_str = f"{bat_v:.2f}V ({bat_p}%)" if bat_v is not None else "Error"
|
|
|
|
# Fetch current time
|
|
dt = rtc_chip.get_datetime()
|
|
time_str = f"{dt[0]:04d}-{dt[1]:02d}-{dt[2]:02d} {dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d}" if dt else "RTC Error"
|
|
|
|
# Draw standard status dashboard layout
|
|
display.clear(0)
|
|
display.text("ESP32-S3-RLCD MCP SERVER", 10, 10, 1)
|
|
display.line(10, 20, 390, 20, 1)
|
|
|
|
display.text_large("ENVIRONMENT", 15, 30, scale=2, c=1)
|
|
display.text(f"Temp : {t_str}", 25, 55, 1)
|
|
display.text(f"Humid : {h_str}", 25, 70, 1)
|
|
|
|
display.line(10, 95, 390, 95, 1)
|
|
|
|
display.text_large("MCP NET CONNECTION", 15, 105, scale=2, c=1)
|
|
display.text(f"IP Address : {ip_addr}", 25, 130, 1)
|
|
display.text(f"Port / Path : 80 /api/mcp", 25, 145, 1)
|
|
display.text(f"BLE Name : ESP32-S3-RLCD", 25, 160, 1)
|
|
|
|
display.line(10, 185, 390, 185, 1)
|
|
|
|
display.text_large("SYSTEM STATUS", 15, 195, scale=2, c=1)
|
|
display.text(f"Battery : {bat_str}", 25, 220, 1)
|
|
display.text(f"Time : {time_str}", 25, 235, 1)
|
|
|
|
display.line(10, 255, 390, 255, 1)
|
|
display.text(f"Status: {last_action_str}", 15, 265, 1)
|
|
display.show()
|
|
|
|
# D. Update NeoPixel animation smoothly (runs every 50ms)
|
|
mode = mcp.active_led_mode
|
|
if mode == "breath":
|
|
led.update_breathing(1.5)
|
|
elif mode == "rainbow":
|
|
led.update_rainbow(0.4)
|
|
elif mode == "off":
|
|
led.off()
|
|
|
|
time.sleep_ms(50)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|