A nightstand noise generator based on M5Stack Atom Echo and integrating with Home Assistant
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 107 lines 3.9 kB view raw
1//! Type-level "wires" between the firmware modules. 2//! 3//! These enums define the shape of the cross-task message passing. Producers 4//! and consumers are independent; adding a new producer (e.g., MQTT in a 5//! later milestone) is a matter of adding another `Sender<AudioCommand>`, 6//! not changing any existing module. 7 8/// What the button task observes and reports to the coordinator. 9#[derive(Debug, Clone, Copy, PartialEq, Eq)] 10pub enum ButtonEvent { 11 /// A single short press (released before 2s, no follow-up press within 400ms). 12 Short, 13 /// Held for 2s or more. 14 Long, 15 /// Two short presses within 400ms of each other. 16 Double, 17} 18 19impl ButtonEvent { 20 /// The wire-format string used in MQTT button event payloads. 21 pub fn as_event_type(self) -> &'static str { 22 match self { 23 Self::Short => "short", 24 Self::Long => "long", 25 Self::Double => "double", 26 } 27 } 28} 29 30/// What the coordinator (or, later, an MQTT task) tells the audio task to do. 31#[derive(Debug, Clone, Copy, PartialEq, Eq)] 32pub enum AudioCommand { 33 /// Start playing white noise at the current volume. 34 Play, 35 /// Stop playing. 36 Stop, 37 /// Toggle play state. 38 Toggle, 39 /// Advance the volume yo-yo by one step in the current direction. 40 CycleVolume, 41 /// Set volume directly to a specific preset index (0..VOLUME_PRESETS.len()). 42 /// Used when HA sends a numeric volume; we snap to the nearest preset. 43 SetVolumeIndex(u8), 44} 45 46/// Audio playback state, sent from the audio task to the LED task. 47#[derive(Debug, Clone, Copy, PartialEq, Eq)] 48pub enum AudioStatus { 49 Idle, 50 Playing, 51} 52 53/// Network connection state, sent from the network task to the LED task. 54#[derive(Debug, Clone, Copy, PartialEq, Eq)] 55pub enum NetStatus { 56 /// WiFi or MQTT not yet up — initial state and during reconnect attempts. 57 Connecting, 58 /// WiFi + MQTT both connected. 59 Online, 60 /// Was online, lost connection, or never connected and giving up for now. 61 Offline, 62} 63 64/// What the audio / network tasks tell the LED task to display. 65/// 66/// The LED task tracks the most recent `Audio(_)` and `Net(_)` separately and 67/// renders the combined color from a 2-axis lookup. `Updating` and `Error` 68/// override both; `PressFlash` is an overlay that brightens whatever is 69/// currently shown. 70#[derive(Debug, Clone, Copy, PartialEq, Eq)] 71pub enum LedSignal { 72 /// Audio task reporting current playback state. 73 Audio(AudioStatus), 74 /// Network task reporting current connection state. 75 Net(NetStatus), 76 /// Brief brighter flash on top of whatever's currently being shown. 77 PressFlash, 78 /// OTA download in progress — overrides everything else with a magenta 79 /// pulse so it's visually obvious the device is mid-update. 80 Updating, 81 /// OTA download finished (either success or failure). Clears the 82 /// `Updating` override so the LED falls back to the audio/net axes. 83 /// On success the device reboots immediately, so this primarily exists 84 /// for the failure path (so the LED doesn't stay stuck magenta). 85 UpdateDone, 86 /// Something's broken — slow red blink. Reserved for unrecoverable 87 /// failures (I2S init, etc.); network outages are just `Net(Offline)`. 88 Error, 89} 90 91/// A snapshot of the audio task's state — what gets published to the 92/// `nightstand/<mac>/state` MQTT topic. 93#[derive(Debug, Clone, Copy, PartialEq, Eq)] 94pub struct StateSnapshot { 95 pub playing: bool, 96 pub volume_pct: u8, 97} 98 99/// What the coordinator and audio task send to the network task for outbound 100/// publication. The network task is the gatekeeper: when offline, button 101/// events for `Short` are translated into a local `AudioCommand::Toggle`; 102/// state snapshots are cached for republish on reconnect. 103#[derive(Debug, Clone, Copy)] 104pub enum OutboundEvent { 105 Button(ButtonEvent), 106 State(StateSnapshot), 107}