Record received consumption from inverter
This commit is contained in:
parent
0e0da14fde
commit
228e1a7293
26
central_backend/Cargo.lock
generated
26
central_backend/Cargo.lock
generated
@ -523,6 +523,25 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
@ -608,6 +627,7 @@ dependencies = [
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
"asn1",
|
||||
"bincode",
|
||||
"chrono",
|
||||
"clap",
|
||||
"env_logger",
|
||||
@ -2697,6 +2717,12 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
|
@ -38,3 +38,4 @@ jsonwebtoken = { version = "9.3.0", features = ["use_pem"] }
|
||||
prettytable-rs = "0.10.0"
|
||||
chrono = "0.4.38"
|
||||
serde_yml = "0.0.12"
|
||||
bincode = "=2.0.0-rc.3"
|
@ -255,6 +255,18 @@ impl AppConfig {
|
||||
pub fn relay_runtime_day_file_path(&self, relay_id: DeviceRelayID, day: u64) -> PathBuf {
|
||||
self.relay_runtime_stats_dir(relay_id).join(day.to_string())
|
||||
}
|
||||
|
||||
/// Get energy consumption history path
|
||||
pub fn energy_consumption_history(&self) -> PathBuf {
|
||||
self.storage_path().join("consumption_history")
|
||||
}
|
||||
|
||||
/// Get energy consumption history file path for a given day
|
||||
pub fn energy_consumption_history_day(&self, number: u64) -> PathBuf {
|
||||
self.storage_path()
|
||||
.join("consumption_history")
|
||||
.join(number.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::constants;
|
||||
use crate::energy::consumption::EnergyConsumption;
|
||||
use log::log;
|
||||
|
||||
pub struct ConsumptionCache {
|
||||
nb_vals: usize,
|
||||
|
128
central_backend/src/energy/consumption_history_file.rs
Normal file
128
central_backend/src/energy/consumption_history_file.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::energy::consumption::EnergyConsumption;
|
||||
use crate::utils::time_utils::day_number;
|
||||
|
||||
const TIME_INTERVAL: usize = 10;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ConsumptionHistoryError {
|
||||
#[error("Given time is out of file bounds!")]
|
||||
TimeOutOfFileBound,
|
||||
}
|
||||
|
||||
/// # ConsumptionHistoryFile
|
||||
///
|
||||
/// Stores the history of house consumption
|
||||
pub struct ConsumptionHistoryFile {
|
||||
day: u64,
|
||||
buff: Vec<EnergyConsumption>,
|
||||
}
|
||||
|
||||
impl ConsumptionHistoryFile {
|
||||
/// Open consumption history file, if it exists, or create an empty one
|
||||
pub fn open(time: u64) -> anyhow::Result<Self> {
|
||||
let day = day_number(time);
|
||||
let path = AppConfig::get().energy_consumption_history_day(day);
|
||||
|
||||
if path.exists() {
|
||||
Ok(Self {
|
||||
day,
|
||||
buff: bincode::decode_from_slice(
|
||||
&std::fs::read(path)?,
|
||||
bincode::config::standard(),
|
||||
)?
|
||||
.0,
|
||||
})
|
||||
} else {
|
||||
log::debug!(
|
||||
"Energy consumption stats for day {day} does not exists yet, creating memory buffer"
|
||||
);
|
||||
Ok(Self::new_memory(day))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new in memory consumption history
|
||||
fn new_memory(day: u64) -> Self {
|
||||
Self {
|
||||
day,
|
||||
buff: vec![0; 3600 * 24 / TIME_INTERVAL],
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve time offset of a given time in buffer
|
||||
fn resolve_offset(&self, time: u64) -> anyhow::Result<usize> {
|
||||
let start_of_day = self.day * 3600 * 24;
|
||||
|
||||
if time < start_of_day || time >= start_of_day + 3600 * 24 {
|
||||
return Err(ConsumptionHistoryError::TimeOutOfFileBound.into());
|
||||
}
|
||||
|
||||
let relative_time = (time - start_of_day) / TIME_INTERVAL as u64;
|
||||
|
||||
Ok(relative_time as usize)
|
||||
}
|
||||
|
||||
/// Check if a time is contained in this history
|
||||
pub fn contains_time(&self, time: u64) -> bool {
|
||||
self.resolve_offset(time).is_ok()
|
||||
}
|
||||
|
||||
/// Set new state of relay
|
||||
pub fn set_consumption(
|
||||
&mut self,
|
||||
time: u64,
|
||||
consumption: EnergyConsumption,
|
||||
) -> anyhow::Result<()> {
|
||||
let idx = self.resolve_offset(time)?;
|
||||
self.buff[idx] = consumption;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the consumption recorded at a given time
|
||||
pub fn get_consumption(&self, time: u64) -> anyhow::Result<EnergyConsumption> {
|
||||
let idx = self.resolve_offset(time)?;
|
||||
|
||||
Ok(self.buff[idx])
|
||||
}
|
||||
|
||||
/// Persist device relay state history
|
||||
pub fn save(&self) -> anyhow::Result<()> {
|
||||
let path = AppConfig::get().energy_consumption_history_day(self.day);
|
||||
std::fs::write(
|
||||
path,
|
||||
bincode::encode_to_vec(&self.buff, bincode::config::standard())?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::energy::consumption::EnergyConsumption;
|
||||
use crate::energy::consumption_history_file::{ConsumptionHistoryFile, TIME_INTERVAL};
|
||||
|
||||
#[test]
|
||||
fn test_consumption_history() {
|
||||
let mut history = ConsumptionHistoryFile::new_memory(0);
|
||||
|
||||
for i in 0..50 {
|
||||
assert_eq!(
|
||||
history.get_consumption(i * TIME_INTERVAL as u64).unwrap(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
for i in 0..50 {
|
||||
history
|
||||
.set_consumption(i * TIME_INTERVAL as u64, i as EnergyConsumption * 2)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
for i in 0..50 {
|
||||
assert_eq!(
|
||||
history.get_consumption(i * TIME_INTERVAL as u64).unwrap(),
|
||||
i as EnergyConsumption * 2
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ use crate::devices::devices_list::DevicesList;
|
||||
use crate::energy::consumption;
|
||||
use crate::energy::consumption::EnergyConsumption;
|
||||
use crate::energy::consumption_cache::ConsumptionCache;
|
||||
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
||||
use crate::energy::engine::EnergyEngine;
|
||||
use crate::utils::time_utils::time_secs;
|
||||
use actix::prelude::*;
|
||||
@ -42,17 +43,19 @@ impl EnergyActor {
|
||||
|
||||
async fn refresh(&mut self) -> anyhow::Result<()> {
|
||||
// Refresh energy
|
||||
self.consumption_cache
|
||||
.add_value(
|
||||
consumption::get_curr_consumption()
|
||||
let latest_consumption = consumption::get_curr_consumption()
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!(
|
||||
"Failed to fetch latest consumption value, will use fallback value! {e}"
|
||||
);
|
||||
constants::FALLBACK_PRODUCTION_VALUE
|
||||
}),
|
||||
);
|
||||
});
|
||||
self.consumption_cache.add_value(latest_consumption);
|
||||
|
||||
let mut history = ConsumptionHistoryFile::open(time_secs())?;
|
||||
history.set_consumption(time_secs(), latest_consumption)?;
|
||||
history.save()?;
|
||||
|
||||
if self.last_engine_refresh + AppConfig::get().refresh_interval > time_secs() {
|
||||
return Ok(());
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub mod consumption;
|
||||
pub mod consumption_cache;
|
||||
pub mod consumption_history_file;
|
||||
pub mod energy_actor;
|
||||
pub mod engine;
|
||||
pub mod relay_state_history;
|
||||
|
@ -47,7 +47,7 @@ impl RelayStateHistory {
|
||||
Self {
|
||||
id,
|
||||
day,
|
||||
buff: vec![0; 3600 * 24 / TIME_INTERVAL],
|
||||
buff: vec![0; (3600 * 24 / (TIME_INTERVAL * 8)) + 1],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ async fn main() -> std::io::Result<()> {
|
||||
create_directory_if_missing(AppConfig::get().pki_path()).unwrap();
|
||||
create_directory_if_missing(AppConfig::get().devices_config_path()).unwrap();
|
||||
create_directory_if_missing(AppConfig::get().relays_runtime_stats_storage_path()).unwrap();
|
||||
create_directory_if_missing(AppConfig::get().energy_consumption_history()).unwrap();
|
||||
|
||||
// Initialize PKI
|
||||
pki::initialize_root_ca().expect("Failed to initialize Root CA!");
|
||||
|
Loading…
Reference in New Issue
Block a user