Skip to content

Commit

Permalink
web: add monthly and yearly chart, restore chart series to original w…
Browse files Browse the repository at this point in the history
…ithout reverse
  • Loading branch information
hoang-rio committed Dec 19, 2024
1 parent 50e3d86 commit cba6bfe
Show file tree
Hide file tree
Showing 28 changed files with 574 additions and 124 deletions.
4 changes: 2 additions & 2 deletions web_viewer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def monthly_chart(_: web.Request):
cursor = db_connection.cursor()
now = datetime.now()
monthly_chart = cursor.execute(
"SELECT id, id, month || '/' || year as month, SUM(pv), SUM(battery_charged), SUM(battery_discharged), SUM(grid_import), SUM(grid_export), SUM(consumption) FROM daily_chart WHERE year = ? GROUP BY month",
"SELECT id, id, id, month || '/' || year as month, SUM(pv), SUM(battery_charged), SUM(battery_discharged), SUM(grid_import), SUM(grid_export), SUM(consumption) FROM daily_chart WHERE year = ? GROUP BY month",
(now.year,)
).fetchall()
res = web.json_response(monthly_chart, headers=VITE_CORS_HEADER)
Expand All @@ -141,7 +141,7 @@ def yearly_chart(_: web.Request):
db_connection = sqlite3.connect(config["DB_NAME"])
cursor = db_connection.cursor()
yearly_chart = cursor.execute(
"SELECT id, id, year, SUM(pv), SUM(battery_charged), SUM(battery_discharged), SUM(grid_import), SUM(grid_export), SUM(consumption) FROM daily_chart GROUP BY year"
"SELECT id, id, id, year, SUM(pv), SUM(battery_charged), SUM(battery_discharged), SUM(grid_import), SUM(grid_export), SUM(consumption) FROM daily_chart GROUP BY year"
).fetchall()
res = web.json_response(yearly_chart, headers=VITE_CORS_HEADER)
return res
Expand Down
13 changes: 7 additions & 6 deletions web_viewer/fe_src/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { useCallback, useEffect, useRef, useState, lazy } from "react";
import "./App.css";
import { IUpdateChart, IInverterData } from "./Intefaces";
import Footer from "./components/Footer";
import Loading from "./components/Loading";

const SystemInformation = lazy(() => import("./components/SystemInformation"));
const Summary = lazy(() => import("./components/Summary"));
const HourlyChart = lazy(() => import("./components/HourlyChart"));
const DailyChart = lazy(() => import("./components/DailyChart"));
const EnergyChart = lazy(() => import("./components/EnergyChart"));

const MAX_RECONNECT_COUNT = 3;

Expand All @@ -16,7 +17,7 @@ function App() {
const selfCloseRef = useRef<boolean>(false);
const reconnectCountRef = useRef<number>(0);
const [isSocketConnected, setIsSocketConnected] = useState<boolean>(true);
const hourlyCharfRef = useRef<IUpdateChart>(null);
const hourlyChartfRef = useRef<IUpdateChart>(null);
const [isInitState, setIsInitState] = useState(true);
const isFetchingRef = useRef(false);

Expand All @@ -43,7 +44,7 @@ function App() {
socket.addEventListener("message", (event) => {
const jsonData = JSON.parse(event.data);
setInverterData(jsonData.inverter_data);
hourlyCharfRef.current?.updateItem(jsonData.hourly_chart_item);
hourlyChartfRef.current?.updateItem(jsonData.hourly_chart_item);
});
socket.addEventListener("close", () => {
document.title = `[Offline] ${import.meta.env.VITE_APP_TITLE}`;
Expand Down Expand Up @@ -116,7 +117,7 @@ function App() {
return (
<>
<div className="d-flex card loading align-center justify-center flex-1">
Loading....
<Loading />
</div>
<Footer />
</>
Expand All @@ -133,8 +134,8 @@ function App() {
onReconnect={connectSocket}
/>
<div className="row chart">
<HourlyChart ref={hourlyCharfRef} className="flex-1 chart-item" />
<DailyChart className="flex-1 chart-item" />
<HourlyChart ref={hourlyChartfRef} className="flex-1 chart-item" />
<EnergyChart className="flex-1 chart-item" />
</div>
<Footer />
</>
Expand Down
6 changes: 5 additions & 1 deletion web_viewer/fe_src/src/Intefaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export interface ICProps {

export interface SeriesItem {
x: number | string;
y: never;
y: never | number;
}

export interface IClassNameProps {
Expand All @@ -71,4 +71,8 @@ export interface ITotal {
grid_import: number;
grid_export: number;
consumption: number;
}

export interface IFetchChart {
fetchChart: () => void;
}
12 changes: 0 additions & 12 deletions web_viewer/fe_src/src/components/DailyChart.css

This file was deleted.

173 changes: 91 additions & 82 deletions web_viewer/fe_src/src/components/DailyChart.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
ForwardedRef,
forwardRef,
memo,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useRef,
useState,
} from "react";
import Chart from "react-apexcharts";
import "./DailyChart.css";
import { IClassNameProps, SeriesItem } from "../Intefaces";
import { IFetchChart, SeriesItem } from "../Intefaces";
import Loading from "./Loading";
import { roundTo } from "./utils";

const SOLAR_PV_SERIE_NAME = "Solar production";

function DailyChart({ className }: IClassNameProps) {
const DailyChart = forwardRef((_, ref: ForwardedRef<IFetchChart>) => {
const [chartData, setChartData] = useState([]);
const [isDark, setIsDark] = useState(false);
const isFetchingRef = useRef<boolean>(false);
Expand All @@ -19,12 +30,12 @@ function DailyChart({ className }: IClassNameProps) {

chartData.forEach((item) => {
const time = new Date(item[3]).getTime();
solarSeries.push({ x: time, y: item[4] });
batteryChargedSeries.push({ x: time, y: item[5] });
batterDischargedSeries.push({ x: time, y: item[6] });
gridImportSeries.push({ x: time, y: item[7] });
gridExportSeries.push({ x: time, y: item[8] });
consumptionSeries.push({ x: time, y: item[9] });
solarSeries.push({ x: time, y: roundTo(item[4]) });
batteryChargedSeries.push({ x: time, y: roundTo(item[5]) });
batterDischargedSeries.push({ x: time, y: roundTo(item[6]) });
gridImportSeries.push({ x: time, y: roundTo(item[7]) });
gridExportSeries.push({ x: time, y: roundTo(item[8]) });
consumptionSeries.push({ x: time, y: roundTo(item[9]) });
});
return [
{
Expand Down Expand Up @@ -65,6 +76,13 @@ function DailyChart({ className }: IClassNameProps) {
isFetchingRef.current = false;
}, [setChartData]);

useImperativeHandle(
ref,
(): IFetchChart => ({
fetchChart: fetchChart,
})
);

useEffect(() => {
fetchChart();
document.addEventListener("visibilitychange", () => {
Expand All @@ -85,78 +103,69 @@ function DailyChart({ className }: IClassNameProps) {
mq.addEventListener("change", (evt) => setIsDark(evt.matches));
}, []);

return (
<div className={`card daily-chart col flex-1 ${className || ""}`}>
<div className="row justify-space-between">
<div className="daily-chart-title">Daily Chart</div>
<div className="row">
<button onClick={() => fetchChart()}>Update</button>
</div>
</div>
<div className="daily-chart-content col flex-1">
{chartData.length ? (
<Chart
type="bar"
series={series.reverse()}
options={{
chart: {
toolbar: {
show: false,
},
height: 300,
zoom: {
allowMouseWheelZoom: false,
},
},
colors: [
"rgb(112, 173, 70)",
"rgb(90, 155, 213)",
"rgb(64, 38, 198)",
"rgb(246, 104, 103)",
"rgb(153, 107, 31)",
"rgb(255, 164, 97)",
].reverse(),
theme: {
mode: isDark ? "dark" : "light",
},
dataLabels: {
enabled: false,
if (chartData.length)
return (
<Chart
type="bar"
series={series}
options={{
chart: {
toolbar: {
show: false,
},
height: 300,
zoom: {
allowMouseWheelZoom: false,
},
},
colors: [
"rgb(112, 173, 70)",
"rgb(90, 155, 213)",
"rgb(64, 38, 198)",
"rgb(246, 104, 103)",
"rgb(153, 107, 31)",
"rgb(255, 164, 97)",
],
theme: {
mode: isDark ? "dark" : "light",
},
dataLabels: {
enabled: false,
},
xaxis: {
type: "datetime",
labels: {
datetimeUTC: false,
format: "dd/MM/yyyy",
},
},
tooltip: {
x: {
format: "dd/MM/yyyy",
},
y: {
formatter(val) {
return `${val} kWh`;
},
xaxis: {
type: "datetime",
labels: {
datetimeUTC: false,
format: "dd/MM/yyyy",
},
},
tooltip: {
x: {
format: "dd/MM/yyyy",
},
y: {
formatter(val) {
return `${val} kWh`;
},
},
},
yaxis: [
{ seriesName: SOLAR_PV_SERIE_NAME, title: { text: "Energy (kWh)" } },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
].reverse(),
}}
/>
) : (
<div className="col flex-1 justify-center align-center">
Loadding...
</div>
)}
</div>
</div>
);
}
},
},
yaxis: [
{
seriesName: SOLAR_PV_SERIE_NAME,
title: { text: "Energy (kWh)" },
},
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
{ seriesName: SOLAR_PV_SERIE_NAME, show: false },
],
}}
/>
);
return <Loading />;
});

DailyChart.displayName = "DailyChart";

export default memo(DailyChart);
24 changes: 24 additions & 0 deletions web_viewer/fe_src/src/components/EnergyChart.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.energy-chart {
margin-top: 10px;
min-height: 300px;
}

.energy-chart-title {
font-weight: bold;
}

.energy-chart-content {
margin-top: 10px;
}

.energy-chart-buttons > button {
margin-right: 10px;
}

.chart-select button{
margin: 0 5px;
}

.chart-select button.active {
background-color: #51ad77;
}
Loading

0 comments on commit cba6bfe

Please sign in to comment.