Add self-creation for controller

This commit is contained in:
Tobias Reisinger 2023-11-25 00:39:44 +01:00
parent d193000aec
commit 4e3df272c3
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
10 changed files with 104 additions and 14 deletions

BIN
Cargo.lock generated

Binary file not shown.

View file

@ -1,4 +1,5 @@
database = "sqlite://emgauwa-controller.sqlite" database = "sqlite://emgauwa-controller.sqlite"
name = "Emgauwa Controller"
[core] [core]
port = 4419 port = 4419
@ -7,3 +8,8 @@ host = "127.0.0.1"
[logging] [logging]
level = "DEBUG" level = "DEBUG"
file = "stdout" file = "stdout"
[[relays]]
driver = "gpio"
pin = 5
inverted = 1

View file

@ -20,4 +20,6 @@ serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
sqlx = { version = "0.7", features = ["sqlite", "runtime-async-std", "macros", "chrono"] }
futures = "0.3" futures = "0.3"

View file

@ -0,0 +1,18 @@
use serde::{Deserialize, Deserializer};
#[derive(Debug, Clone, Copy)]
pub enum Driver {
Gpio,
Piface,
}
impl<'de> Deserialize<'de> for Driver {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
match String::deserialize(deserializer)?.as_str() {
"gpio" => Ok(Driver::Gpio),
"piface" => Ok(Driver::Piface),
_ => Err(serde::de::Error::custom("invalid driver")),
}
}
}

View file

@ -1,19 +1,50 @@
use std::str; use std::str;
use futures::{future, pin_mut, StreamExt}; use futures::{future, pin_mut, SinkExt, StreamExt};
use futures::channel::mpsc; use futures::channel::mpsc;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use tokio_tungstenite::tungstenite::Error; use tokio_tungstenite::tungstenite::Error;
use emgauwa_lib::db; use emgauwa_lib::db;
use emgauwa_lib::db::Controller;
use emgauwa_lib::db::types::ControllerUid;
use crate::settings::Settings;
mod settings; mod settings;
mod driver;
fn create_this_controller(conn: &mut PoolConnection<Sqlite>, settings: &Settings) -> Controller {
futures::executor::block_on(async {
Controller::create(
conn,
&ControllerUid::new(),
&settings.name,
i64::try_from(settings.relays.len()).expect("Too many relays"),
true
).await.expect("Failed to create controller")
})
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let settings = settings::init(); let settings = settings::init();
let _pool = db::init(&settings.database).await; let pool = db::init(&settings.database).await;
let mut conn = pool.acquire().await.unwrap();
let this = Controller::get_all(&mut conn)
.await
.expect("Failed to get controller from database")
.pop()
.unwrap_or_else(|| create_this_controller(&mut conn, &settings));
let this_json = serde_json::to_string(&this).unwrap();
println!("{:?}", this);
println!("{:?}", this_json);
let url = format!( let url = format!(
"ws://{}:{}/api/v1/ws/controllers", "ws://{}:{}/api/v1/ws/controllers",
@ -26,13 +57,14 @@ async fn main() {
let (ws_stream, _) = connect_async(url).await.expect("Failed to connect"); let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
let (write, read) = ws_stream.split(); let (mut write, read) = ws_stream.split();
let stdin_to_ws = stdin_rx.map(Ok).forward(write); write.send(Message::text(this_json)).await.unwrap();
let ws_to_stdout = read.for_each(handle_message); let ws_to_stdout = read.for_each(handle_message);
pin_mut!(stdin_to_ws, ws_to_stdout); ws_to_stdout.await;
future::select(stdin_to_ws, ws_to_stdout).await; //pin_mut!(stdin_to_ws, ws_to_stdout);
//future::select(stdin_to_ws, ws_to_stdout).await;
} }
// Our helper method which will read data from stdin and send it along the // Our helper method which will read data from stdin and send it along the

View file

@ -1,5 +1,6 @@
use emgauwa_lib::{constants, utils}; use emgauwa_lib::{constants, utils};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use crate::driver::Driver;
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(default)] #[serde(default)]
@ -17,6 +18,15 @@ pub struct Logging {
pub file: String, pub file: String,
} }
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
#[allow(unused)]
pub struct Relay {
pub driver: Driver,
pub pin: u8,
pub inverted: bool,
}
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(default)] #[serde(default)]
#[allow(unused)] #[allow(unused)]
@ -24,6 +34,8 @@ pub struct Settings {
pub core: Core, pub core: Core,
pub database: String, pub database: String,
pub logging: Logging, pub logging: Logging,
pub name: String,
pub relays: Vec<Relay>,
} }
impl Default for Settings { impl Default for Settings {
@ -32,6 +44,18 @@ impl Default for Settings {
core: Core::default(), core: Core::default(),
database: String::from("sqlite://emgauwa-controller.sqlite"), database: String::from("sqlite://emgauwa-controller.sqlite"),
logging: Logging::default(), logging: Logging::default(),
name: String::from("Emgauwa Controller"),
relays: Vec::new(),
}
}
}
impl Default for Relay {
fn default() -> Self {
Relay {
driver: Driver::Gpio,
pin: 0,
inverted: false,
} }
} }
} }

View file

@ -8,16 +8,16 @@ use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period; use crate::db::model_utils::Period;
use crate::db::types::ScheduleUid; use crate::db::types::ScheduleUid;
// export for easier/flatter access
pub use crate::db::schedules::{Periods, Schedule};
pub mod errors; pub mod errors;
mod model_utils; mod model_utils;
mod models; mod models;
pub mod schedules; mod schedules;
pub mod tag; pub mod tag;
pub mod types; pub mod types;
pub mod controllers; mod controllers;
pub use controllers::Controller;
pub use schedules::{Periods, Schedule};
static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations" static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"

View file

@ -9,6 +9,12 @@ use uuid::Uuid;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ControllerUid(Uuid); pub struct ControllerUid(Uuid);
impl ControllerUid {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
}
impl Serialize for ControllerUid { impl Serialize for ControllerUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where

View file

@ -25,10 +25,12 @@ impl StreamHandler<Result<Message, ProtocolError>> for ControllerWs {
fn handle(&mut self, msg: Result<Message, ProtocolError>, ctx: &mut Self::Context) { fn handle(&mut self, msg: Result<Message, ProtocolError>, ctx: &mut Self::Context) {
let schedules = futures::executor::block_on(get_schedules(&mut self.pool)).unwrap(); let schedules = futures::executor::block_on(get_schedules(&mut self.pool)).unwrap();
let schedules_json = serde_json::to_string(&schedules).unwrap(); let schedules_json = serde_json::to_string(&schedules).unwrap();
println!("{:?}", msg);
match msg { match msg {
Ok(Message::Ping(msg)) => ctx.pong(&msg), Ok(Message::Ping(msg)) => ctx.pong(&msg),
Ok(Message::Text(_text)) => ctx.text(schedules_json), Ok(Message::Text(text)) => {
println!("Got text: {}", text.to_string());
ctx.text(schedules_json)
},
_ => {} _ => {}
} }
} }

View file

@ -1,4 +1,4 @@
use crate::db::schedules::Schedule; use crate::db::Schedule;
use futures::executor; use futures::executor;
use serde::Serialize; use serde::Serialize;
use sqlx::pool::PoolConnection; use sqlx::pool::PoolConnection;