Can set forced state to relays
This commit is contained in:
		| @@ -25,19 +25,56 @@ impl DeviceState { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Default, Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] | ||||
| #[serde(tag = "type")] | ||||
| pub enum RelayForcedState { | ||||
|     #[default] | ||||
|     None, | ||||
|     Off { | ||||
|         until: u64, | ||||
|     }, | ||||
|     On { | ||||
|         until: u64, | ||||
|     }, | ||||
| } | ||||
|  | ||||
| #[derive(Default, Clone)] | ||||
| pub struct RelayState { | ||||
|     on: bool, | ||||
|     since: usize, | ||||
|     forced_state: RelayForcedState, | ||||
| } | ||||
|  | ||||
| impl RelayState { | ||||
|     /// Get actual forced state (returns None if state is expired) | ||||
|     pub fn actual_forced_state(&self) -> RelayForcedState { | ||||
|         match self.forced_state { | ||||
|             RelayForcedState::Off { until } if until > time_secs() => { | ||||
|                 RelayForcedState::Off { until } | ||||
|             } | ||||
|             RelayForcedState::On { until } if until > time_secs() => RelayForcedState::On { until }, | ||||
|             _ => RelayForcedState::None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn is_on(&self) -> bool { | ||||
|         self.on | ||||
|         let forced_state = self.actual_forced_state(); | ||||
|         (self.on || matches!(forced_state, RelayForcedState::On { .. })) | ||||
|             && !matches!(forced_state, RelayForcedState::Off { .. }) | ||||
|     } | ||||
|  | ||||
|     fn is_off(&self) -> bool { | ||||
|         !self.on | ||||
|         !self.is_on() | ||||
|     } | ||||
|  | ||||
|     /// Check if relay state is enforced | ||||
|     pub fn is_forced(&self) -> bool { | ||||
|         self.actual_forced_state() != RelayForcedState::None | ||||
|     } | ||||
|  | ||||
|     pub fn set_forced(&mut self, s: RelayForcedState) { | ||||
|         self.since = time_secs() as usize; | ||||
|         self.forced_state = s; | ||||
|     } | ||||
|  | ||||
|     pub fn state_for(&self) -> usize { | ||||
| @@ -146,7 +183,11 @@ impl EnergyEngine { | ||||
|                     r.name, | ||||
|                     r.consumption, | ||||
|                     format!("{} / {}", r.minimal_downtime, r.minimal_uptime), | ||||
|                     status.is_on().to_string(), | ||||
|                     status.is_on().to_string() | ||||
|                         + match status.is_forced() { | ||||
|                             true => " (Forced)", | ||||
|                             false => "", | ||||
|                         }, | ||||
|                     status.since, | ||||
|                     match dev_online { | ||||
|                         true => "Online", | ||||
| @@ -192,19 +233,28 @@ impl EnergyEngine { | ||||
|  | ||||
|         let mut new_relays_state = self.relays_state.clone(); | ||||
|  | ||||
|         // Forcefully turn off relays that belongs to offline devices | ||||
|         // Forcefully turn off disabled relays | ||||
|         for d in devices { | ||||
|             if !self.device_state(&d.id).is_online() { | ||||
|                 for r in &d.relays { | ||||
|             for r in &d.relays { | ||||
|                 if !r.enabled || !d.enabled { | ||||
|                     new_relays_state.get_mut(&r.id).unwrap().on = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Forcefully turn off disabled relays | ||||
|         // Apply forced relays state | ||||
|         for d in devices { | ||||
|             for r in &d.relays { | ||||
|                 if !r.enabled || !d.enabled { | ||||
|                 if self.relay_state(r.id).is_forced() { | ||||
|                     new_relays_state.get_mut(&r.id).unwrap().on = self.relay_state(r.id).is_on(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Forcefully turn off relays that belongs to offline devices | ||||
|         for d in devices { | ||||
|             if !self.device_state(&d.id).is_online() { | ||||
|                 for r in &d.relays { | ||||
|                     new_relays_state.get_mut(&r.id).unwrap().on = false; | ||||
|                 } | ||||
|             } | ||||
| @@ -216,7 +266,9 @@ impl EnergyEngine { | ||||
|  | ||||
|             for d in devices { | ||||
|                 for r in &d.relays { | ||||
|                     if new_relays_state.get(&r.id).unwrap().is_off() { | ||||
|                     if new_relays_state.get(&r.id).unwrap().is_off() | ||||
|                         || new_relays_state.get(&r.id).unwrap().is_forced() | ||||
|                     { | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
| @@ -240,7 +292,7 @@ impl EnergyEngine { | ||||
|             for d in devices { | ||||
|                 for r in &d.relays { | ||||
|                     let state = new_relays_state.get(&r.id).unwrap(); | ||||
|                     if state.is_off() { | ||||
|                     if state.is_off() || state.is_forced() { | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
| @@ -271,7 +323,9 @@ impl EnergyEngine { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 if new_relays_state.get(&r.id).unwrap().is_on() { | ||||
|                 if new_relays_state.get(&r.id).unwrap().is_on() | ||||
|                     || new_relays_state.get(&r.id).unwrap().is_forced() | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
| @@ -298,7 +352,7 @@ impl EnergyEngine { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Order relays | ||||
|         // Order relays to select the ones with the most elevated priorities | ||||
|         let mut ordered_relays = devices | ||||
|             .iter() | ||||
|             .filter(|d| self.device_state(&d.id).is_online() && d.enabled) | ||||
| @@ -308,10 +362,13 @@ impl EnergyEngine { | ||||
|         ordered_relays.sort_by_key(|r| r.priority); | ||||
|         ordered_relays.reverse(); | ||||
|  | ||||
|         // Select relays to start, starting with those with highest priorities | ||||
|         loop { | ||||
|             let mut changed = false; | ||||
|             for relay in &ordered_relays { | ||||
|                 if new_relays_state.get(&relay.id).unwrap().is_on() { | ||||
|                 if new_relays_state.get(&relay.id).unwrap().is_on() | ||||
|                     || new_relays_state.get(&relay.id).unwrap().is_forced() | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user