Compare commits

..

No commits in common. "929985c64af0a69db30c89e3c03d22294fc0935c" and "f26e66d68796bcd3e391a36100c12c3bb9fa210a" have entirely different histories.

12 changed files with 35 additions and 124 deletions

BIN
Cargo.lock generated

Binary file not shown.

View file

@ -13,7 +13,6 @@ 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"

View file

@ -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;
@ -67,12 +67,12 @@ impl Period {
let start_before_end = self.start.lt(&self.end); let start_before_end = self.start.lt(&self.end);
match (start_after_now, end_after_now, start_before_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, 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 (false, false, false) => true, // both before now; end before start means "inversed" period around now
(true, false, _) => false, // only start after now (true, false, _) => false, // only start after now
(false, true, _) => true, // only end after now (false, true, _) => true, // only end after now
(true, true, true) => false, // both after now but start first (true, true, true) => false, // both after now but start first
(true, true, false) => true, // both after now but end first (true, true, false) => true, // both after now but end first
} }
} }

View file

@ -47,9 +47,7 @@ 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) => { EmgauwaError::Connection(uid) => format!("unable to connect to controller with uid: {}", 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),
} }

View file

@ -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::{EmgauwaNow, RelayState, RelayStates}; use crate::types::RelayStates;
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)] #[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
pub struct Controller { pub struct Controller {
@ -57,20 +57,19 @@ impl Controller {
self.relays self.relays
.iter_mut() .iter_mut()
.zip(relay_states.iter()) .zip(relay_states.iter())
.for_each(|(relay, state)| relay.apply_state(state)); .for_each(|(relay, is_on)| {
relay.is_on = *is_on;
});
} }
pub fn get_relay_states(&self) -> RelayStates { pub fn get_relay_states(&self) -> RelayStates {
self.relays.iter().map(RelayState::from).collect() self.relays.iter().map(|r| r.is_on).collect()
} }
pub fn check_next_time(&mut self, now: &EmgauwaNow) -> Option<NaiveTime> { pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
self.relays self.relays
.iter_mut() .iter()
.filter_map(|r| { .filter_map(|r| r.active_schedule.get_next_time(now))
r.reload_active_schedule(now.weekday);
r.active_schedule.get_next_time(&now.time)
})
.min() .min()
} }
@ -81,8 +80,6 @@ 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(())
} }

View file

@ -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, DbSchedule}; use crate::db::{DbJunctionRelaySchedule, DbMacroAction};
use crate::errors::{DatabaseError, EmgauwaError}; use crate::errors::{DatabaseError, EmgauwaError};
use crate::models::{FromDbModel, Relay}; use crate::models::{FromDbModel, Relay, Schedule};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MacroAction { pub struct MacroAction {
pub schedule: DbSchedule, pub schedule: Schedule,
pub relay: Relay, pub relay: Relay,
pub weekday: i64, pub weekday: i64,
} }
@ -30,7 +30,8 @@ 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 = block_on(db_model.get_schedule(conn))?; let schedule_db = 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)?;
@ -47,7 +48,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, self.weekday) DbJunctionRelaySchedule::set_schedule(conn, &self.relay.r, &self.schedule.s, self.weekday)
.await?; .await?;
Ok(()) Ok(())
} }

View file

@ -9,8 +9,7 @@ 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, RelayState, Weekday}; use crate::types::EmgauwaUid;
use crate::utils;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Relay { pub struct Relay {
@ -20,18 +19,12 @@ 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 {
@ -65,11 +58,9 @@ 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(),
}) })
} }
} }
@ -78,9 +69,16 @@ 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)?;
self.reload_active_schedule(utils::get_weekday()); Ok(())
}
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(())
} }
@ -105,31 +103,4 @@ 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());
}
}
} }

View file

@ -1,26 +0,0 @@
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()
}
}

View file

@ -1,13 +1,9 @@
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};
@ -18,6 +14,8 @@ 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 {

View file

@ -1,22 +0,0 @@
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
}
}
}

View file

@ -23,12 +23,7 @@ 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>,
#[serde( pub active_schedule: Option<RequestScheduleId>,
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>>,
} }

View file

@ -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.is_on { relay_debug.push_str(match state {
Some(true) => "+", Some(true) => "+",
Some(false) => "-", Some(false) => "-",
None => "?", None => "?",