Store last ping of devices

This commit is contained in:
Pierre HUBERT 2024-09-09 21:05:52 +02:00
parent 6bdebe6932
commit 7cac6aeb35
4 changed files with 80 additions and 0 deletions

View File

@ -6,6 +6,9 @@ pub const SESSION_COOKIE_NAME: &str = "X-session-cookie";
/// Energy refresh operations interval /// Energy refresh operations interval
pub const ENERGY_REFRESH_INTERVAL: Duration = Duration::from_secs(30); pub const ENERGY_REFRESH_INTERVAL: Duration = Duration::from_secs(30);
/// Maximum time after a ping during which a device is considered "up"
pub const DEVICE_MAX_PING_TIME: u64 = 30;
/// Fallback value to use if production cannot be fetched /// Fallback value to use if production cannot be fetched
pub const FALLBACK_PRODUCTION_VALUE: i32 = 5000; pub const FALLBACK_PRODUCTION_VALUE: i32 = 5000;

View File

@ -5,12 +5,33 @@ use crate::devices::device::{
use crate::devices::devices_list::DevicesList; use crate::devices::devices_list::DevicesList;
use crate::energy::consumption; use crate::energy::consumption;
use crate::energy::consumption::EnergyConsumption; use crate::energy::consumption::EnergyConsumption;
use crate::utils::time_utils::time_secs;
use actix::prelude::*; use actix::prelude::*;
use openssl::x509::X509Req; use openssl::x509::X509Req;
use std::collections::HashMap;
#[derive(Default)]
struct DeviceState {
last_ping: u64,
}
impl DeviceState {
fn is_online(&self) -> bool {
(time_secs() - self.last_ping) < constants::DEVICE_MAX_PING_TIME
}
}
#[derive(Default)]
struct RelayState {
enabled: bool,
since: usize,
}
pub struct EnergyActor { pub struct EnergyActor {
curr_consumption: EnergyConsumption, curr_consumption: EnergyConsumption,
devices: DevicesList, devices: DevicesList,
devices_state: HashMap<DeviceId, DeviceState>,
relays_state: HashMap<DeviceRelayID, RelayState>,
} }
impl EnergyActor { impl EnergyActor {
@ -18,9 +39,20 @@ impl EnergyActor {
Ok(Self { Ok(Self {
curr_consumption: consumption::get_curr_consumption().await?, curr_consumption: consumption::get_curr_consumption().await?,
devices: DevicesList::load()?, devices: DevicesList::load()?,
devices_state: Default::default(),
relays_state: Default::default(),
}) })
} }
fn device_state(&mut self, dev_id: &DeviceId) -> &mut DeviceState {
if !self.devices_state.contains_key(dev_id) {
self.devices_state
.insert(dev_id.clone(), Default::default());
}
self.devices_state.get_mut(dev_id).unwrap()
}
async fn refresh(&mut self) -> anyhow::Result<()> { async fn refresh(&mut self) -> anyhow::Result<()> {
// Refresh energy // Refresh energy
self.curr_consumption = consumption::get_curr_consumption() self.curr_consumption = consumption::get_curr_consumption()
@ -253,6 +285,9 @@ impl Handler<SynchronizeDevice> for EnergyActor {
type Result = anyhow::Result<Vec<RelaySyncStatus>>; type Result = anyhow::Result<Vec<RelaySyncStatus>>;
fn handle(&mut self, msg: SynchronizeDevice, _ctx: &mut Context<Self>) -> Self::Result { fn handle(&mut self, msg: SynchronizeDevice, _ctx: &mut Context<Self>) -> Self::Result {
let s = self.device_state(&msg.0);
s.last_ping = time_secs();
// TODO : implement real code // TODO : implement real code
let mut v = vec![]; let mut v = vec![];
for i in 0..msg.1.max_relays { for i in 0..msg.1.max_relays {
@ -263,3 +298,34 @@ impl Handler<SynchronizeDevice> for EnergyActor {
Ok(v) Ok(v)
} }
} }
#[derive(serde::Serialize)]
pub struct ResDevState {
id: DeviceId,
last_ping: u64,
online: bool,
}
/// Get the state of devices
#[derive(Message)]
#[rtype(result = "Vec<ResDevState>")]
pub struct GetDevicesState;
impl Handler<GetDevicesState> for EnergyActor {
type Result = Vec<ResDevState>;
fn handle(&mut self, _msg: GetDevicesState, _ctx: &mut Context<Self>) -> Self::Result {
self.devices
.full_list()
.into_iter()
.map(|d| {
let s = self.device_state(&d.id);
ResDevState {
id: d.id,
last_ping: time_secs() - s.last_ping,
online: s.is_online(),
}
})
.collect()
}
}

View File

@ -144,6 +144,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
"/web_api/devices/list_validated", "/web_api/devices/list_validated",
web::get().to(devices_controller::list_validated), web::get().to(devices_controller::list_validated),
) )
.route(
"/web_api/devices/state",
web::get().to(devices_controller::devices_state),
)
.route( .route(
"/web_api/device/{id}", "/web_api/device/{id}",
web::get().to(devices_controller::get_single), web::get().to(devices_controller::get_single),

View File

@ -28,6 +28,13 @@ pub async fn list_validated(actor: WebEnergyActor) -> HttpResult {
Ok(HttpResponse::Ok().json(list)) Ok(HttpResponse::Ok().json(list))
} }
/// Get the state of devices
pub async fn devices_state(actor: WebEnergyActor) -> HttpResult {
let states = actor.send(energy_actor::GetDevicesState).await?;
Ok(HttpResponse::Ok().json(states))
}
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct DeviceInPath { pub struct DeviceInPath {
id: DeviceId, id: DeviceId,