Display relays status

This commit is contained in:
Pierre HUBERT 2024-09-25 19:35:39 +02:00
parent 78ace02d15
commit 3c2fa18d9a
6 changed files with 101 additions and 8 deletions

View File

@ -360,3 +360,34 @@ impl Handler<GetDevicesState> for EnergyActor {
.collect() .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<ResRelayState>")]
pub struct GetAllRelaysState;
impl Handler<GetAllRelaysState> for EnergyActor {
type Result = Vec<ResRelayState>;
fn handle(&mut self, _msg: GetAllRelaysState, _ctx: &mut Context<Self>) -> 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
}
}

View File

@ -39,6 +39,10 @@ impl RelayState {
fn is_off(&self) -> bool { fn is_off(&self) -> bool {
!self.on !self.on
} }
pub fn state_for(&self) -> usize {
(time_secs() - self.since as u64) as usize
}
} }
type RelaysState = HashMap<DeviceRelayID, RelayState>; type RelaysState = HashMap<DeviceRelayID, RelayState>;

View File

@ -185,6 +185,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
"/web_api/relay/{id}", "/web_api/relay/{id}",
web::delete().to(relays_controller::delete), web::delete().to(relays_controller::delete),
) )
.route(
"/web_api/relays/status",
web::get().to(relays_controller::get_status_all),
)
// Devices API // Devices API
.route( .route(
"/devices_api/utils/time", "/devices_api/utils/time",

View File

@ -93,3 +93,10 @@ pub async fn delete(actor: WebEnergyActor, path: web::Path<RelayIDInPath>) -> Ht
Ok(HttpResponse::Accepted().finish()) 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))
}

View File

@ -1,6 +1,14 @@
import { APIClient } from "./ApiClient"; import { APIClient } from "./ApiClient";
import { Device, DeviceRelay } from "./DeviceApi"; import { Device, DeviceRelay } from "./DeviceApi";
export interface RelayStatus {
id: string;
on: boolean;
for: number;
}
export type RelaysStatus = Map<string, RelayStatus>;
export class RelayApi { export class RelayApi {
/** /**
* Get the full list of relays * Get the full list of relays
@ -49,4 +57,22 @@ export class RelayApi {
uri: `/relay/${relay.id}`, uri: `/relay/${relay.id}`,
}); });
} }
/**
* Get the status of all relays
*/
static async GetRelaysStatus(): Promise<RelaysStatus> {
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;
}
} }

View File

@ -12,17 +12,20 @@ import {
} from "@mui/material"; } from "@mui/material";
import React from "react"; import React from "react";
import { DeviceRelay } from "../api/DeviceApi"; import { DeviceRelay } from "../api/DeviceApi";
import { RelayApi } from "../api/RelayApi"; import { RelayApi, RelaysStatus } from "../api/RelayApi";
import { AsyncWidget } from "../widgets/AsyncWidget"; import { AsyncWidget } from "../widgets/AsyncWidget";
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer"; import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
import { TimeWidget } from "../widgets/TimeWidget";
export function RelaysListRoute(): React.ReactElement { export function RelaysListRoute(): React.ReactElement {
const loadKey = React.useRef(1); const loadKey = React.useRef(1);
const [list, setList] = React.useState<DeviceRelay[] | undefined>(); const [list, setList] = React.useState<DeviceRelay[] | undefined>();
const [status, setStatus] = React.useState<RelaysStatus | undefined>();
const load = async () => { const load = async () => {
setList(await RelayApi.GetList()); setList(await RelayApi.GetList());
setStatus(await RelayApi.GetRelaysStatus());
list?.sort((a, b) => b.priority - a.priority); list?.sort((a, b) => b.priority - a.priority);
}; };
@ -48,7 +51,9 @@ export function RelaysListRoute(): React.ReactElement {
ready={!!list} ready={!!list}
errMsg="Failed to load the list of relays!" errMsg="Failed to load the list of relays!"
load={load} load={load}
build={() => <RelaysList onReload={reload} list={list!} />} build={() => (
<RelaysList onReload={reload} list={list!} status={status!} />
)}
/> />
</SolarEnergyRouteContainer> </SolarEnergyRouteContainer>
); );
@ -56,6 +61,7 @@ export function RelaysListRoute(): React.ReactElement {
function RelaysList(p: { function RelaysList(p: {
list: DeviceRelay[]; list: DeviceRelay[];
status: RelaysStatus;
onReload: () => void; onReload: () => void;
}): React.ReactElement { }): React.ReactElement {
return ( return (
@ -78,15 +84,18 @@ function RelaysList(p: {
> >
<TableCell>{row.name}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell> <TableCell>
{row.enabled ? ( <BoolText val={row.enabled} positive="YES" negative="NO" />
<span style={{ color: "green" }}>YES</span>
) : (
<span style={{ color: "red" }}>NO</span>
)}
</TableCell> </TableCell>
<TableCell>{row.priority}</TableCell> <TableCell>{row.priority}</TableCell>
<TableCell>{row.consumption}</TableCell> <TableCell>{row.consumption}</TableCell>
<TableCell>TODO</TableCell> <TableCell>
<BoolText
val={p.status.get(row.id)!.on}
positive="ON"
negative="OFF"
/>{" "}
for <TimeWidget diff time={p.status.get(row.id)!.for} />
</TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
@ -94,3 +103,15 @@ function RelaysList(p: {
</TableContainer> </TableContainer>
); );
} }
function BoolText(p: {
val: boolean;
positive: string;
negative: string;
}): React.ReactElement {
return p.val ? (
<span style={{ color: "green" }}>{p.positive}</span>
) : (
<span style={{ color: "red" }}>{p.negative}</span>
);
}