import time 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 # LED state management 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"), # Dummy base color, handled by cycle ("LED Off", lambda led: led.off(), "off") ] current_mode_idx = 1 # Start on Green (Breathing) def main(): global current_mode_idx print("=== Initializing ESP32-S3-RLCD-4.2 Demo ===") # 1. Initialize shared I2C bus and SPI display print("Initializing I2C (SDA=13, SCL=14)...") i2c = I2C(0, sda=Pin(13), scl=Pin(14)) print("Initializing SPI and Display...") 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)) # Enable the speaker amplifier power control pin (just to show how, set low for now to save power/avoid hum) print("Configuring Audio Amp control pin...") amp_pin = Pin(46, Pin.OUT, value=0) # 2. Initialize Utilities print("Initializing hardware utilities...") sensor = SHTC3(i2c) rtc_chip = PCF85063(i2c) battery = BatteryMonitor() led = BoardLED(38) buttons = BoardButtons() # Sync system clock from hardware RTC on startup rtc_chip.sync_to_system() # Set initial LED mode (Green breathing) led_modes[current_mode_idx][1](led) # 3. Setup Button Event Callbacks last_action_str = "System Started" trigger_screen_update = True def on_key_click(): global current_mode_idx current_mode_idx = (current_mode_idx + 1) % len(led_modes) mode_name = led_modes[current_mode_idx][0] # Apply color settings led_modes[current_mode_idx][1](led) print(f"KEY clicked! Switched LED mode to: {mode_name}") nonlocal last_action_str, trigger_screen_update last_action_str = f"LED: {mode_name}" trigger_screen_update = True def on_boot_click(): print("BOOT clicked! Triggering manual refresh.") nonlocal last_action_str, trigger_screen_update last_action_str = "Manual Screen Refresh" trigger_screen_update = True # Register callbacks buttons.key.on_click(on_key_click) buttons.boot.on_click(on_boot_click) # 4. Main execution loop print("Starting Main Loop...") last_screen_update = 0 screen_update_interval_ms = 5000 # Update display every 5 seconds or on button triggers screenshot_saved = False while True: current_time_ms = time.ticks_ms() # Check if we should update the screen if trigger_screen_update or (time.ticks_diff(current_time_ms, last_screen_update) >= screen_update_interval_ms): trigger_screen_update = False last_screen_update = current_time_ms # Read sensor values temp, hum = sensor.read_sensor() temp_str = f"{temp} C" if temp is not None else "Error" hum_str = f"{hum} %" if hum is not None else "Error" # Read RTC time dt = rtc_chip.get_datetime() if dt: time_str = f"{dt[0]:04d}-{dt[1]:02d}-{dt[2]:02d} {dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d}" else: time_str = "RTC Error" # Read battery info 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" print(f"[{rtc_chip.get_time_string()}] T={temp_str}, H={hum_str}, Battery={bat_str}") # Draw display display.clear(0) # Clear to white (standard background) # Title display.text("WAVESHARE ESP32-S3-RLCD-4.2", 10, 10, 1) display.line(10, 20, 390, 20, 1) # Sensor Readings block display.text_large("ENVIRONMENT", 15, 30, scale=2, c=1) display.text(f"Temperature : {temp_str}", 25, 55, 1) display.text(f"Humidity : {hum_str}", 25, 70, 1) display.line(10, 95, 390, 95, 1) # Device Status block display.text_large("DEVICE STATUS", 15, 105, scale=2, c=1) display.text(f"RTC Time : {time_str}", 25, 130, 1) display.text(f"Battery : {bat_str}", 25, 145, 1) display.line(10, 170, 390, 170, 1) # Interactions block display.text_large("INTERACTIVE CONTROLS", 15, 180, scale=2, c=1) display.text("Press [KEY] button to cycle NeoPixel LED", 25, 205, 1) display.text("Press [BOOT] button to force display refresh", 25, 220, 1) # Footer / Last action display.line(10, 245, 390, 245, 1) display.text(f"Event: {last_action_str}", 15, 255, 1) # Send buffer to screen display.show() # Capture the first frame as a screenshot so we can verify it if not screenshot_saved: try: display.save_screenshot('screenshot_demo.pbm') screenshot_saved = True except Exception as e: print(f"Failed to save screenshot_demo: {e}") # Update NeoPixel animation smoothly (runs every 50ms) mode_type = led_modes[current_mode_idx][2] if mode_type == "breath": led.update_breathing(1.5) elif mode_type == "rainbow": led.update_rainbow(0.4) else: led.off() time.sleep_ms(50) if __name__ == "__main__": main()