From 5c3f91cad299a8b1524b1d8754505cbd0b60040c Mon Sep 17 00:00:00 2001 From: Ismail Ali Date: Sun, 27 Apr 2025 11:25:54 +0200 Subject: [PATCH] feat: integriere Systemspannungen und Temperaturen mit Redux Thunk und Slice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Neues Slice systemVoltTempSlice.ts erstellt für Speicherung von Spannungen und Verlauf - Thunk fetchSystemVoltTempThunk.ts implementiert für asynchrones Laden der Systemwerte - Service fetchSystemVoltTempService.ts verwendet API /api/cpl/systemVoltTempAPIHandler - Mock-Daten in systemVoltTempMockData.js definiert - system.tsx auf Redux umgestellt: useSelector für Werte und Verlauf, fetch per Thunk - store.ts angepasst: systemVoltTempSlice hinzugefügt - Chart.js Darstellung von Spannungen und Temperaturen mit Echtzeit-Update alle 5 Sekunden --- apiMockData/SERVICE/systemVoltTempMockData.js | 9 + components/navigation/Navigation.tsx | 2 +- config/webVersion.ts | 2 +- pages/api/cpl/systemVoltTempAPIHandler.ts | 24 +++ pages/system.tsx | 157 ++++++++++++++++++ redux/slices/systemVoltTempSlice.ts | 38 +++++ redux/store.ts | 2 + redux/thunks/fetchSystemVoltTempThunk.ts | 15 ++ services/fetchSystemVoltTempService.ts | 30 ++++ 9 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 apiMockData/SERVICE/systemVoltTempMockData.js create mode 100644 pages/api/cpl/systemVoltTempAPIHandler.ts create mode 100644 pages/system.tsx create mode 100644 redux/slices/systemVoltTempSlice.ts create mode 100644 redux/thunks/fetchSystemVoltTempThunk.ts create mode 100644 services/fetchSystemVoltTempService.ts diff --git a/apiMockData/SERVICE/systemVoltTempMockData.js b/apiMockData/SERVICE/systemVoltTempMockData.js new file mode 100644 index 0000000..4aa3d99 --- /dev/null +++ b/apiMockData/SERVICE/systemVoltTempMockData.js @@ -0,0 +1,9 @@ +// /apiMockData/SERVICE/systemVoltTempMockData.js +var win_systemVoltTempMockData = { + "+5V": 5.03, + "+15V": 15.02, + "-15V": -15.01, + "-98V": -97.8, + "ADC Temp": 42.5, + "CPU Temp": 47.3, +}; diff --git a/components/navigation/Navigation.tsx b/components/navigation/Navigation.tsx index b53128b..0de220b 100644 --- a/components/navigation/Navigation.tsx +++ b/components/navigation/Navigation.tsx @@ -28,7 +28,7 @@ const Navigation: React.FC = ({ className }) => { { name: "Schaltausgänge ", path: "/digitalOutputs" }, //vorher Digitale Ein -und Ausgänge { name: "Messwertüberwachung ", path: "/analogeEingaenge" }, //vorher Analoge Eingänge { name: "Berichte ", path: "/meldungen" }, - { name: "System ", path: "/meldungen" }, + { name: "System ", path: "/system" }, { name: "Einstellungen ", path: "/einstellungen" }, //{ name: "Zutriffskontrolle", path: "/zutrittskontrolle" }, diff --git a/config/webVersion.ts b/config/webVersion.ts index e283774..f1b257a 100644 --- a/config/webVersion.ts +++ b/config/webVersion.ts @@ -6,5 +6,5 @@ 2: Patch oder Hotfix (Bugfixes oder kleine Änderungen). */ -const webVersion = "1.6.282"; +const webVersion = "1.6.283"; export default webVersion; diff --git a/pages/api/cpl/systemVoltTempAPIHandler.ts b/pages/api/cpl/systemVoltTempAPIHandler.ts new file mode 100644 index 0000000..5dd6ea0 --- /dev/null +++ b/pages/api/cpl/systemVoltTempAPIHandler.ts @@ -0,0 +1,24 @@ +// /pages/api/cpl/systemVoltTempAPIHandler.ts + +import { NextApiRequest, NextApiResponse } from "next"; +import path from "path"; +import fs from "fs/promises"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const filePath = path.join( + process.cwd(), + "apiMockData", + "SERVICE", + "systemVoltTempMockData.js" + ); + + try { + const data = await fs.readFile(filePath, "utf-8"); + res.status(200).send(data); + } catch (error) { + res.status(404).json({ error: "File not found" }); + } +} diff --git a/pages/system.tsx b/pages/system.tsx new file mode 100644 index 0000000..8a9f15c --- /dev/null +++ b/pages/system.tsx @@ -0,0 +1,157 @@ +"use client"; // /pages/system.tsx +import React, { useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { AppDispatch, RootState } from "../redux/store"; // passe an, falls dein Pfad anders ist +import { fetchSystemVoltTempThunk } from "../redux/thunks/fetchSystemVoltTempThunk"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from "chart.js"; +import { Line } from "react-chartjs-2"; + +// Chart.js registrieren +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +); + +const SystemPage = () => { + const dispatch = useDispatch(); + + const voltages = useSelector( + (state: RootState) => state.systemVoltTemp.voltages + ); + const history = useSelector( + (state: RootState) => state.systemVoltTemp.history + ); + + useEffect(() => { + dispatch(fetchSystemVoltTempThunk()); + + const interval = setInterval(() => { + dispatch(fetchSystemVoltTempThunk()); + }, 5000); + + return () => clearInterval(interval); + }, [dispatch]); + + const chartData = { + labels: history.map((h) => new Date(h.time).toLocaleTimeString()), + datasets: [ + { + label: "+5V", + data: history.map((h) => h["+5V"]), + borderColor: "rgba(59,130,246,1)", + backgroundColor: "rgba(59,130,246,0.5)", + fill: false, + }, + { + label: "+15V", + data: history.map((h) => h["+15V"]), + borderColor: "rgba(34,197,94,1)", + backgroundColor: "rgba(34,197,94,0.5)", + fill: false, + }, + { + label: "-15V", + data: history.map((h) => h["-15V"]), + borderColor: "rgba(239,68,68,1)", + backgroundColor: "rgba(239,68,68,0.5)", + fill: false, + }, + { + label: "-98V", + data: history.map((h) => h["-98V"]), + borderColor: "rgba(234,179,8,1)", + backgroundColor: "rgba(234,179,8,0.5)", + fill: false, + }, + { + label: "ADC Temp", + data: history.map((h) => h["ADC Temp"]), + borderColor: "rgba(168,85,247,1)", + backgroundColor: "rgba(168,85,247,0.5)", + fill: false, + }, + { + label: "CPU Temp", + data: history.map((h) => h["CPU Temp"]), + borderColor: "rgba(251,191,36,1)", + backgroundColor: "rgba(251,191,36,0.5)", + fill: false, + }, + ], + }; + + const chartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: false, + grid: { + color: "rgba(200,200,200,0.2)", + }, + title: { + display: true, + text: "Wert", + }, + }, + x: { + grid: { + color: "rgba(200,200,200,0.2)", + }, + title: { + display: true, + text: "Zeit", + }, + }, + }, + plugins: { + legend: { + position: "bottom" as const, + }, + title: { + display: true, + text: "Systemspannungen und Temperaturen Verlauf", + }, + }, + }; + + return ( +
+

+ System Spannungen & Temperaturen +

+ +
+ {Object.entries(voltages).map(([key, value]) => ( +
+

{key}

+

{value}

+
+ ))} +
+ +
+

Verlauf (Messkurve)

+
+ +
+
+
+ ); +}; + +export default SystemPage; diff --git a/redux/slices/systemVoltTempSlice.ts b/redux/slices/systemVoltTempSlice.ts new file mode 100644 index 0000000..1a37220 --- /dev/null +++ b/redux/slices/systemVoltTempSlice.ts @@ -0,0 +1,38 @@ +// /redux/slices/systemVoltTempSlice.ts +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +interface VoltagesState { + voltages: { [key: string]: number }; + history: { time: number; [key: string]: number }[]; +} + +const initialState: VoltagesState = { + voltages: { + "+5V": 0, + "+15V": 0, + "-15V": 0, + "-98V": 0, + "ADC Temp": 0, + "CPU Temp": 0, + }, + history: [], +}; + +const systemVoltTempSlice = createSlice({ + name: "systemVoltTemp", + initialState, + reducers: { + setVoltages(state, action: PayloadAction<{ [key: string]: number }>) { + state.voltages = action.payload; + }, + addHistory( + state, + action: PayloadAction<{ time: number; [key: string]: number }> + ) { + state.history.push(action.payload); + }, + }, +}); + +export const { setVoltages, addHistory } = systemVoltTempSlice.actions; +export default systemVoltTempSlice.reducer; diff --git a/redux/store.ts b/redux/store.ts index e54643b..e8151bb 100644 --- a/redux/store.ts +++ b/redux/store.ts @@ -22,6 +22,7 @@ import selectedChartDataReducer from "./slices/selectedChartDataSlice"; import tdmSingleChartReducer from "./slices/tdmSingleChartSlice"; import tdrReferenceChartDataBySlotReducer from "./slices/tdrReferenceChartDataBySlotSlice"; import loopChartTypeSlice from "./slices/loopChartTypeSlice"; +import systemVoltTempReducer from "./slices/systemVoltTempSlice"; const store = configureStore({ reducer: { @@ -46,6 +47,7 @@ const store = configureStore({ tdmSingleChartSlice: tdmSingleChartReducer, tdrReferenceChartDataBySlotSlice: tdrReferenceChartDataBySlotReducer, loopChartType: loopChartTypeSlice, + systemVoltTemp: systemVoltTempReducer, }, }); diff --git a/redux/thunks/fetchSystemVoltTempThunk.ts b/redux/thunks/fetchSystemVoltTempThunk.ts new file mode 100644 index 0000000..bc15901 --- /dev/null +++ b/redux/thunks/fetchSystemVoltTempThunk.ts @@ -0,0 +1,15 @@ +// /redux/thunks/fetchSystemVoltTempThunk.ts +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { fetchSystemVoltTempService } from "../../services/fetchSystemVoltTempService"; +import { setVoltages, addHistory } from "../slices/systemVoltTempSlice"; + +export const fetchSystemVoltTempThunk = createAsyncThunk( + "systemVoltTemp/fetch", + async (_, { dispatch }) => { + const data = await fetchSystemVoltTempService(); + if (data) { + dispatch(setVoltages(data)); + dispatch(addHistory({ time: Date.now(), ...data })); + } + } +); diff --git a/services/fetchSystemVoltTempService.ts b/services/fetchSystemVoltTempService.ts new file mode 100644 index 0000000..e62543f --- /dev/null +++ b/services/fetchSystemVoltTempService.ts @@ -0,0 +1,30 @@ +// /services/fetchSystemVoltTempService.ts + +export const fetchSystemVoltTempService = async () => { + if (typeof window === "undefined") return null; + + const scriptSrc = + process.env.NEXT_PUBLIC_NODE_ENV === "production" + ? "/CPL?/CPL/SERVICE/voltTemp.js" // ⬅️ später anpassen, wenn CPL liefert + : "/api/cpl/systemVoltTempAPIHandler"; + + await new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = scriptSrc; + script.async = true; + script.onload = () => resolve(); + script.onerror = () => + reject("❌ Fehler beim Laden von systemVoltTempMockData.js"); + document.body.appendChild(script); + }); + + const win = window as any; + const data = win.win_systemVoltTempMockData; + + if (!data) { + console.warn("⚠️ win_systemVoltTempMockData fehlt oder ungültig:", data); + return null; + } + + return data; +};