From 3c2fa18d9af482310c76cb8ae70c36085e30a3b1 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 25 Sep 2024 19:35:39 +0200 Subject: [PATCH] Display relays status --- central_backend/src/energy/energy_actor.rs | 31 ++++++++++++++++ central_backend/src/energy/engine.rs | 4 ++ central_backend/src/server/servers.rs | 4 ++ .../src/server/web_api/relays_controller.rs | 7 ++++ central_frontend/src/api/RelayApi.ts | 26 +++++++++++++ .../src/routes/RelaysListRoute.tsx | 37 +++++++++++++++---- 6 files changed, 101 insertions(+), 8 deletions(-) diff --git a/central_backend/src/energy/energy_actor.rs b/central_backend/src/energy/energy_actor.rs index 06a7b3b..9d3de54 100644 --- a/central_backend/src/energy/energy_actor.rs +++ b/central_backend/src/energy/energy_actor.rs @@ -360,3 +360,34 @@ impl Handler for EnergyActor { .collect() } } + +#[derive(serde::Serialize)] +pub struct ResRelayState { + pub id: DeviceRelayID, + on: bool, + r#for: usize, +} + +/// Get the state of all relays +#[derive(Message)] +#[rtype(result = "Vec")] +pub struct GetAllRelaysState; + +impl Handler for EnergyActor { + type Result = Vec; + + fn handle(&mut self, _msg: GetAllRelaysState, _ctx: &mut Context) -> Self::Result { + let mut list = vec![]; + + for d in &self.devices.relays_list() { + let state = self.engine.relay_state(d.id); + list.push(ResRelayState { + id: d.id, + on: state.is_on(), + r#for: state.state_for(), + }) + } + + list + } +} diff --git a/central_backend/src/energy/engine.rs b/central_backend/src/energy/engine.rs index 0d3f2dd..46bcd94 100644 --- a/central_backend/src/energy/engine.rs +++ b/central_backend/src/energy/engine.rs @@ -39,6 +39,10 @@ impl RelayState { fn is_off(&self) -> bool { !self.on } + + pub fn state_for(&self) -> usize { + (time_secs() - self.since as u64) as usize + } } type RelaysState = HashMap; diff --git a/central_backend/src/server/servers.rs b/central_backend/src/server/servers.rs index 2e331f8..4bb4f51 100644 --- a/central_backend/src/server/servers.rs +++ b/central_backend/src/server/servers.rs @@ -185,6 +185,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> "/web_api/relay/{id}", web::delete().to(relays_controller::delete), ) + .route( + "/web_api/relays/status", + web::get().to(relays_controller::get_status_all), + ) // Devices API .route( "/devices_api/utils/time", diff --git a/central_backend/src/server/web_api/relays_controller.rs b/central_backend/src/server/web_api/relays_controller.rs index 3ff5dfc..909d570 100644 --- a/central_backend/src/server/web_api/relays_controller.rs +++ b/central_backend/src/server/web_api/relays_controller.rs @@ -93,3 +93,10 @@ pub async fn delete(actor: WebEnergyActor, path: web::Path) -> Ht Ok(HttpResponse::Accepted().finish()) } + +/// Get the status of all relays +pub async fn get_status_all(actor: WebEnergyActor) -> HttpResult { + let list = actor.send(energy_actor::GetAllRelaysState).await?; + + Ok(HttpResponse::Ok().json(list)) +} diff --git a/central_frontend/src/api/RelayApi.ts b/central_frontend/src/api/RelayApi.ts index 7d6a8db..6e92d2a 100644 --- a/central_frontend/src/api/RelayApi.ts +++ b/central_frontend/src/api/RelayApi.ts @@ -1,6 +1,14 @@ import { APIClient } from "./ApiClient"; import { Device, DeviceRelay } from "./DeviceApi"; +export interface RelayStatus { + id: string; + on: boolean; + for: number; +} + +export type RelaysStatus = Map; + export class RelayApi { /** * Get the full list of relays @@ -49,4 +57,22 @@ export class RelayApi { uri: `/relay/${relay.id}`, }); } + + /** + * Get the status of all relays + */ + static async GetRelaysStatus(): Promise { + const data: any[] = ( + await APIClient.exec({ + method: "GET", + uri: `/relays/status`, + }) + ).data; + + const map = new Map(); + for (let r of data) { + map.set(r.id, r); + } + return map; + } } diff --git a/central_frontend/src/routes/RelaysListRoute.tsx b/central_frontend/src/routes/RelaysListRoute.tsx index 1c297bf..8a43e90 100644 --- a/central_frontend/src/routes/RelaysListRoute.tsx +++ b/central_frontend/src/routes/RelaysListRoute.tsx @@ -12,17 +12,20 @@ import { } from "@mui/material"; import React from "react"; import { DeviceRelay } from "../api/DeviceApi"; -import { RelayApi } from "../api/RelayApi"; +import { RelayApi, RelaysStatus } from "../api/RelayApi"; import { AsyncWidget } from "../widgets/AsyncWidget"; import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer"; +import { TimeWidget } from "../widgets/TimeWidget"; export function RelaysListRoute(): React.ReactElement { const loadKey = React.useRef(1); const [list, setList] = React.useState(); + const [status, setStatus] = React.useState(); const load = async () => { setList(await RelayApi.GetList()); + setStatus(await RelayApi.GetRelaysStatus()); list?.sort((a, b) => b.priority - a.priority); }; @@ -48,7 +51,9 @@ export function RelaysListRoute(): React.ReactElement { ready={!!list} errMsg="Failed to load the list of relays!" load={load} - build={() => } + build={() => ( + + )} /> ); @@ -56,6 +61,7 @@ export function RelaysListRoute(): React.ReactElement { function RelaysList(p: { list: DeviceRelay[]; + status: RelaysStatus; onReload: () => void; }): React.ReactElement { return ( @@ -78,15 +84,18 @@ function RelaysList(p: { > {row.name} - {row.enabled ? ( - YES - ) : ( - NO - )} + {row.priority} {row.consumption} - TODO + + {" "} + for + ))} @@ -94,3 +103,15 @@ function RelaysList(p: { ); } + +function BoolText(p: { + val: boolean; + positive: string; + negative: string; +}): React.ReactElement { + return p.val ? ( + {p.positive} + ) : ( + {p.negative} + ); +}