From 473832f58a258e404d7bba0ca20a3ff58e6ba11c Mon Sep 17 00:00:00 2001 From: Tobias Reisinger Date: Sun, 26 May 2024 22:48:22 +0200 Subject: [PATCH] Rename active_schedule to override_schedule and add EmgauwaNow --- Cargo.lock | Bin 65662 -> 68197 bytes Cargo.toml | 1 + src/db/model_utils.rs | 14 +++++------ src/errors/emgauwa_error.rs | 4 +++- src/models/controller.rs | 26 +++++++++++++------- src/models/relay.rs | 46 +++++++++++++++++++++++++++++------- src/types/emgauwa_now.rs | 26 ++++++++++++++++++++ src/types/mod.rs | 10 +++++++- src/types/request.rs | 7 +++++- src/utils.rs | 2 +- 10 files changed, 108 insertions(+), 28 deletions(-) create mode 100644 src/types/emgauwa_now.rs diff --git a/Cargo.lock b/Cargo.lock index 18d357b90c022e29bfdfbe1da842f26f22088dad..1bee2db4896e2d59a330fecdd6d53870f9dd3ec6 100644 GIT binary patch delta 1302 zcmZvc&ug4T7{_V5t8E%D|gNZc$U2=X$&=NYSw!IPf0;-#XE^URMVHrXwk(0Wq; z072+@>p`RlLO~i|dMO62;HeiCJm|%Oc=hB_#An}h3jwe54m02Rd_T|o??t%#G08g9Pq97fG=sgNh!ov9O>B+(4HErgXG>U2U+Q!a${nyIdXCCW{N>rx2e$kiC*KeE$?^3cXDCvDx+y;U! zoiR##mOW@;gaXD9tB&KBaSs1j8GZkc6d2X&gm7YA*=9Q~t;Sc)Dky(<^ zNvS2Zk|o^)-8_*bV zL5H);&z9-@ph0$I?JG5zk9zmUXu7<6vo+iBJ7BV`V1Hhij|yZI9vN3IY7zqjT}LWO z!e=>8jB6ReNX+y#GU+Hd0ClW9>C^GE<;UIjsqs*XiZ>dC_0e!JET7$(neR3L_T?JH z^!}E=^02}W_h!nkD+_av3SMoz-){EqkaeB7P*!iY+fDkia{qMeQEH>LaRggX=Ss;0 z7yuDDO`UZZnbHg~Ss_tVgW!M>?-Z1_z%V2+7Vp?Y@fy=t>fV>vpE$7}tx2#sTr2PF zE!Mx?dF|jI=iJ>(hbM@~zo2sN?uq)_Z=PzMX@=zhW@?BxoR@9%fZ9qL2_0P)IUq=z u2&hXWDLJN4B6;L3a|*o746P-~5OhXWmafdzKYjOJXEFdpukQa`RsR7EV~j}v delta 120 zcmV-;0EhqOlmz~O1hBmXlRm>4v)u&q8MBWc#~ZV9KEVN##f=xUR6vXcv+qS#7n4g} zVY6;tX$!NNY7GICq-@KR+F%#6kZrCslRm>3vt6QE46`w@kqxuRzHbDxKErkblRm>H av*E=P1hccsX%Um5#ubw=+8(o2+z>7je>W5W diff --git a/Cargo.toml b/Cargo.toml index 30ed02a..464e9b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ actix-web-actors = "4.2" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" +serde_with = "3.8" simple_logger = "5.0" log = "0.4" diff --git a/src/db/model_utils.rs b/src/db/model_utils.rs index e178d8e..db845bc 100644 --- a/src/db/model_utils.rs +++ b/src/db/model_utils.rs @@ -1,10 +1,10 @@ use chrono::{NaiveTime, Timelike}; use serde::{Deserialize, Serialize}; -use sqlx::{Decode, Encode, Sqlite, Type}; use sqlx::database::HasArguments; use sqlx::encode::IsNull; use sqlx::error::BoxDynError; use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef}; +use sqlx::{Decode, Encode, Sqlite, Type}; use crate::db::DbPeriods; @@ -67,12 +67,12 @@ impl Period { let start_before_end = self.start.lt(&self.end); match (start_after_now, end_after_now, start_before_end) { - (false, false, true) => false, // both before now; start before end means "normal" period before now - (false, false, false) => true, // both before now; end before start means "inversed" period around now - (true, false, _) => false, // only start after now - (false, true, _) => true, // only end after now - (true, true, true) => false, // both after now but start first - (true, true, false) => true, // both after now but end first + (false, false, true) => false, // both before now; start before end means "normal" period before now + (false, false, false) => true, // both before now; end before start means "inversed" period around now + (true, false, _) => false, // only start after now + (false, true, _) => true, // only end after now + (true, true, true) => false, // both after now but start first + (true, true, false) => true, // both after now but end first } } diff --git a/src/errors/emgauwa_error.rs b/src/errors/emgauwa_error.rs index f37c38e..a833c78 100644 --- a/src/errors/emgauwa_error.rs +++ b/src/errors/emgauwa_error.rs @@ -47,7 +47,9 @@ impl From<&EmgauwaError> for String { EmgauwaError::Database(err) => String::from(err), EmgauwaError::Uid(_) => String::from("the uid is in a bad format"), 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::Hardware(err) => format!("hardware error: {}", err), } diff --git a/src/models/controller.rs b/src/models/controller.rs index 96d7b00..ebc556a 100644 --- a/src/models/controller.rs +++ b/src/models/controller.rs @@ -10,7 +10,7 @@ use sqlx::Sqlite; use crate::db::DbController; use crate::errors::{DatabaseError, EmgauwaError}; 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)] pub struct Controller { @@ -57,19 +57,29 @@ impl Controller { self.relays .iter_mut() .zip(relay_states.iter()) - .for_each(|(relay, is_on)| { - relay.is_on = *is_on; + .for_each(|(relay, state)| { + relay.active_schedule = state.active_schedule.clone(); + relay.is_on = state.is_on; }); } pub fn get_relay_states(&self) -> RelayStates { - self.relays.iter().map(|r| r.is_on).collect() - } - - pub fn get_next_time(&self, now: &NaiveTime) -> Option { self.relays .iter() - .filter_map(|r| r.active_schedule.get_next_time(now)) + .map(|r| RelayState { + active_schedule: r.active_schedule.clone(), + is_on: r.is_on, + }) + .collect() + } + + pub fn check_next_time(&mut self, now: &EmgauwaNow) -> Option { + self.relays + .iter_mut() + .filter_map(|r| { + r.reload_active_schedule(now.weekday); + r.active_schedule.get_next_time(&now.time) + }) .min() } diff --git a/src/models/relay.rs b/src/models/relay.rs index e6ecd0f..f44b290 100644 --- a/src/models/relay.rs +++ b/src/models/relay.rs @@ -9,7 +9,8 @@ use sqlx::Sqlite; use crate::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule}; use crate::errors::DatabaseError; use crate::models::FromDbModel; -use crate::types::EmgauwaUid; +use crate::types::{EmgauwaUid, Weekday}; +use crate::utils; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Relay { @@ -19,12 +20,23 @@ pub struct Relay { pub controller_id: EmgauwaUid, pub schedules: Vec, pub active_schedule: DbSchedule, + #[serde( + default, // <- important for deserialization + skip_serializing_if = "Option::is_none", // <- important for serialization + with = "::serde_with::rust::double_option", + )] + pub override_schedule: Option>, pub is_on: Option, pub tags: Vec, // for internal use only. #[serde(skip)] pub pulsing: Option, + #[serde( + skip, + default = "utils::get_weekday", + )] + pub override_schedule_weekday: Weekday, } impl FromDbModel for Relay { @@ -58,9 +70,11 @@ impl FromDbModel for Relay { controller_id, schedules, active_schedule, + override_schedule: None, is_on, tags, pulsing: None, + override_schedule_weekday: Weekday::default(), }) } } @@ -69,16 +83,9 @@ impl Relay { pub fn reload(&mut self, conn: &mut PoolConnection) -> Result<(), DatabaseError> { self.r = block_on(self.r.reload(conn))?; 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, - ) -> Result<(), DatabaseError> { - self.active_schedule = block_on(self.r.get_active_schedule(conn))?; Ok(()) } @@ -103,4 +110,25 @@ impl Relay { None => None, } } + + pub fn reload_active_schedule(&mut self, weekday: Weekday) { + if let Some((Some(schedule), schedule_weekday)) = self.unwrap_override_schedule() { + if schedule_weekday == weekday { + self.active_schedule = schedule.clone(); + return; + } + if schedule_weekday != weekday { + self.override_schedule = None; + } + } + + self.active_schedule = self.schedules.get(weekday as usize).unwrap().clone() + } + + pub fn unwrap_override_schedule(&self) -> Option<(&Option, Weekday)> { + if let Some(schedule) = &self.override_schedule { + return Some((schedule, self.override_schedule_weekday)); + } + None + } } diff --git a/src/types/emgauwa_now.rs b/src/types/emgauwa_now.rs new file mode 100644 index 0000000..40f4907 --- /dev/null +++ b/src/types/emgauwa_now.rs @@ -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() + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index dbbfb77..24f3c78 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,8 +1,10 @@ +mod emgauwa_now; mod emgauwa_uid; mod request; mod schedule_uid; use actix::Message; +pub use emgauwa_now::EmgauwaNow; pub use emgauwa_uid::EmgauwaUid; pub use request::*; pub use schedule_uid::ScheduleUid; @@ -14,7 +16,13 @@ use crate::models::{Controller, Relay}; pub type Weekday = i64; -pub type RelayStates = Vec>; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RelayState { + pub active_schedule: DbSchedule, + pub is_on: Option +} + +pub type RelayStates = Vec; #[derive(Debug, Serialize, Deserialize, Message)] #[rtype(result = "Result<(), EmgauwaError>")] diff --git a/src/types/request.rs b/src/types/request.rs index 4956733..d452b31 100644 --- a/src/types/request.rs +++ b/src/types/request.rs @@ -23,7 +23,12 @@ pub struct RequestScheduleUpdate { #[derive(Debug, Serialize, Deserialize)] pub struct RequestRelayUpdate { pub name: Option, - pub active_schedule: Option, + #[serde( + default, // <- important for deserialization + skip_serializing_if = "Option::is_none", // <- important for serialization + with = "::serde_with::rust::double_option", + )] + pub override_schedule: Option>, pub schedules: Option>, pub tags: Option>, } diff --git a/src/utils.rs b/src/utils.rs index e9ee62e..3b20d9a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -103,7 +103,7 @@ pub fn get_weekday() -> Weekday { pub fn printable_relay_states(relay_states: &RelayStates) -> String { let mut relay_debug = String::new(); relay_states.iter().for_each(|state| { - relay_debug.push_str(match state { + relay_debug.push_str(match state.is_on { Some(true) => "+", Some(false) => "-", None => "?",