Send color commands to pi from actix; add string to Rgb parser

This commit is contained in:
Austen Adler 2021-08-08 15:24:40 -04:00
parent 09ac4e37fd
commit 2ce2b09ad7
4 changed files with 58 additions and 8 deletions

View File

@ -10,6 +10,7 @@ ws2818-rgb-led-spi-driver = { path = "lib-ws2818-rgb-led-spi-driver/" }
serde = {version = "1.0", features = ["derive"]} serde = {version = "1.0", features = ["derive"]}
actix-web = {version = "3", default_features = false} actix-web = {version = "3", default_features = false}
rust-embed="6.0.0" rust-embed="6.0.0"
hex = "0.4.3"
[target.armv7-unknown-linux-gnueabihf] [target.armv7-unknown-linux-gnueabihf]
linker = "armv7-unknown-linux-gnueabihf" linker = "armv7-unknown-linux-gnueabihf"

View File

@ -1,3 +1,7 @@
use hex;
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub struct Rgb(pub u8, pub u8, pub u8); pub struct Rgb(pub u8, pub u8, pub u8);
impl Rgb { impl Rgb {
@ -12,6 +16,36 @@ impl Rgb {
// ) // )
// } // }
} }
impl FromStr for Rgb {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let [r, g, b] = s.split(" ").collect::<Vec<&str>>().as_slice() {
return Ok(Rgb(r.parse::<u8>()?, g.parse::<u8>()?, b.parse::<u8>()?));
}
hex::decode(
s.trim_start_matches('#')
.trim_start_matches("0x")
.trim_start_matches("0X"),
)
.map_err(|_| ())
.and_then(|v| {
Ok(Rgb(
*v.get(0).ok_or(())?,
*v.get(1).ok_or(())?,
*v.get(2).ok_or(())?,
))
})
.or_else(|_| {
// TODO: Return a proper error here
let color_value = s.parse::<u8>()?;
Ok(Rgb(color_value, color_value, color_value))
})
}
}
#[allow(dead_code)] #[allow(dead_code)]
pub const BLACK: Rgb = Rgb(0, 0, 0); pub const BLACK: Rgb = Rgb(0, 0, 0);
#[allow(dead_code)] #[allow(dead_code)]

View File

@ -55,12 +55,13 @@ fn main() -> Result<(), ProgramError> {
}); });
// I do not care if the console ui crashes // I do not care if the console ui crashes
let (g, h) = (tx.clone(), tx.clone());
let _console_ui_handle = let _console_ui_handle =
thread::spawn(move || -> Result<(), ProgramError> { console_ui_loop(&tx) }); thread::spawn(move || -> Result<(), ProgramError> { console_ui_loop(&g) });
// I do not care if the web ui crashes // I do not care if the web ui crashes
let _web_ui_handle = thread::spawn(move || -> Result<(), io::Error> { let _web_ui_handle = thread::spawn(move || -> Result<(), io::Error> {
webui::start() webui::start(h)
// TODO: Do not join -- this is just because we are running on a computer with no spi env // TODO: Do not join -- this is just because we are running on a computer with no spi env
}) })
.join()?; .join()?;

View File

@ -1,7 +1,14 @@
use crate::color::Rgb;
use crate::pattern;
use crate::strip;
use actix_web::web::Form; use actix_web::web::Form;
use actix_web::{get, post, web, App, HttpRequest, HttpServer, Responder}; use actix_web::{get, post, web, App, HttpRequest, HttpServer, Responder};
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use serde::Deserialize; use serde::Deserialize;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;
// TODO: Pre-compute binary somehow? So do not have to unwrap // TODO: Pre-compute binary somehow? So do not have to unwrap
#[derive(RustEmbed)] #[derive(RustEmbed)]
@ -9,7 +16,7 @@ use serde::Deserialize;
struct Asset; struct Asset;
struct AppState { struct AppState {
app_name: String, strip_tx: Arc<Mutex<Sender<strip::Message>>>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -19,24 +26,31 @@ struct ColorForm {
#[post("/setcolor")] #[post("/setcolor")]
async fn set_color(data: web::Data<AppState>, params: Form<ColorForm>) -> impl Responder { async fn set_color(data: web::Data<AppState>, params: Form<ColorForm>) -> impl Responder {
data.strip_tx
.lock()
.unwrap()
.send(strip::Message::ChangePattern(Box::new(
pattern::Solid::new(Rgb::from_str(&params.color).unwrap()),
)))
.unwrap();
format!("{:?}", params) format!("{:?}", params)
} }
#[get("/")] #[get("/")]
async fn test(data: web::Data<AppState>, req: HttpRequest) -> impl Responder { async fn index(_data: web::Data<AppState>, _req: HttpRequest) -> impl Responder {
// TODO: This is probably the ugliest possible way to do it. Make this better // TODO: This is probably the ugliest possible way to do it. Make this better
String::from_utf8((&Asset::get("index.html").unwrap().data).to_vec()).unwrap() String::from_utf8((&Asset::get("index.html").unwrap().data).to_vec()).unwrap()
} }
#[actix_web::main] #[actix_web::main]
pub async fn start() -> std::io::Result<()> { pub async fn start(tx: Sender<strip::Message>) -> std::io::Result<()> {
println!("Starting webui"); println!("Starting webui");
HttpServer::new(|| { HttpServer::new(move || {
App::new() App::new()
.data(AppState { .data(AppState {
app_name: String::from("abawse"), strip_tx: Arc::new(Mutex::new(tx.clone())),
}) })
.service(test) .service(index)
.service(set_color) .service(set_color)
// App::new() // App::new()
// .route("/", web::get().to(greet)) // .route("/", web::get().to(greet))