|
1 | 1 | import RefreshIcon from "@mui/icons-material/Refresh"; |
2 | 2 | import { Button, Chip, IconButton, Stack } from "@mui/material"; |
3 | 3 | import { FC, useState } from "react"; |
4 | | -import { |
5 | | - useGetWaterQuery, |
6 | | - type GetWaterResponse, |
7 | | -} from "../../../../Services/generated/energyUsageApiWithRetry"; |
| 4 | +import { BarProps } from "recharts"; |
| 5 | +import { useGetWaterQuery } from "../../../../Services/generated/energyUsageApiWithRetry"; |
8 | 6 | import EnergyChart, { |
| 7 | + SensorItem, |
9 | 8 | axisDateTimeFormatDayHour, |
10 | 9 | } from "../../../Molecules/EnergyChart/EnergyChart"; |
11 | 10 |
|
12 | | -type WaterSensorItem = GetWaterResponse[0][0] & { |
13 | | - delta?: number; |
14 | | - liters?: number; |
15 | | -}; |
16 | | - |
17 | | -const INTERVAL_24_HOURS = 1000 * 60 * 60 * 24; |
18 | | -const INTERVAL_5_MIN = 1000 * 60 * 5; |
19 | | - |
20 | | -const aggregateByInterval = |
21 | | - (interval: number) => |
22 | | - (acc: WaterSensorItem[], next: WaterSensorItem): WaterSensorItem[] => { |
23 | | - const prevEntry = acc.at(-1) ?? next; |
24 | | - const prevTime = new Date(prevEntry.last_changed ?? "0").getTime(); |
25 | | - const nextTime = new Date(next.last_changed ?? "0").getTime(); |
26 | | - if (nextTime <= prevTime + interval) { |
27 | | - return [ |
28 | | - ...acc.slice(0, -1), |
29 | | - { ...prevEntry, liters: (prevEntry.liters ?? 0) + 1 }, |
30 | | - ]; |
31 | | - } |
32 | | - return [...acc, { ...next, liters: (next.liters ?? 0) + 1 }]; |
33 | | - }; |
| 11 | +const COLORS = ["#66bb6a"]; |
34 | 12 |
|
35 | 13 | export const WaterChart: FC = () => { |
36 | 14 | const [mode, setMode] = useState<"day" | "month">("day"); |
37 | 15 | const { data, isLoading, isFetching, refetch } = useGetWaterQuery({ |
38 | 16 | range: mode, |
39 | 17 | }); |
40 | 18 |
|
41 | | - const sensorEntries: WaterSensorItem[] = data?.[0] ?? []; |
| 19 | + const sensors = data?.flatMap((sensor) => sensor[0]) ?? []; |
42 | 20 |
|
43 | | - const interval = mode === "month" ? INTERVAL_24_HOURS : INTERVAL_5_MIN; |
| 21 | + const entriesBySensor = ( |
| 22 | + data?.flatMap((sensor) => |
| 23 | + sensor |
| 24 | + .map((item) => ({ |
| 25 | + time: new Date(item?.last_changed ?? 0).getTime(), |
| 26 | + [`${item.attributes?.friendly_name ?? item?.entity_id}`]: |
| 27 | + parseFloat(item.state ?? ""), |
| 28 | + })) |
| 29 | + .slice(1) |
| 30 | + ) ?? [] |
| 31 | + ).toSorted((a, b) => { |
| 32 | + return a.time - b.time; |
| 33 | + }); |
| 34 | + const entriesByTimestamp = entriesBySensor.reduce< |
| 35 | + Record<number, SensorItem> |
| 36 | + >((acc: Record<number, SensorItem>, item: SensorItem) => { |
| 37 | + acc[item.time] = { ...acc[item.time], ...item }; |
| 38 | + return acc; |
| 39 | + }, {}); |
| 40 | + const entries = Object.values(entriesByTimestamp); |
44 | 41 |
|
45 | | - const aggregatedByInterval = sensorEntries.reduce<WaterSensorItem[]>( |
46 | | - aggregateByInterval(interval), |
47 | | - [] |
48 | | - ); |
| 42 | + const bars: Omit<BarProps, "ref">[] = sensors.map((sensor, i) => ({ |
| 43 | + dataKey: `${sensor.attributes?.friendly_name ?? sensor?.entity_id}`, |
| 44 | + fill: COLORS[i], |
| 45 | + unit: "l", |
| 46 | + })); |
| 47 | + |
| 48 | + if (!data) { |
| 49 | + return <div>Loading...</div>; |
| 50 | + } |
49 | 51 |
|
50 | 52 | return ( |
51 | 53 | <> |
@@ -84,19 +86,9 @@ export const WaterChart: FC = () => { |
84 | 86 | ))} |
85 | 87 | </Stack> |
86 | 88 | <EnergyChart |
87 | | - data={aggregatedByInterval.map((item) => ({ |
88 | | - time: new Date(item.last_changed ?? "0").getTime() ?? 1, |
89 | | - liters: item.liters, |
90 | | - state: item.state, |
91 | | - }))} |
| 89 | + data={entries} |
92 | 90 | config={{ |
93 | | - bars: [ |
94 | | - { |
95 | | - dataKey: "liters", |
96 | | - fill: "#66bb6a", |
97 | | - unit: "l", |
98 | | - }, |
99 | | - ], |
| 91 | + bars, |
100 | 92 | rightYAxis: { |
101 | 93 | unit: "l", |
102 | 94 | }, |
|
0 commit comments