Working app

This commit is contained in:
Austen Adler 2024-04-21 21:44:09 -04:00
parent dd978179df
commit 058a076414
16 changed files with 123 additions and 28 deletions

1
.cargo/config.toml Symbolic link
View File

@ -0,0 +1 @@
../config.toml

View File

@ -195,6 +195,7 @@ impl Parameters {
}
pub trait Pattern: std::fmt::Debug + Send + Sync {
fn get_name(&self) -> &'static str;
fn init(&mut self, num_lights: u16) -> PatternResult<()>;
fn step(&mut self) -> PatternResult<bool>;
fn get_strip(&self) -> ColorIterator;

View File

@ -50,6 +50,9 @@ impl CarRainbow {
}
}
impl Pattern for CarRainbow {
fn get_name(&self) -> &'static str {
"CarRainbow"
}
fn step(&mut self) -> PatternResult<bool> {
self.lights_buf.rotate_left(1);
// TODO: Not sure if we should go forward or backwards

View File

@ -71,6 +71,9 @@ impl Collide {
}
}
impl Pattern for Collide {
fn get_name(&self) -> &'static str {
"Collide"
}
fn step(&mut self) -> PatternResult<bool> {
// TODO: Better range storage
// Set the left and right color

View File

@ -74,6 +74,9 @@ impl CustomVisualizer {
}
impl Pattern for CustomVisualizer {
fn get_name(&self) -> &'static str {
"CustomVisualizer"
}
fn step(&mut self) -> PatternResult<bool> {
if let Some(c) = &self.cava {
let reading = c

View File

@ -47,6 +47,9 @@ impl Fade {
}
}
impl Pattern for Fade {
fn get_name(&self) -> &'static str {
"Fade"
}
fn step(&mut self) -> PatternResult<bool> {
if self.direction {
if self.step == 254 {

View File

@ -59,6 +59,9 @@ impl Flashing {
}
impl Pattern for Flashing {
fn get_name(&self) -> &'static str {
"Flashing"
}
fn step(&mut self) -> PatternResult<bool> {
self.step = self.step.wrapping_add(1).rem_euclid(self.tick_rate);
if self.step != 0 {

View File

@ -48,6 +48,9 @@ impl MovingPixel {
}
impl Pattern for MovingPixel {
fn get_name(&self) -> &'static str {
"MovingPixel"
}
fn step(&mut self) -> PatternResult<bool> {
let len = self.num_lights;
self.lights_buf.swap(

View File

@ -63,6 +63,9 @@ impl MovingRainbow {
}
}
impl Pattern for MovingRainbow {
fn get_name(&self) -> &'static str {
"MovingRainbow"
}
fn step(&mut self) -> PatternResult<bool> {
if self.forward {
self.lights_buf.rotate_left(1);

View File

@ -75,6 +75,9 @@ impl Orb {
}
}
impl Pattern for Orb {
fn get_name(&self) -> &'static str {
"Orb"
}
fn step(&mut self) -> PatternResult<bool> {
if !self.bounces {
// If we don't bounce, then just wrap and we're done

View File

@ -64,6 +64,9 @@ impl Slide {
}
impl Pattern for Slide {
fn get_name(&self) -> &'static str {
"Slide"
}
fn step(&mut self) -> PatternResult<bool> {
self.step = self.step.wrapping_add(1);
if self.step.rem_euclid(self.speed as usize) != 0 {

View File

@ -43,6 +43,9 @@ impl Solid {
}
}
impl Pattern for Solid {
fn get_name(&self) -> &'static str {
"Solid"
}
fn step(&mut self) -> PatternResult<bool> {
let ret = !self.has_run;
self.has_run = true;

View File

@ -42,6 +42,9 @@ impl Visualizer {
}
impl Pattern for Visualizer {
fn get_name(&self) -> &'static str {
"Visualizer"
}
fn step(&mut self) -> PatternResult<bool> {
if let Some(c) = &self.cava {
let reading = c

View File

@ -7,6 +7,7 @@ use crate::{
#[derive(Debug)]
pub enum Message {
ClearLights,
TurnOn(Option<String>),
ChangePattern(Box<dyn Pattern + Send + Sync>),
SetNumLights(u16),
SetTickTime(u64),
@ -17,22 +18,22 @@ pub enum Message {
#[derive(Clone, Debug)]
pub struct State {
pub on: bool,
pub pattern: Option<String>,
pub pattern: String,
// brightnes: u8,
pub color: Rgb,
// Off,
// Pattern
}
impl Default for State {
fn default() -> Self {
Self {
on: false,
pattern: None,
color: color::BLACK,
}
}
}
// impl Default for State {
// fn default() -> Self {
// Self {
// on: false,
// pattern: None,
// color: color::BLACK,
// }
// }
// }
// impl Debug for Message {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@ -3,7 +3,7 @@ use anyhow::{Context as _, Result};
use common::{
color::{self, Gradient, Rgb},
error::ProgramError,
pattern::{MovingRainbow, Solid, SolidParams},
pattern::{MovingRainbow, Parameters, Solid, SolidParams},
MqttConfig,
};
use homeassistant_mqtt_discovery::{
@ -150,7 +150,7 @@ impl Mqtt {
}
}
InternalMessage::OutboundStatePacket(p) => {
let state_msg = self.gen_state_message(&p);
let state_msg = self.gen_state_message(p);
info!("Sending state message: {:?}", state_msg);
@ -163,7 +163,7 @@ impl Mqtt {
false,
serde_json::to_vec(&state_msg).unwrap(),
)
.context("Sending initial autodiscovery")
.context("Sending state change")
{
error!("{e:?}");
}
@ -263,7 +263,12 @@ impl Mqtt {
..Common::default()
},
name: Some(FRIENDLY_NAME.to_string()),
effect_list: Some(vec!["Rainbow".into()]),
effect_list: Some(
Parameters::get_names()
.iter()
.map(|s| s.to_string())
.collect(),
),
brightness: Some(false),
effect: Some(true),
supported_color_modes: Some(vec![light::ColorMode::Rgb]),
@ -272,7 +277,7 @@ impl Mqtt {
}
}
fn gen_state_message(&self, state: &strip::State) -> light::JsonIncoming {
fn gen_state_message(&self, state: strip::State) -> light::JsonIncoming {
// "<discovery_prefix>/device_trigger/[<node_id>/]<object_id>/config",
// homeassistant/device_trigger/0x90fd9ffffedf1266/action_arrow_left_click/config
light::JsonIncoming {
@ -285,7 +290,7 @@ impl Mqtt {
b: Some(state.color.2 as usize),
..IncomingColor::default()
}),
effect: state.pattern.clone(),
effect: Some(state.pattern),
state: Some(
(if state.on {
light::STATUS_DEFAULT_LIGHT_ON
@ -311,11 +316,11 @@ fn build_strip_tx_msg(command: &JsonIncoming) -> Option<strip::Message> {
return Some(Message::ClearLights);
}
if let Some(effect) = &command.effect
&& effect == "Rainbow"
{
return Some(Message::ChangePattern(Box::new(MovingRainbow::default())));
}
// if let Some(effect) = &command.effect
// && effect == "Rainbow"
// {
// return Some(Message::ChangePattern(Box::new(MovingRainbow::default())));
// }
if command.effect.is_none()
&& let Some(color) = &command.color
@ -336,6 +341,14 @@ fn build_strip_tx_msg(command: &JsonIncoming) -> Option<strip::Message> {
}))));
}
if let Some(state) = &command.state
&& state == light::STATUS_DEFAULT_LIGHT_ON
{
return Some(Message::TurnOn(
command.effect.as_ref().map(|s| s.to_string()),
));
}
error!("Not able to parse input as a command: {command:?}");
None
}

View File

@ -21,6 +21,7 @@ pub struct LedStrip {
pub adapter: Box<dyn Ws28xxAdapter>,
pub config: Config,
pub pattern: Box<dyn Pattern + Send + Sync>,
pub state: common::strip::State,
}
impl LedStrip {
@ -49,10 +50,20 @@ impl LedStrip {
}))
});
let state = common::strip::State {
on: true,
pattern: pattern.get_name().to_string(),
// brightnes: u8,
color: color::WHITE,
// Off,
// Pattern
};
let mut ret = Self {
adapter,
config,
pattern,
state,
};
ret.set_num_lights(num_lights);
@ -138,6 +149,11 @@ impl LedStrip {
}
}
// pub fn set_state(&self) {
// // let mut state = common::strip::State::default();
// }
pub fn strip_loop(
&mut self,
message_tx: &Sender<common::Message>,
@ -146,8 +162,7 @@ impl LedStrip {
strip_terminated: Sender<()>,
) -> Result<(), ProgramError> {
let mut exit = false;
let mut state = common::strip::State::default();
let _ = state_tx.send(state.clone());
let _ = state_tx.send(self.state.clone());
loop {
let target_time = Instant::now().add(Duration::from_millis(self.config.tick_time_ms));
@ -160,8 +175,9 @@ impl LedStrip {
}));
if pat.init(self.pattern_num_lights()).is_ok() {
self.pattern = pat;
state.on = false;
let _ = state_tx.send(state.clone());
self.state.pattern = self.pattern.get_name().to_string();
self.state.on = false;
let _ = state_tx.send(self.state.clone());
info!("Cleared lights");
} else {
let _result = message_tx.send(common::Message::String(format!(
@ -177,9 +193,9 @@ impl LedStrip {
self.pattern = pat;
info!("Changed pattern");
state.on = true;
state.pattern = Some(format!("Rainbow"));
let _ = state_tx.send(state.clone());
self.state.on = true;
self.state.pattern = self.pattern.get_name().to_string();
let _ = state_tx.send(self.state.clone());
}
Err(e) => {
let _result = message_tx.send(common::Message::String(format!(
@ -187,6 +203,36 @@ impl LedStrip {
)));
}
},
Message::TurnOn(pattern_name) => {
// It's already on
if self.state.on {
continue;
}
if let Err(e) = self.pattern.cleanup() {
error!("Error cleaning up old pattern: {e:?}");
}
// Parameters::from_str(pattern_name)
let mut pat = pattern_name
.and_then(|p| pattern::Parameters::from_str(&p).ok())
.map(|p| p.to_pattern())
.unwrap_or_else(|| {
self.state.color = color::WHITE;
Box::new(pattern::Solid::new(&pattern::SolidParams {
color: color::WHITE,
}))
});
if pat.init(self.pattern_num_lights()).is_ok() {
self.pattern = pat;
self.state.pattern = self.pattern.get_name().to_string();
self.state.on = true;
let _ = state_tx.send(self.state.clone());
info!("Turned on");
}
}
Message::SetNumLights(num_lights) => {
self.set_num_lights(num_lights);
}