use crate::constants; use crate::devices::device::{ Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID, }; use crate::devices::devices_list::DevicesList; use crate::energy::consumption; use crate::energy::consumption::EnergyConsumption; use actix::prelude::*; use openssl::x509::X509Req; pub struct EnergyActor { curr_consumption: EnergyConsumption, devices: DevicesList, } impl EnergyActor { pub async fn new() -> anyhow::Result { Ok(Self { curr_consumption: consumption::get_curr_consumption().await?, devices: DevicesList::load()?, }) } async fn refresh(&mut self) -> anyhow::Result<()> { // Refresh energy self.curr_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 }); Ok(()) } } impl Actor for EnergyActor { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { log::info!("Energy actor successfully started!"); ctx.run_interval(constants::ENERGY_REFRESH_INTERVAL, |act, _ctx| { log::info!("Performing energy refresh operation"); if let Err(e) = futures::executor::block_on(act.refresh()) { log::error!("Energy refresh failed! {e}") } }); } fn stopped(&mut self, _ctx: &mut Self::Context) { log::info!("Energy actor successfully stopped!"); } } pub type EnergyActorAddr = Addr; /// Get current consumption #[derive(Message)] #[rtype(result = "EnergyConsumption")] pub struct GetCurrConsumption; impl Handler for EnergyActor { type Result = EnergyConsumption; fn handle(&mut self, _msg: GetCurrConsumption, _ctx: &mut Context) -> Self::Result { self.curr_consumption } } /// Get current consumption #[derive(Message)] #[rtype(result = "bool")] pub struct CheckDeviceExists(pub DeviceId); impl Handler for EnergyActor { type Result = bool; fn handle(&mut self, msg: CheckDeviceExists, _ctx: &mut Context) -> Self::Result { self.devices.exists(&msg.0) } } /// Enroll device #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct EnrollDevice(pub DeviceId, pub DeviceInfo, pub X509Req); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: EnrollDevice, _ctx: &mut Context) -> Self::Result { self.devices.enroll(&msg.0, &msg.1, &msg.2) } } /// Validate a device #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct ValidateDevice(pub DeviceId); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: ValidateDevice, _ctx: &mut Context) -> Self::Result { log::info!("Requested to validate device {:?}...", &msg.0); self.devices.validate(&msg.0)?; Ok(()) } } /// Update a device general information #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct UpdateDeviceGeneralInfo(pub DeviceId, pub DeviceGeneralInfo); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: UpdateDeviceGeneralInfo, _ctx: &mut Context) -> Self::Result { log::info!( "Requested to update device general info {:?}... {:#?}", &msg.0, &msg.1 ); self.devices.update_general_info(&msg.0, msg.1)?; Ok(()) } } /// Delete a device #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct DeleteDevice(pub DeviceId); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: DeleteDevice, _ctx: &mut Context) -> Self::Result { log::info!("Requested to delete device {:?}...", &msg.0); self.devices.delete(&msg.0)?; // TODO : delete energy related information Ok(()) } } /// Get the list of devices #[derive(Message)] #[rtype(result = "Vec")] pub struct GetDeviceLists; impl Handler for EnergyActor { type Result = Vec; fn handle(&mut self, _msg: GetDeviceLists, _ctx: &mut Context) -> Self::Result { self.devices.full_list() } } /// Get the information about a single device #[derive(Message)] #[rtype(result = "Option")] pub struct GetSingleDevice(pub DeviceId); impl Handler for EnergyActor { type Result = Option; fn handle(&mut self, msg: GetSingleDevice, _ctx: &mut Context) -> Self::Result { self.devices.get_single(&msg.0) } } /// Get the full list of relays #[derive(Message)] #[rtype(result = "Vec")] pub struct GetRelaysList; impl Handler for EnergyActor { type Result = Vec; fn handle(&mut self, _msg: GetRelaysList, _ctx: &mut Context) -> Self::Result { self.devices.relays_list() } } /// Create a new device relay #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct CreateDeviceRelay(pub DeviceId, pub DeviceRelay); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: CreateDeviceRelay, _ctx: &mut Context) -> Self::Result { self.devices.relay_create(&msg.0, msg.1) } } /// Get the information about a single relay #[derive(Message)] #[rtype(result = "Option")] pub struct GetSingleRelay(pub DeviceRelayID); impl Handler for EnergyActor { type Result = Option; fn handle(&mut self, msg: GetSingleRelay, _ctx: &mut Context) -> Self::Result { self.devices.relay_get_single(msg.0) } } /// Update a device relay #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct UpdateDeviceRelay(pub DeviceRelay); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: UpdateDeviceRelay, _ctx: &mut Context) -> Self::Result { self.devices.relay_update(msg.0) } } /// Delete a device relay #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] pub struct DeleteDeviceRelay(pub DeviceRelayID); impl Handler for EnergyActor { type Result = anyhow::Result<()>; fn handle(&mut self, msg: DeleteDeviceRelay, _ctx: &mut Context) -> Self::Result { self.devices.relay_delete(msg.0) } } #[derive(serde::Serialize)] pub struct RelaySyncStatus { enabled: bool, } /// Synchronize a device #[derive(Message)] #[rtype(result = "anyhow::Result>")] pub struct SynchronizeDevice(pub DeviceId, pub DeviceInfo); impl Handler for EnergyActor { type Result = anyhow::Result>; fn handle(&mut self, msg: SynchronizeDevice, _ctx: &mut Context) -> Self::Result { // TODO : implement real code let mut v = vec![]; for i in 0..msg.1.max_relays { v.push(RelaySyncStatus { enabled: i % 2 == 0, }); } Ok(v) } }