Display relay consumption history
This commit is contained in:
parent
903f1fa8ce
commit
7895b9eca8
@ -115,6 +115,11 @@ impl DevicesList {
|
|||||||
self.0.clone().into_values().collect()
|
self.0.clone().into_values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference on the full list of devices
|
||||||
|
pub fn full_list_ref(&self) -> Vec<&Device> {
|
||||||
|
self.0.values().collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the information about a single device
|
/// Get the information about a single device
|
||||||
pub fn get_single(&self, id: &DeviceId) -> Option<Device> {
|
pub fn get_single(&self, id: &DeviceId) -> Option<Device> {
|
||||||
self.0.get(id).cloned()
|
self.0.get(id).cloned()
|
||||||
|
@ -53,7 +53,7 @@ impl EnergyActor {
|
|||||||
});
|
});
|
||||||
self.consumption_cache.add_value(latest_consumption);
|
self.consumption_cache.add_value(latest_consumption);
|
||||||
|
|
||||||
let devices_list = self.devices.full_list();
|
let devices_list = self.devices.full_list_ref();
|
||||||
|
|
||||||
let mut history =
|
let mut history =
|
||||||
ConsumptionHistoryFile::open(time_secs(), ConsumptionHistoryType::GridConsumption)?;
|
ConsumptionHistoryFile::open(time_secs(), ConsumptionHistoryType::GridConsumption)?;
|
||||||
@ -119,7 +119,21 @@ impl Handler<GetCurrConsumption> for EnergyActor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current consumption
|
/// Get relays consumption
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "usize")]
|
||||||
|
pub struct RelaysConsumption;
|
||||||
|
|
||||||
|
impl Handler<RelaysConsumption> for EnergyActor {
|
||||||
|
type Result = usize;
|
||||||
|
|
||||||
|
fn handle(&mut self, _msg: RelaysConsumption, _ctx: &mut Context<Self>) -> Self::Result {
|
||||||
|
self.engine
|
||||||
|
.sum_relays_consumption(&self.devices.full_list_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if device exists
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
#[rtype(result = "bool")]
|
#[rtype(result = "bool")]
|
||||||
pub struct CheckDeviceExists(pub DeviceId);
|
pub struct CheckDeviceExists(pub DeviceId);
|
||||||
|
@ -55,7 +55,7 @@ pub struct EnergyEngine {
|
|||||||
|
|
||||||
impl DeviceRelay {
|
impl DeviceRelay {
|
||||||
// Note : this function is not recursive
|
// Note : this function is not recursive
|
||||||
fn has_running_dependencies(&self, s: &RelaysState, devices: &[Device]) -> bool {
|
fn has_running_dependencies(&self, s: &RelaysState, devices: &[&Device]) -> bool {
|
||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
if r.depends_on.contains(&self.id) && s.get(&r.id).unwrap().is_on() {
|
if r.depends_on.contains(&self.id) && s.get(&r.id).unwrap().is_on() {
|
||||||
@ -72,7 +72,7 @@ impl DeviceRelay {
|
|||||||
self.depends_on.iter().any(|id| s.get(id).unwrap().is_off())
|
self.depends_on.iter().any(|id| s.get(id).unwrap().is_off())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_having_conflict(&self, s: &RelaysState, devices: &[Device]) -> bool {
|
fn is_having_conflict(&self, s: &RelaysState, devices: &[&Device]) -> bool {
|
||||||
if self
|
if self
|
||||||
.conflicts_with
|
.conflicts_with
|
||||||
.iter()
|
.iter()
|
||||||
@ -94,7 +94,7 @@ impl DeviceRelay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sum_relays_consumption(state: &RelaysState, devices: &[Device]) -> usize {
|
fn sum_relays_consumption(state: &RelaysState, devices: &[&Device]) -> usize {
|
||||||
let mut consumption = 0;
|
let mut consumption = 0;
|
||||||
|
|
||||||
for d in devices {
|
for d in devices {
|
||||||
@ -119,11 +119,11 @@ impl EnergyEngine {
|
|||||||
self.relays_state.get_mut(&relay_id).unwrap()
|
self.relays_state.get_mut(&relay_id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sum_relays_consumption(&self, devices: &[Device]) -> usize {
|
pub fn sum_relays_consumption(&self, devices: &[&Device]) -> usize {
|
||||||
sum_relays_consumption(&self.relays_state, devices)
|
sum_relays_consumption(&self.relays_state, devices)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_summary(&mut self, curr_consumption: EnergyConsumption, devices: &[Device]) {
|
fn print_summary(&mut self, curr_consumption: EnergyConsumption, devices: &[&Device]) {
|
||||||
log::info!("Current consumption: {curr_consumption}");
|
log::info!("Current consumption: {curr_consumption}");
|
||||||
|
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
@ -172,13 +172,13 @@ impl EnergyEngine {
|
|||||||
pub fn estimated_consumption_without_relays(
|
pub fn estimated_consumption_without_relays(
|
||||||
&self,
|
&self,
|
||||||
curr_consumption: EnergyConsumption,
|
curr_consumption: EnergyConsumption,
|
||||||
devices: &[Device],
|
devices: &[&Device],
|
||||||
) -> EnergyConsumption {
|
) -> EnergyConsumption {
|
||||||
curr_consumption - self.sum_relays_consumption(devices) as i32
|
curr_consumption - self.sum_relays_consumption(devices) as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refresh energy engine; this method shall never fail !
|
/// Refresh energy engine; this method shall never fail !
|
||||||
pub fn refresh(&mut self, curr_consumption: EnergyConsumption, devices: &[Device]) {
|
pub fn refresh(&mut self, curr_consumption: EnergyConsumption, devices: &[&Device]) {
|
||||||
let base_production = self.estimated_consumption_without_relays(curr_consumption, devices);
|
let base_production = self.estimated_consumption_without_relays(curr_consumption, devices);
|
||||||
log::info!("Estimated base production: {base_production}");
|
log::info!("Estimated base production: {base_production}");
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ impl EnergyEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Save relays state to disk
|
/// Save relays state to disk
|
||||||
pub fn persist_relays_state(&mut self, devices: &[Device]) -> anyhow::Result<()> {
|
pub fn persist_relays_state(&mut self, devices: &[&Device]) -> anyhow::Result<()> {
|
||||||
// Save all relays state
|
// Save all relays state
|
||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
|
@ -139,6 +139,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
|||||||
"/web_api/energy/cached_consumption",
|
"/web_api/energy/cached_consumption",
|
||||||
web::get().to(energy_controller::cached_consumption),
|
web::get().to(energy_controller::cached_consumption),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/web_api/energy/relays_consumption",
|
||||||
|
web::get().to(energy_controller::relays_consumption),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/web_api/energy/relays_consumption/history",
|
"/web_api/energy/relays_consumption/history",
|
||||||
web::get().to(energy_controller::relays_consumption_history),
|
web::get().to(energy_controller::relays_consumption_history),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::app_config::ConsumptionHistoryType;
|
use crate::app_config::ConsumptionHistoryType;
|
||||||
|
use crate::energy::consumption::EnergyConsumption;
|
||||||
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
||||||
use crate::energy::{consumption, energy_actor};
|
use crate::energy::{consumption, energy_actor};
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
@ -36,6 +37,14 @@ pub async fn cached_consumption(energy_actor: WebEnergyActor) -> HttpResult {
|
|||||||
Ok(HttpResponse::Ok().json(Consumption { consumption }))
|
Ok(HttpResponse::Ok().json(Consumption { consumption }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get current relays consumption
|
||||||
|
pub async fn relays_consumption(energy_actor: WebEnergyActor) -> HttpResult {
|
||||||
|
let consumption =
|
||||||
|
energy_actor.send(energy_actor::RelaysConsumption).await? as EnergyConsumption;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().json(Consumption { consumption }))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn relays_consumption_history() -> HttpResult {
|
pub async fn relays_consumption_history() -> HttpResult {
|
||||||
let history = ConsumptionHistoryFile::get_history(
|
let history = ConsumptionHistoryFile::get_history(
|
||||||
ConsumptionHistoryType::RelayConsumption,
|
ConsumptionHistoryType::RelayConsumption,
|
||||||
|
@ -35,6 +35,18 @@ export class EnergyApi {
|
|||||||
return data.data.consumption;
|
return data.data.consumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get relays consumption
|
||||||
|
*/
|
||||||
|
static async RelaysConsumption(): Promise<number> {
|
||||||
|
return (
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "GET",
|
||||||
|
uri: "/energy/relays_consumption",
|
||||||
|
})
|
||||||
|
).data.consumption;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get relays consumption history
|
* Get relays consumption history
|
||||||
*/
|
*/
|
||||||
|
@ -83,7 +83,7 @@ export class RelayApi {
|
|||||||
return (
|
return (
|
||||||
await APIClient.exec({
|
await APIClient.exec({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
uri: `/relay/${relay.id}/state`,
|
uri: `/relay/${relay.id}/status`,
|
||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Typography } from "@mui/material";
|
|||||||
import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget";
|
import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid2";
|
||||||
import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget";
|
import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget";
|
||||||
|
import { RelayConsumptionWidget } from "./HomeRoute/RelayConsumptionWidget";
|
||||||
|
|
||||||
export function HomeRoute(): React.ReactElement {
|
export function HomeRoute(): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
@ -18,6 +19,9 @@ export function HomeRoute(): React.ReactElement {
|
|||||||
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
||||||
<CurrConsumptionWidget />
|
<CurrConsumptionWidget />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
||||||
|
<RelayConsumptionWidget />
|
||||||
|
</Grid>
|
||||||
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
||||||
<CachedConsumptionWidget />
|
<CachedConsumptionWidget />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { EnergyApi } from "../../api/EnergyApi";
|
||||||
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
|
import StatCard from "../../widgets/StatCard";
|
||||||
|
|
||||||
|
export function RelayConsumptionWidget(): React.ReactElement {
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
|
const [val, setVal] = React.useState<undefined | number>();
|
||||||
|
const [history, setHistory] = React.useState<number[] | undefined>();
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
try {
|
||||||
|
const s = await EnergyApi.RelaysConsumption();
|
||||||
|
const history = await EnergyApi.RelaysConsumptionHistory();
|
||||||
|
setVal(s);
|
||||||
|
setHistory(history);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
snackbar("Failed to refresh current relays consumption!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const i = setInterval(() => refresh(), 3000);
|
||||||
|
|
||||||
|
return () => clearInterval(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatCard
|
||||||
|
title="Relays consumption"
|
||||||
|
data={history ?? []}
|
||||||
|
interval="Last day"
|
||||||
|
value={val?.toString() ?? "Loading"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -61,7 +61,10 @@ export function TimeWidget(p: {
|
|||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
if (!p.time) return <></>;
|
if (!p.time) return <></>;
|
||||||
return (
|
return (
|
||||||
<Tooltip title={formatDate(p.time)} arrow>
|
<Tooltip
|
||||||
|
title={formatDate(p.diff ? new Date().getTime() / 1000 - p.time : p.time)}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
<span>{p.diff ? timeDiff(0, p.time) : timeDiffFromNow(p.time)}</span>
|
<span>{p.diff ? timeDiff(0, p.time) : timeDiffFromNow(p.time)}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user