Record relays state

This commit is contained in:
2024-09-17 22:31:51 +02:00
parent 368eb13089
commit 565db05fb0
8 changed files with 165 additions and 19 deletions

View File

@ -38,8 +38,11 @@ impl EnergyActor {
constants::FALLBACK_PRODUCTION_VALUE
});
self.engine
.refresh(self.curr_consumption, &self.devices.full_list());
let devices_list = self.devices.full_list();
self.engine.refresh(self.curr_consumption, &devices_list);
self.engine.persist_relays_state(&devices_list)?;
Ok(())
}

View File

@ -6,6 +6,7 @@ use prettytable::{row, Table};
use crate::constants;
use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
use crate::energy::consumption::EnergyConsumption;
use crate::energy::relay_state_history::RelayStateHistory;
use crate::utils::time_utils::time_secs;
#[derive(Default)]
@ -320,4 +321,18 @@ impl EnergyEngine {
self.print_summary(curr_consumption, devices);
}
/// Save relays state to disk
pub fn persist_relays_state(&mut self, devices: &[Device]) -> anyhow::Result<()> {
// Save all relays state
for d in devices {
for r in &d.relays {
let mut file = RelayStateHistory::open(r.id, time_secs())?;
file.set_state(time_secs(), self.relay_state(r.id).is_on())?;
file.save()?;
}
}
Ok(())
}
}

View File

@ -1,4 +1,15 @@
use crate::app_config::AppConfig;
use crate::devices::device::DeviceRelayID;
use crate::utils::files_utils;
use crate::utils::time_utils::day_number;
const TIME_INTERVAL: usize = 30;
#[derive(thiserror::Error, Debug)]
pub enum RelayStateHistoryError {
#[error("Given time is out of file bounds!")]
TimeOutOfFileBound,
}
/// # RelayStateHistory
///
@ -7,38 +18,124 @@ use crate::devices::device::DeviceRelayID;
/// These file are binary file optimizing used space.
pub struct RelayStateHistory {
id: DeviceRelayID,
day: usize,
day: u64,
buff: Vec<u8>,
}
impl RelayStateHistory {
/// Open relay state history file, if it exist, or create an empty one
pub fn open(id: DeviceRelayID, day: usize) -> anyhow::Result<Self> {
todo!()
/// Open relay state history file, if it exists, or create an empty one
pub fn open(id: DeviceRelayID, time: u64) -> anyhow::Result<Self> {
let day = day_number(time);
let path = AppConfig::get().relay_runtime_file_path(id, day);
if path.exists() {
Ok(Self {
id,
day,
buff: std::fs::read(path)?,
})
} else {
log::debug!(
"Stats for relay {id:?} for day {day} does not exists yet, creating memory buffer"
);
Ok(Self::new_memory(id, day))
}
}
/// Create a new in memory dev relay state history
fn new_memory(id: DeviceRelayID, day: usize) -> Self {
todo!()
fn new_memory(id: DeviceRelayID, day: u64) -> Self {
Self {
id,
day,
buff: vec![0; 3600 * 24 / TIME_INTERVAL],
}
}
/// Resolve time offset of a given time in buffer
fn resolve_offset(&self, time: i64) -> anyhow::Result<(usize, u8)> {
todo!()
fn resolve_offset(&self, time: u64) -> anyhow::Result<(usize, u8)> {
let start_of_day = self.day * 3600 * 24;
if time < start_of_day || time >= start_of_day + 3600 * 24 {
return Err(RelayStateHistoryError::TimeOutOfFileBound.into());
}
let relative_time = (time - start_of_day) / TIME_INTERVAL as u64;
Ok(((relative_time / 8) as usize, (relative_time % 8) as u8))
}
/// Set new state of relay
fn set_state(&mut self, time: i64, on: bool) -> anyhow::Result<()> {
todo!()
pub fn set_state(&mut self, time: u64, on: bool) -> anyhow::Result<()> {
let (idx, offset) = self.resolve_offset(time)?;
self.buff[idx] = if on {
self.buff[idx] | (0x1 << offset)
} else {
self.buff[idx] & !(0x1 << offset)
};
Ok(())
}
/// Get the state of relay at a given time
fn get_state(&self, time: i64) -> anyhow::Result<bool> {
todo!()
pub fn get_state(&self, time: u64) -> anyhow::Result<bool> {
let (idx, offset) = self.resolve_offset(time)?;
Ok(self.buff[idx] & (0x1 << offset) != 0)
}
/// Persist device relay state history
pub fn save(&self) -> anyhow::Result<()> {
todo!()
let path = AppConfig::get().relay_runtime_file_path(self.id, self.day);
files_utils::create_directory_if_missing(path.parent().unwrap())?;
std::fs::write(path, &self.buff)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::devices::device::DeviceRelayID;
use crate::energy::relay_state_history::RelayStateHistory;
#[test]
fn test_relay_state_history() {
let mut history = RelayStateHistory::new_memory(DeviceRelayID::default(), 0);
let val_1 = 5 * 30;
let val_2 = 7 * 30;
for i in 0..500 {
assert!(!history.get_state(i).unwrap())
}
history.set_state(val_1, true).unwrap();
for i in 0..500 {
assert_eq!(history.get_state(i).unwrap(), (i / 30) * 30 == val_1);
}
history.set_state(val_2, true).unwrap();
for i in 0..500 {
assert_eq!(
history.get_state(i).unwrap(),
(i / 30) * 30 == val_1 || (i / 30) * 30 == val_2
);
}
history.set_state(val_2, false).unwrap();
for i in 0..500 {
assert_eq!(history.get_state(i).unwrap(), (i / 30) * 30 == val_1);
}
history.set_state(val_1, false).unwrap();
for i in 0..500 {
assert!(!history.get_state(i).unwrap())
}
assert!(history.get_state(8989898).is_err());
}
}