WIP engine
This commit is contained in:
parent
f0081eb4bf
commit
2262b98952
@ -1,9 +1,11 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use prettytable::{row, Table};
|
||||||
|
|
||||||
use crate::constants;
|
use crate::constants;
|
||||||
use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
|
use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
|
||||||
use crate::energy::consumption::EnergyConsumption;
|
use crate::energy::consumption::EnergyConsumption;
|
||||||
use crate::utils::time_utils::time_secs;
|
use crate::utils::time_utils::time_secs;
|
||||||
use prettytable::{row, Table};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DeviceState {
|
pub struct DeviceState {
|
||||||
@ -26,6 +28,16 @@ pub struct RelayState {
|
|||||||
since: usize,
|
since: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RelayState {
|
||||||
|
fn is_on(&self) -> bool {
|
||||||
|
self.on
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_off(&self) -> bool {
|
||||||
|
!self.on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type RelaysState = HashMap<DeviceRelayID, RelayState>;
|
type RelaysState = HashMap<DeviceRelayID, RelayState>;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -35,10 +47,37 @@ pub struct EnergyEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceRelay {
|
impl DeviceRelay {
|
||||||
fn relay_has_running_dependencies(&self, s: &RelaysState, devices: &[Device]) -> bool {
|
// Note : this function is not recursive
|
||||||
|
fn has_running_dependencies(&self, s: &RelaysState, devices: &[Device]) -> bool {
|
||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
if r.depends_on.contains(&self.id) && s.get(&r.id).unwrap().on {
|
if r.depends_on.contains(&self.id) && s.get(&r.id).unwrap().is_on() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note : this function is not recursive
|
||||||
|
fn is_missing_dependencies(&self, s: &RelaysState) -> bool {
|
||||||
|
self.depends_on.iter().any(|id| s.get(id).unwrap().is_off())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_having_conflict(&self, s: &RelaysState, devices: &[Device]) -> bool {
|
||||||
|
if self
|
||||||
|
.conflicts_with
|
||||||
|
.iter()
|
||||||
|
.any(|id| s.get(id).unwrap().is_on())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse search
|
||||||
|
for device in devices {
|
||||||
|
for r in &device.relays {
|
||||||
|
if s.get(&r.id).unwrap().is_on() && r.conflicts_with.contains(&self.id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +106,12 @@ impl EnergyEngine {
|
|||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
let status = self.relay_state(r.id);
|
let status = self.relay_state(r.id);
|
||||||
table.add_row(row![d.name, r.name, status.on.to_string(), status.since]);
|
table.add_row(row![
|
||||||
|
d.name,
|
||||||
|
r.name,
|
||||||
|
status.is_on().to_string(),
|
||||||
|
status.since
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table.printstd();
|
table.printstd();
|
||||||
@ -93,28 +137,32 @@ impl EnergyEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forcefully turn off disabled relays
|
||||||
|
for d in devices {
|
||||||
|
for r in &d.relays {
|
||||||
|
if !r.enabled {
|
||||||
|
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Forcefully turn off relays with missing dependency
|
// Forcefully turn off relays with missing dependency
|
||||||
loop {
|
loop {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
|
|
||||||
for d in devices {
|
for d in devices {
|
||||||
if !self.device_state(&d.id).is_online() {
|
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
if !new_relays_state.get(&r.id).unwrap().on {
|
if new_relays_state.get(&r.id).unwrap().is_off() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any dependency of relay is off
|
// Check if any dependency of relay is off
|
||||||
if r.depends_on
|
if r.is_missing_dependencies(&new_relays_state) {
|
||||||
.iter()
|
|
||||||
.any(|d| !new_relays_state.get(d).unwrap().on)
|
|
||||||
{
|
|
||||||
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !changed {
|
if !changed {
|
||||||
break;
|
break;
|
||||||
@ -128,7 +176,7 @@ impl EnergyEngine {
|
|||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
let state = new_relays_state.get(&r.id).unwrap();
|
let state = new_relays_state.get(&r.id).unwrap();
|
||||||
if !state.on {
|
if state.is_off() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +186,7 @@ impl EnergyEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that no relay that depends on this relay are turned on
|
// Check that no relay that depends on this relay are turned on
|
||||||
if r.relay_has_running_dependencies(&new_relays_state, devices) {
|
if r.has_running_dependencies(&new_relays_state, devices) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,19 +200,63 @@ impl EnergyEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Turn on relays based on priority / dependencies / enabled / min downtime
|
// TODO Turn on relays with running constraints (only ENABLED)
|
||||||
|
|
||||||
// TODO Turn on relays with running constraints
|
// Order relays
|
||||||
|
let mut ordered_relays = devices
|
||||||
|
.iter()
|
||||||
|
.filter(|d| self.device_state(&d.id).is_online() && d.enabled)
|
||||||
|
.flat_map(|d| &d.relays)
|
||||||
|
.filter(|r| r.enabled)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
ordered_relays.sort_by_key(|r| r.priority);
|
||||||
|
ordered_relays.reverse();
|
||||||
|
|
||||||
// TODO Commit changes
|
loop {
|
||||||
|
let mut changed = false;
|
||||||
|
for relay in &ordered_relays {
|
||||||
|
if new_relays_state.get(&relay.id).unwrap().is_on() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !relay.enabled {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let real_relay_state = self.relays_state.get(&relay.id).unwrap();
|
||||||
|
if real_relay_state.is_off()
|
||||||
|
&& (real_relay_state.since + relay.minimal_downtime) as u64 > time_secs()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if relay.is_missing_dependencies(&new_relays_state) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if relay.is_having_conflict(&new_relays_state, devices) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : check consumption
|
||||||
|
log::info!("Turn on relay {}", relay.name);
|
||||||
|
new_relays_state.get_mut(&relay.id).unwrap().on = true;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !changed {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit changes
|
||||||
for (id, new_state) in &new_relays_state {
|
for (id, new_state) in &new_relays_state {
|
||||||
let curr_state = self.relay_state(*id);
|
let curr_state = self.relay_state(*id);
|
||||||
if curr_state.on != new_state.on {
|
if curr_state.on != new_state.on {
|
||||||
curr_state.on = new_state.on;
|
curr_state.on = new_state.on;
|
||||||
curr_state.since = time_secs() as usize;
|
curr_state.since = time_secs() as usize;
|
||||||
|
log::info!("Changing state of {id:?} to {}", new_state.on);
|
||||||
}
|
}
|
||||||
log::info!("Changing state of {id:?}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.print_summary(curr_consumption, devices);
|
self.print_summary(curr_consumption, devices);
|
||||||
|
Loading…
Reference in New Issue
Block a user