Compare commits
3 commits
f26e66d687
...
929985c64a
Author | SHA1 | Date | |
---|---|---|---|
929985c64a | |||
473832f58a | |||
9326b66007 |
12 changed files with 124 additions and 35 deletions
BIN
Cargo.lock
generated
BIN
Cargo.lock
generated
Binary file not shown.
|
@ -13,6 +13,7 @@ actix-web-actors = "4.2"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
serde_with = "3.8"
|
||||||
|
|
||||||
simple_logger = "5.0"
|
simple_logger = "5.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use chrono::{NaiveTime, Timelike};
|
use chrono::{NaiveTime, Timelike};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{Decode, Encode, Sqlite, Type};
|
|
||||||
use sqlx::database::HasArguments;
|
use sqlx::database::HasArguments;
|
||||||
use sqlx::encode::IsNull;
|
use sqlx::encode::IsNull;
|
||||||
use sqlx::error::BoxDynError;
|
use sqlx::error::BoxDynError;
|
||||||
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
|
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
|
||||||
|
use sqlx::{Decode, Encode, Sqlite, Type};
|
||||||
|
|
||||||
use crate::db::DbPeriods;
|
use crate::db::DbPeriods;
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,9 @@ impl From<&EmgauwaError> for String {
|
||||||
EmgauwaError::Database(err) => String::from(err),
|
EmgauwaError::Database(err) => String::from(err),
|
||||||
EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
|
EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
|
||||||
EmgauwaError::Internal(_) => String::from("internal error"),
|
EmgauwaError::Internal(_) => String::from("internal error"),
|
||||||
EmgauwaError::Connection(uid) => format!("unable to connect to controller with uid: {}", uid),
|
EmgauwaError::Connection(uid) => {
|
||||||
|
format!("unable to connect to controller with uid: {}", uid)
|
||||||
|
}
|
||||||
EmgauwaError::Other(err) => format!("other error: {}", err),
|
EmgauwaError::Other(err) => format!("other error: {}", err),
|
||||||
EmgauwaError::Hardware(err) => format!("hardware error: {}", err),
|
EmgauwaError::Hardware(err) => format!("hardware error: {}", err),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use sqlx::Sqlite;
|
||||||
use crate::db::DbController;
|
use crate::db::DbController;
|
||||||
use crate::errors::{DatabaseError, EmgauwaError};
|
use crate::errors::{DatabaseError, EmgauwaError};
|
||||||
use crate::models::{convert_db_list_cache, FromDbModel, Relay};
|
use crate::models::{convert_db_list_cache, FromDbModel, Relay};
|
||||||
use crate::types::RelayStates;
|
use crate::types::{EmgauwaNow, RelayState, RelayStates};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
|
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
|
@ -57,19 +57,20 @@ impl Controller {
|
||||||
self.relays
|
self.relays
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(relay_states.iter())
|
.zip(relay_states.iter())
|
||||||
.for_each(|(relay, is_on)| {
|
.for_each(|(relay, state)| relay.apply_state(state));
|
||||||
relay.is_on = *is_on;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_relay_states(&self) -> RelayStates {
|
pub fn get_relay_states(&self) -> RelayStates {
|
||||||
self.relays.iter().map(|r| r.is_on).collect()
|
self.relays.iter().map(RelayState::from).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
pub fn check_next_time(&mut self, now: &EmgauwaNow) -> Option<NaiveTime> {
|
||||||
self.relays
|
self.relays
|
||||||
.iter()
|
.iter_mut()
|
||||||
.filter_map(|r| r.active_schedule.get_next_time(now))
|
.filter_map(|r| {
|
||||||
|
r.reload_active_schedule(now.weekday);
|
||||||
|
r.active_schedule.get_next_time(&now.time)
|
||||||
|
})
|
||||||
.min()
|
.min()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +81,8 @@ impl Controller {
|
||||||
.find(|r| r.r.number == relay_num)
|
.find(|r| r.r.number == relay_num)
|
||||||
.ok_or(EmgauwaError::Other(String::from("Relay not found")))?;
|
.ok_or(EmgauwaError::Other(String::from("Relay not found")))?;
|
||||||
|
|
||||||
|
log::debug!("Pulsing relay {} until {:?}", relay_num, until);
|
||||||
|
|
||||||
relay.pulsing = Some(until);
|
relay.pulsing = Some(until);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ use serde_derive::{Deserialize, Serialize};
|
||||||
use sqlx::pool::PoolConnection;
|
use sqlx::pool::PoolConnection;
|
||||||
use sqlx::Sqlite;
|
use sqlx::Sqlite;
|
||||||
|
|
||||||
use crate::db::{DbJunctionRelaySchedule, DbMacroAction};
|
use crate::db::{DbJunctionRelaySchedule, DbMacroAction, DbSchedule};
|
||||||
use crate::errors::{DatabaseError, EmgauwaError};
|
use crate::errors::{DatabaseError, EmgauwaError};
|
||||||
use crate::models::{FromDbModel, Relay, Schedule};
|
use crate::models::{FromDbModel, Relay};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct MacroAction {
|
pub struct MacroAction {
|
||||||
pub schedule: Schedule,
|
pub schedule: DbSchedule,
|
||||||
pub relay: Relay,
|
pub relay: Relay,
|
||||||
pub weekday: i64,
|
pub weekday: i64,
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ impl FromDbModel for MacroAction {
|
||||||
db_model: Self::DbModel,
|
db_model: Self::DbModel,
|
||||||
_cache: Self::DbModelCache,
|
_cache: Self::DbModelCache,
|
||||||
) -> Result<Self, DatabaseError> {
|
) -> Result<Self, DatabaseError> {
|
||||||
let schedule_db = block_on(db_model.get_schedule(conn))?;
|
let schedule = block_on(db_model.get_schedule(conn))?;
|
||||||
let schedule = Schedule::from_db_model(conn, schedule_db)?;
|
|
||||||
|
|
||||||
let relay_db = block_on(db_model.get_relay(conn))?;
|
let relay_db = block_on(db_model.get_relay(conn))?;
|
||||||
let relay = Relay::from_db_model(conn, relay_db)?;
|
let relay = Relay::from_db_model(conn, relay_db)?;
|
||||||
|
@ -48,7 +47,7 @@ impl FromDbModel for MacroAction {
|
||||||
|
|
||||||
impl MacroAction {
|
impl MacroAction {
|
||||||
pub async fn execute(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> {
|
pub async fn execute(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> {
|
||||||
DbJunctionRelaySchedule::set_schedule(conn, &self.relay.r, &self.schedule.s, self.weekday)
|
DbJunctionRelaySchedule::set_schedule(conn, &self.relay.r, &self.schedule, self.weekday)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ use sqlx::Sqlite;
|
||||||
use crate::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule};
|
use crate::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule};
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::models::FromDbModel;
|
use crate::models::FromDbModel;
|
||||||
use crate::types::EmgauwaUid;
|
use crate::types::{EmgauwaUid, RelayState, Weekday};
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Relay {
|
pub struct Relay {
|
||||||
|
@ -19,12 +20,18 @@ pub struct Relay {
|
||||||
pub controller_id: EmgauwaUid,
|
pub controller_id: EmgauwaUid,
|
||||||
pub schedules: Vec<DbSchedule>,
|
pub schedules: Vec<DbSchedule>,
|
||||||
pub active_schedule: DbSchedule,
|
pub active_schedule: DbSchedule,
|
||||||
|
pub override_schedule: Option<DbSchedule>,
|
||||||
pub is_on: Option<bool>,
|
pub is_on: Option<bool>,
|
||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
|
|
||||||
// for internal use only.
|
// for internal use only.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub pulsing: Option<Instant>,
|
pub pulsing: Option<Instant>,
|
||||||
|
#[serde(
|
||||||
|
skip,
|
||||||
|
default = "utils::get_weekday",
|
||||||
|
)]
|
||||||
|
pub override_schedule_weekday: Weekday,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromDbModel for Relay {
|
impl FromDbModel for Relay {
|
||||||
|
@ -58,9 +65,11 @@ impl FromDbModel for Relay {
|
||||||
controller_id,
|
controller_id,
|
||||||
schedules,
|
schedules,
|
||||||
active_schedule,
|
active_schedule,
|
||||||
|
override_schedule: None,
|
||||||
is_on,
|
is_on,
|
||||||
tags,
|
tags,
|
||||||
pulsing: None,
|
pulsing: None,
|
||||||
|
override_schedule_weekday: Weekday::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,16 +78,9 @@ impl Relay {
|
||||||
pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||||
self.r = block_on(self.r.reload(conn))?;
|
self.r = block_on(self.r.reload(conn))?;
|
||||||
self.schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &self.r))?;
|
self.schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &self.r))?;
|
||||||
self.reload_active_schedule(conn)?;
|
|
||||||
|
|
||||||
Ok(())
|
self.reload_active_schedule(utils::get_weekday());
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reload_active_schedule(
|
|
||||||
&mut self,
|
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
|
||||||
) -> Result<(), DatabaseError> {
|
|
||||||
self.active_schedule = block_on(self.r.get_active_schedule(conn))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,4 +105,31 @@ impl Relay {
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reload_active_schedule(&mut self, weekday: Weekday) {
|
||||||
|
if let Some(schedule) = &self.override_schedule {
|
||||||
|
if self.override_schedule_weekday == weekday {
|
||||||
|
self.active_schedule = schedule.clone();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.override_schedule_weekday != weekday {
|
||||||
|
self.override_schedule = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.active_schedule = self.schedules.get(weekday as usize).unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_state(&mut self, state: &RelayState) {
|
||||||
|
self.active_schedule = state.active_schedule.clone();
|
||||||
|
self.override_schedule.clone_from(&state.override_schedule);
|
||||||
|
self.is_on = state.is_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_and_apply_state(&mut self, stated_relays: &[Relay]) {
|
||||||
|
if let Some(stated_relay) = stated_relays.iter().find(|r| r.r.id == self.r.id) {
|
||||||
|
self.apply_state(&stated_relay.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
26
src/types/emgauwa_now.rs
Normal file
26
src/types/emgauwa_now.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use chrono::{Local, NaiveTime, Timelike};
|
||||||
|
|
||||||
|
use crate::types::Weekday;
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
pub struct EmgauwaNow {
|
||||||
|
pub time: NaiveTime,
|
||||||
|
pub instant: Instant,
|
||||||
|
pub weekday: Weekday,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmgauwaNow {
|
||||||
|
pub fn now() -> EmgauwaNow {
|
||||||
|
EmgauwaNow {
|
||||||
|
time: Local::now().time(),
|
||||||
|
instant: Instant::now(),
|
||||||
|
weekday: utils::get_weekday(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn time_in_s(&self) -> u32 {
|
||||||
|
self.time.num_seconds_from_midnight()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,13 @@
|
||||||
|
mod emgauwa_now;
|
||||||
mod emgauwa_uid;
|
mod emgauwa_uid;
|
||||||
mod request;
|
mod request;
|
||||||
mod schedule_uid;
|
mod schedule_uid;
|
||||||
|
mod relay_state;
|
||||||
|
|
||||||
use actix::Message;
|
use actix::Message;
|
||||||
|
pub use emgauwa_now::EmgauwaNow;
|
||||||
pub use emgauwa_uid::EmgauwaUid;
|
pub use emgauwa_uid::EmgauwaUid;
|
||||||
|
pub use relay_state::{RelayState, RelayStates};
|
||||||
pub use request::*;
|
pub use request::*;
|
||||||
pub use schedule_uid::ScheduleUid;
|
pub use schedule_uid::ScheduleUid;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
@ -14,8 +18,6 @@ use crate::models::{Controller, Relay};
|
||||||
|
|
||||||
pub type Weekday = i64;
|
pub type Weekday = i64;
|
||||||
|
|
||||||
pub type RelayStates = Vec<Option<bool>>;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Message)]
|
#[derive(Debug, Serialize, Deserialize, Message)]
|
||||||
#[rtype(result = "Result<(), EmgauwaError>")]
|
#[rtype(result = "Result<(), EmgauwaError>")]
|
||||||
pub enum ControllerWsAction {
|
pub enum ControllerWsAction {
|
||||||
|
|
22
src/types/relay_state.rs
Normal file
22
src/types/relay_state.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use crate::db::DbSchedule;
|
||||||
|
use crate::models::Relay;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct RelayState {
|
||||||
|
pub active_schedule: DbSchedule,
|
||||||
|
pub override_schedule: Option<DbSchedule>,
|
||||||
|
pub is_on: Option<bool>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RelayStates = Vec<RelayState>;
|
||||||
|
|
||||||
|
impl From<&Relay> for RelayState {
|
||||||
|
fn from(relay: &Relay) -> Self {
|
||||||
|
RelayState {
|
||||||
|
active_schedule: relay.active_schedule.clone(),
|
||||||
|
override_schedule: relay.override_schedule.clone(),
|
||||||
|
is_on: relay.is_on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,12 @@ pub struct RequestScheduleUpdate {
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct RequestRelayUpdate {
|
pub struct RequestRelayUpdate {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub active_schedule: Option<RequestScheduleId>,
|
#[serde(
|
||||||
|
default, // <- important for deserialization
|
||||||
|
skip_serializing_if = "Option::is_none", // <- important for serialization
|
||||||
|
with = "::serde_with::rust::double_option",
|
||||||
|
)]
|
||||||
|
pub override_schedule: Option<Option<RequestScheduleId>>,
|
||||||
pub schedules: Option<Vec<RequestScheduleId>>,
|
pub schedules: Option<Vec<RequestScheduleId>>,
|
||||||
pub tags: Option<Vec<String>>,
|
pub tags: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ pub fn get_weekday() -> Weekday {
|
||||||
pub fn printable_relay_states(relay_states: &RelayStates) -> String {
|
pub fn printable_relay_states(relay_states: &RelayStates) -> String {
|
||||||
let mut relay_debug = String::new();
|
let mut relay_debug = String::new();
|
||||||
relay_states.iter().for_each(|state| {
|
relay_states.iter().for_each(|state| {
|
||||||
relay_debug.push_str(match state {
|
relay_debug.push_str(match state.is_on {
|
||||||
Some(true) => "+",
|
Some(true) => "+",
|
||||||
Some(false) => "-",
|
Some(false) => "-",
|
||||||
None => "?",
|
None => "?",
|
||||||
|
|
Loading…
Reference in a new issue