Working app
This commit is contained in:
parent
dd978179df
commit
058a076414
1
.cargo/config.toml
Symbolic link
1
.cargo/config.toml
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../config.toml
|
@ -195,6 +195,7 @@ impl Parameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Pattern: std::fmt::Debug + Send + Sync {
|
pub trait Pattern: std::fmt::Debug + Send + Sync {
|
||||||
|
fn get_name(&self) -> &'static str;
|
||||||
fn init(&mut self, num_lights: u16) -> PatternResult<()>;
|
fn init(&mut self, num_lights: u16) -> PatternResult<()>;
|
||||||
fn step(&mut self) -> PatternResult<bool>;
|
fn step(&mut self) -> PatternResult<bool>;
|
||||||
fn get_strip(&self) -> ColorIterator;
|
fn get_strip(&self) -> ColorIterator;
|
||||||
|
@ -50,6 +50,9 @@ impl CarRainbow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Pattern for CarRainbow {
|
impl Pattern for CarRainbow {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"CarRainbow"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
self.lights_buf.rotate_left(1);
|
self.lights_buf.rotate_left(1);
|
||||||
// TODO: Not sure if we should go forward or backwards
|
// TODO: Not sure if we should go forward or backwards
|
||||||
|
@ -71,6 +71,9 @@ impl Collide {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Pattern for Collide {
|
impl Pattern for Collide {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Collide"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
// TODO: Better range storage
|
// TODO: Better range storage
|
||||||
// Set the left and right color
|
// Set the left and right color
|
||||||
|
@ -74,6 +74,9 @@ impl CustomVisualizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern for CustomVisualizer {
|
impl Pattern for CustomVisualizer {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"CustomVisualizer"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
if let Some(c) = &self.cava {
|
if let Some(c) = &self.cava {
|
||||||
let reading = c
|
let reading = c
|
||||||
|
@ -47,6 +47,9 @@ impl Fade {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Pattern for Fade {
|
impl Pattern for Fade {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Fade"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
if self.direction {
|
if self.direction {
|
||||||
if self.step == 254 {
|
if self.step == 254 {
|
||||||
|
@ -59,6 +59,9 @@ impl Flashing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern for Flashing {
|
impl Pattern for Flashing {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Flashing"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
self.step = self.step.wrapping_add(1).rem_euclid(self.tick_rate);
|
self.step = self.step.wrapping_add(1).rem_euclid(self.tick_rate);
|
||||||
if self.step != 0 {
|
if self.step != 0 {
|
||||||
|
@ -48,6 +48,9 @@ impl MovingPixel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern for MovingPixel {
|
impl Pattern for MovingPixel {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"MovingPixel"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
let len = self.num_lights;
|
let len = self.num_lights;
|
||||||
self.lights_buf.swap(
|
self.lights_buf.swap(
|
||||||
|
@ -63,6 +63,9 @@ impl MovingRainbow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Pattern for MovingRainbow {
|
impl Pattern for MovingRainbow {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"MovingRainbow"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
if self.forward {
|
if self.forward {
|
||||||
self.lights_buf.rotate_left(1);
|
self.lights_buf.rotate_left(1);
|
||||||
|
@ -75,6 +75,9 @@ impl Orb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Pattern for Orb {
|
impl Pattern for Orb {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Orb"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
if !self.bounces {
|
if !self.bounces {
|
||||||
// If we don't bounce, then just wrap and we're done
|
// If we don't bounce, then just wrap and we're done
|
||||||
|
@ -64,6 +64,9 @@ impl Slide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern for Slide {
|
impl Pattern for Slide {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Slide"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
self.step = self.step.wrapping_add(1);
|
self.step = self.step.wrapping_add(1);
|
||||||
if self.step.rem_euclid(self.speed as usize) != 0 {
|
if self.step.rem_euclid(self.speed as usize) != 0 {
|
||||||
|
@ -43,6 +43,9 @@ impl Solid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Pattern for Solid {
|
impl Pattern for Solid {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Solid"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
let ret = !self.has_run;
|
let ret = !self.has_run;
|
||||||
self.has_run = true;
|
self.has_run = true;
|
||||||
|
@ -42,6 +42,9 @@ impl Visualizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern for Visualizer {
|
impl Pattern for Visualizer {
|
||||||
|
fn get_name(&self) -> &'static str {
|
||||||
|
"Visualizer"
|
||||||
|
}
|
||||||
fn step(&mut self) -> PatternResult<bool> {
|
fn step(&mut self) -> PatternResult<bool> {
|
||||||
if let Some(c) = &self.cava {
|
if let Some(c) = &self.cava {
|
||||||
let reading = c
|
let reading = c
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
ClearLights,
|
ClearLights,
|
||||||
|
TurnOn(Option<String>),
|
||||||
ChangePattern(Box<dyn Pattern + Send + Sync>),
|
ChangePattern(Box<dyn Pattern + Send + Sync>),
|
||||||
SetNumLights(u16),
|
SetNumLights(u16),
|
||||||
SetTickTime(u64),
|
SetTickTime(u64),
|
||||||
@ -17,22 +18,22 @@ pub enum Message {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub on: bool,
|
pub on: bool,
|
||||||
pub pattern: Option<String>,
|
pub pattern: String,
|
||||||
// brightnes: u8,
|
// brightnes: u8,
|
||||||
pub color: Rgb,
|
pub color: Rgb,
|
||||||
// Off,
|
// Off,
|
||||||
// Pattern
|
// Pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
// impl Default for State {
|
||||||
fn default() -> Self {
|
// fn default() -> Self {
|
||||||
Self {
|
// Self {
|
||||||
on: false,
|
// on: false,
|
||||||
pattern: None,
|
// pattern: None,
|
||||||
color: color::BLACK,
|
// color: color::BLACK,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// impl Debug for Message {
|
// impl Debug for Message {
|
||||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
@ -3,7 +3,7 @@ use anyhow::{Context as _, Result};
|
|||||||
use common::{
|
use common::{
|
||||||
color::{self, Gradient, Rgb},
|
color::{self, Gradient, Rgb},
|
||||||
error::ProgramError,
|
error::ProgramError,
|
||||||
pattern::{MovingRainbow, Solid, SolidParams},
|
pattern::{MovingRainbow, Parameters, Solid, SolidParams},
|
||||||
MqttConfig,
|
MqttConfig,
|
||||||
};
|
};
|
||||||
use homeassistant_mqtt_discovery::{
|
use homeassistant_mqtt_discovery::{
|
||||||
@ -150,7 +150,7 @@ impl Mqtt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
InternalMessage::OutboundStatePacket(p) => {
|
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);
|
info!("Sending state message: {:?}", state_msg);
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ impl Mqtt {
|
|||||||
false,
|
false,
|
||||||
serde_json::to_vec(&state_msg).unwrap(),
|
serde_json::to_vec(&state_msg).unwrap(),
|
||||||
)
|
)
|
||||||
.context("Sending initial autodiscovery")
|
.context("Sending state change")
|
||||||
{
|
{
|
||||||
error!("{e:?}");
|
error!("{e:?}");
|
||||||
}
|
}
|
||||||
@ -263,7 +263,12 @@ impl Mqtt {
|
|||||||
..Common::default()
|
..Common::default()
|
||||||
},
|
},
|
||||||
name: Some(FRIENDLY_NAME.to_string()),
|
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),
|
brightness: Some(false),
|
||||||
effect: Some(true),
|
effect: Some(true),
|
||||||
supported_color_modes: Some(vec![light::ColorMode::Rgb]),
|
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",
|
// "<discovery_prefix>/device_trigger/[<node_id>/]<object_id>/config",
|
||||||
// homeassistant/device_trigger/0x90fd9ffffedf1266/action_arrow_left_click/config
|
// homeassistant/device_trigger/0x90fd9ffffedf1266/action_arrow_left_click/config
|
||||||
light::JsonIncoming {
|
light::JsonIncoming {
|
||||||
@ -285,7 +290,7 @@ impl Mqtt {
|
|||||||
b: Some(state.color.2 as usize),
|
b: Some(state.color.2 as usize),
|
||||||
..IncomingColor::default()
|
..IncomingColor::default()
|
||||||
}),
|
}),
|
||||||
effect: state.pattern.clone(),
|
effect: Some(state.pattern),
|
||||||
state: Some(
|
state: Some(
|
||||||
(if state.on {
|
(if state.on {
|
||||||
light::STATUS_DEFAULT_LIGHT_ON
|
light::STATUS_DEFAULT_LIGHT_ON
|
||||||
@ -311,11 +316,11 @@ fn build_strip_tx_msg(command: &JsonIncoming) -> Option<strip::Message> {
|
|||||||
return Some(Message::ClearLights);
|
return Some(Message::ClearLights);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(effect) = &command.effect
|
// if let Some(effect) = &command.effect
|
||||||
&& effect == "Rainbow"
|
// && effect == "Rainbow"
|
||||||
{
|
// {
|
||||||
return Some(Message::ChangePattern(Box::new(MovingRainbow::default())));
|
// return Some(Message::ChangePattern(Box::new(MovingRainbow::default())));
|
||||||
}
|
// }
|
||||||
|
|
||||||
if command.effect.is_none()
|
if command.effect.is_none()
|
||||||
&& let Some(color) = &command.color
|
&& 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:?}");
|
error!("Not able to parse input as a command: {command:?}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
60
src/strip.rs
60
src/strip.rs
@ -21,6 +21,7 @@ pub struct LedStrip {
|
|||||||
pub adapter: Box<dyn Ws28xxAdapter>,
|
pub adapter: Box<dyn Ws28xxAdapter>,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub pattern: Box<dyn Pattern + Send + Sync>,
|
pub pattern: Box<dyn Pattern + Send + Sync>,
|
||||||
|
pub state: common::strip::State,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LedStrip {
|
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 {
|
let mut ret = Self {
|
||||||
adapter,
|
adapter,
|
||||||
config,
|
config,
|
||||||
pattern,
|
pattern,
|
||||||
|
state,
|
||||||
};
|
};
|
||||||
ret.set_num_lights(num_lights);
|
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(
|
pub fn strip_loop(
|
||||||
&mut self,
|
&mut self,
|
||||||
message_tx: &Sender<common::Message>,
|
message_tx: &Sender<common::Message>,
|
||||||
@ -146,8 +162,7 @@ impl LedStrip {
|
|||||||
strip_terminated: Sender<()>,
|
strip_terminated: Sender<()>,
|
||||||
) -> Result<(), ProgramError> {
|
) -> Result<(), ProgramError> {
|
||||||
let mut exit = false;
|
let mut exit = false;
|
||||||
let mut state = common::strip::State::default();
|
let _ = state_tx.send(self.state.clone());
|
||||||
let _ = state_tx.send(state.clone());
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let target_time = Instant::now().add(Duration::from_millis(self.config.tick_time_ms));
|
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() {
|
if pat.init(self.pattern_num_lights()).is_ok() {
|
||||||
self.pattern = pat;
|
self.pattern = pat;
|
||||||
state.on = false;
|
self.state.pattern = self.pattern.get_name().to_string();
|
||||||
let _ = state_tx.send(state.clone());
|
self.state.on = false;
|
||||||
|
let _ = state_tx.send(self.state.clone());
|
||||||
info!("Cleared lights");
|
info!("Cleared lights");
|
||||||
} else {
|
} else {
|
||||||
let _result = message_tx.send(common::Message::String(format!(
|
let _result = message_tx.send(common::Message::String(format!(
|
||||||
@ -177,9 +193,9 @@ impl LedStrip {
|
|||||||
|
|
||||||
self.pattern = pat;
|
self.pattern = pat;
|
||||||
info!("Changed pattern");
|
info!("Changed pattern");
|
||||||
state.on = true;
|
self.state.on = true;
|
||||||
state.pattern = Some(format!("Rainbow"));
|
self.state.pattern = self.pattern.get_name().to_string();
|
||||||
let _ = state_tx.send(state.clone());
|
let _ = state_tx.send(self.state.clone());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let _result = message_tx.send(common::Message::String(format!(
|
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) => {
|
Message::SetNumLights(num_lights) => {
|
||||||
self.set_num_lights(num_lights);
|
self.set_num_lights(num_lights);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user