diff --git a/.env.development b/.env.development index aa51a09..6dc3e5a 100644 --- a/.env.development +++ b/.env.development @@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_USE_CGI=false # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.527 +NEXT_PUBLIC_APP_VERSION=1.6.530 NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) diff --git a/.env.production b/.env.production index dd4dc6f..60d0bd1 100644 --- a/.env.production +++ b/.env.production @@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_USE_CGI=true # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.527 +NEXT_PUBLIC_APP_VERSION=1.6.530 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b8d4c26..a731805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## [1.6.530] – 2025-07-03 + +- fix: KÜ Firmwareupdate + +--- +## [1.6.529] – 2025-07-03 + +- fix: KÜ Firmwareupdate + +--- +## [1.6.528] – 2025-07-03 + +- fix: KÜ Firmwareupdate + +--- ## [1.6.527] – 2025-07-03 - fix: Firmware-Update läuft nun exakt 5 Minuten bis 100 % Fortschritt diff --git a/components/main/system/DetailModal.tsx b/components/main/system/DetailModal.tsx new file mode 100644 index 0000000..a1ecd66 --- /dev/null +++ b/components/main/system/DetailModal.tsx @@ -0,0 +1,96 @@ +// components/main/system/DetailModal.tsx +"use client"; +import React from "react"; +import { Line } from "react-chartjs-2"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; + +type Props = { + isOpen: boolean; + selectedKey: string | null; + onClose: () => void; +}; + +export const DetailModal = ({ isOpen, selectedKey, onClose }: Props) => { + // Mapping: Welcher Redux-Zweig zu welchem selectedKey gehört + const typMap: Record = { + "+5V": "DIA1", + "+15V": "DIA1", + "-15V": "DIA1", + "-98V": "DIA1", + }; + + const typ = selectedKey ? typMap[selectedKey] : null; + + // Redux State abrufen + const reduxData = useSelector((state: RootState) => + typ ? state.systemspannung5Vplus[typ] : [] + ); + + // Zeitstempel und Werte extrahieren + const labels = reduxData.map((e: any) => e.t); + const values = reduxData.map((e: any) => e.i); + + const baseOptions = { + 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: `Verlauf – ${selectedKey}` }, + }, + }; + + if (!isOpen || !selectedKey) return null; + + return ( +
+
+
+

+ Detailansicht: {selectedKey} +

+ +
+ +
+ + +
+ +
+ +
+
+
+ ); +}; diff --git a/components/main/system/SystemCharts.tsx b/components/main/system/SystemCharts.tsx new file mode 100644 index 0000000..7852e18 --- /dev/null +++ b/components/main/system/SystemCharts.tsx @@ -0,0 +1,144 @@ +// components/main/system/SystemCharts.tsx + +import React from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +); + +type HistoryEntry = { + time: string | number | Date; + "+5V": number; + "+15V": number; + "-15V": number; + "-98V": number; + "ADC Temp": number; + "CPU Temp": number; +}; + +type Props = { + history: HistoryEntry[]; +}; + +export const SystemCharts = ({ history }: Props) => { + const labels = history.map((h) => new Date(h.time).toLocaleTimeString()); + const formatValue = (v: number) => v.toFixed(2); + + const baseOptions = { + 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 }, + }, + }; + + return ( +
+
+ formatValue(h["+5V"])), + borderColor: "rgba(59,130,246,1)", + backgroundColor: "rgba(59,130,246,0.5)", + fill: false, + }, + { + label: "+15V", + data: history.map((h) => formatValue(h["+15V"])), + borderColor: "rgba(34,197,94,1)", + backgroundColor: "rgba(34,197,94,0.5)", + fill: false, + }, + { + label: "-15V", + data: history.map((h) => formatValue(h["-15V"])), + borderColor: "rgba(239,68,68,1)", + backgroundColor: "rgba(239,68,68,0.5)", + fill: false, + }, + { + label: "-98V", + data: history.map((h) => formatValue(h["-98V"])), + borderColor: "rgba(234,179,8,1)", + backgroundColor: "rgba(234,179,8,0.5)", + fill: false, + }, + ], + }} + options={{ + ...baseOptions, + plugins: { + ...baseOptions.plugins, + title: { display: true, text: "Systemspannungen" }, + }, + }} + /> +
+ +
+ 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) => + parseFloat(formatValue(h["CPU Temp"])) + ), + borderColor: "rgba(251,191,36,1)", + backgroundColor: "rgba(251,191,36,0.5)", + fill: false, + }, + ], + }} + options={{ + ...baseOptions, + plugins: { + ...baseOptions.plugins, + title: { display: true, text: "Systemtemperaturen" }, + }, + }} + /> +
+
+ ); +}; diff --git a/components/main/system/SystemOverviewGrid.tsx b/components/main/system/SystemOverviewGrid.tsx new file mode 100644 index 0000000..0f4e3e1 --- /dev/null +++ b/components/main/system/SystemOverviewGrid.tsx @@ -0,0 +1,33 @@ +// components/main/system/SystemOverviewGrid.tsx +import React from "react"; + +type Props = { + voltages: Record; + onOpenDetail: (key: string) => void; +}; + +export const SystemOverviewGrid = ({ voltages, onOpenDetail }: Props) => { + const formatValue = (value: number) => value.toFixed(2); + + return ( +
+ {Object.entries(voltages).map(([key, value]) => { + const unit = key.includes("Temp") ? "°C" : "V"; + return ( +
+

{key}

+

+ {formatValue(value)} {unit} + +

+
+ ); + })} +
+ ); +}; diff --git a/package-lock.json b/package-lock.json index e2b64b9..25b8e71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.527", + "version": "1.6.530", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.527", + "version": "1.6.530", "dependencies": { "@fontsource/roboto": "^5.1.0", "@iconify-icons/ri": "^1.2.10", diff --git a/package.json b/package.json index 784fdab..a567b8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.527", + "version": "1.6.530", "private": true, "scripts": { "dev": "next dev", diff --git a/pages/api/cpl/getSystemspannung5VplusHandler.ts b/pages/api/cpl/getSystemspannung5VplusHandler.ts new file mode 100644 index 0000000..d0a9f0b --- /dev/null +++ b/pages/api/cpl/getSystemspannung5VplusHandler.ts @@ -0,0 +1,35 @@ +// @/pages/api/cpl/getSystemspannung5VplusHandler.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 { typ = "DIA0" } = req.query; + + if (!["DIA0", "DIA1", "DIA2"].includes(typ as string)) { + return res + .status(400) + .json({ error: "Ungültiger Typ. Nur DIA0, DIA1 oder DIA2 erlaubt." }); + } + + try { + // Verwende __dirname um relativen Pfad zur API-Datei zu bestimmen + const filePath = path.join( + process.cwd(), // ← Root-Projektverzeichnis + "mocks/device-cgi-simulator/chartsData/systemspannung5Vplus", + `${typ}.json` + ); + + const fileContent = await fs.readFile(filePath, "utf-8"); + const json = JSON.parse(fileContent); + return res.status(200).json(json); + } catch (error) { + console.error("❌ Fehler beim Lesen der Datei:", error); + return res + .status(500) + .json({ error: "Datei konnte nicht gelesen werden." }); + } +} diff --git a/pages/system.tsx b/pages/system.tsx index 5fa4f3d..023cf6a 100644 --- a/pages/system.tsx +++ b/pages/system.tsx @@ -1,30 +1,12 @@ -"use client"; // /pages/system.tsx -import React, { useEffect } from "react"; +// pages/system.tsx +"use client"; +import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { AppDispatch, RootState } from "../redux/store"; import { getSystemVoltTempThunk } from "../redux/thunks/getSystemVoltTempThunk"; -import { - Chart as ChartJS, - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, - TooltipItem, -} from "chart.js"; -import { Line } from "react-chartjs-2"; - -ChartJS.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend -); +import { SystemOverviewGrid } from "@/components/main/system/SystemOverviewGrid"; +import { SystemCharts } from "@/components/main/system/SystemCharts"; +import { DetailModal } from "@/components/main/system/DetailModal"; const SystemPage = () => { const dispatch = useDispatch(); @@ -35,6 +17,9 @@ const SystemPage = () => { (state: RootState) => state.systemVoltTemp.history ); + const [selectedKey, setSelectedKey] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + useEffect(() => { dispatch(getSystemVoltTempThunk()); const interval = setInterval(() => { @@ -45,96 +30,14 @@ const SystemPage = () => { const labels = history.map((h) => new Date(h.time).toLocaleTimeString()); - const formatValue = (value: number) => value.toFixed(2); + const handleOpenDetail = (key: string) => { + setSelectedKey(key); + setIsModalOpen(true); + }; - const voltageDatasets = [ - { - label: "+5V", - data: history.map((h) => formatValue(h["+5V"])), - borderColor: "rgba(59,130,246,1)", - backgroundColor: "rgba(59,130,246,0.5)", - fill: false, - }, - { - label: "+15V", - data: history.map((h) => formatValue(h["+15V"])), - borderColor: "rgba(34,197,94,1)", - backgroundColor: "rgba(34,197,94,0.5)", - fill: false, - }, - { - label: "-15V", - data: history.map((h) => formatValue(h["-15V"])), - borderColor: "rgba(239,68,68,1)", - backgroundColor: "rgba(239,68,68,0.5)", - fill: false, - }, - { - label: "-98V", - data: history.map((h) => formatValue(h["-98V"])), - borderColor: "rgba(234,179,8,1)", - backgroundColor: "rgba(234,179,8,0.5)", - fill: false, - }, - ]; - - const temperatureDatasets = [ - { - 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) => Number(formatValue(h["CPU Temp"]))), - borderColor: "rgba(251,191,36,1)", - backgroundColor: "rgba(251,191,36,0.5)", - fill: false, - }, - ]; - - const baseChartOptions = { - 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, - }, - tooltip: { - callbacks: { - label: function (context: TooltipItem<"line">) { - const label = context.dataset.label || ""; - const value = - context.parsed.y !== null ? context.parsed.y.toFixed(2) : ""; - const unit = label.includes("Temp") ? "°C" : "V"; - return `${label}: ${value} ${unit}`; - }, - }, - }, - }, + const handleCloseDetail = () => { + setSelectedKey(null); + setIsModalOpen(false); }; return ( @@ -142,55 +45,14 @@ const SystemPage = () => {

System Spannungen & Temperaturen

- -
- {Object.entries(voltages).map(([key, value]) => { - const formattedValue = formatValue(value); - const unit = key.includes("Temp") ? "°C" : "V"; - return ( -
-

{key}

-

- {formattedValue} {unit} -

-
- ); - })} -
- -
-
- -
- -
- -
-
+ + + ); }; diff --git a/public/CPL/SERVICE/systemVoltTemp.json b/public/CPL/SERVICE/systemVoltTemp.json index 8d15e3d..cf2e90f 100644 --- a/public/CPL/SERVICE/systemVoltTemp.json +++ b/public/CPL/SERVICE/systemVoltTemp.json @@ -1,3 +1,10 @@ { - "win_systemVoltTemp": ["AAV09", "AAV11", "AAV15", "AAV16", "AAV17", "AAV18"] + "win_systemVoltTemp": [ + "<%=AAV09%>", + "<%=AAV11%>", + "<%=AAV15%>", + "<%=AAV16%>", + "<%=AAV17%>", + "<%=AAV18%>" + ] } diff --git a/redux/slices/systemspannung5VplusSlice.ts b/redux/slices/systemspannung5VplusSlice.ts new file mode 100644 index 0000000..a3bb817 --- /dev/null +++ b/redux/slices/systemspannung5VplusSlice.ts @@ -0,0 +1,48 @@ +// redux/slices/systemspannung5VplusSlice.ts +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { getSystemspannung5VplusThunk } from "../thunks/getSystemspannung5VplusThunk"; + +type StateType = { + DIA0: any[]; // alle Werte + DIA1: any[]; // stündlich + DIA2: any[]; // täglich + isLoading: boolean; + error: string | null; +}; + +const initialState: StateType = { + DIA0: [], + DIA1: [], + DIA2: [], + isLoading: false, + error: null, +}; + +export const systemspannung5VplusSlice = createSlice({ + name: "systemspannung5Vplus", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(getSystemspannung5VplusThunk.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase( + getSystemspannung5VplusThunk.fulfilled, + ( + state, + action: PayloadAction<{ typ: "DIA0" | "DIA1" | "DIA2"; data: any[] }> + ) => { + state.isLoading = false; + state[action.payload.typ] = action.payload.data; + } + ) + .addCase(getSystemspannung5VplusThunk.rejected, (state, action) => { + state.isLoading = false; + state.error = action.payload as string; + }); + }, +}); + +export default systemspannung5VplusSlice.reducer; diff --git a/redux/store.ts b/redux/store.ts index bc46e24..ddc4969 100644 --- a/redux/store.ts +++ b/redux/store.ts @@ -29,6 +29,7 @@ import messagesReducer from "./slices/messagesSlice"; import firmwareUpdateReducer from "@/redux/slices/firmwareUpdateSlice"; import confirmModalReducer from "./slices/confirmModalSlice"; import firmwareProgressReducer from "./slices/firmwareProgressSlice"; +import systemspannung5VplusReducer from "./slices/systemspannung5VplusSlice"; const store = configureStore({ reducer: { @@ -60,6 +61,7 @@ const store = configureStore({ firmwareUpdate: firmwareUpdateReducer, confirmModal: confirmModalReducer, firmwareProgress: firmwareProgressReducer, + systemspannung5Vplus: systemspannung5VplusReducer, }, }); diff --git a/redux/thunks/getSystemspannung5VplusThunk.ts b/redux/thunks/getSystemspannung5VplusThunk.ts new file mode 100644 index 0000000..1012ebd --- /dev/null +++ b/redux/thunks/getSystemspannung5VplusThunk.ts @@ -0,0 +1,16 @@ +// redux/thunks/getSystemspannung5VplusThunk.ts +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { fetchSystemspannung5VplusService } from "@/services/fetchSystemspannung5VplusService"; + +export const getSystemspannung5VplusThunk = createAsyncThunk( + "systemspannung5Vplus/fetch", + async (typ: "DIA0" | "DIA1" | "DIA2", thunkAPI) => { + try { + const data = await fetchSystemspannung5VplusService(typ); + return { typ, data }; + } catch (error) { + console.error("Fehler in getSystemspannung5VplusThunk:", error); + return thunkAPI.rejectWithValue("Fehler beim Laden der 5V-Daten"); + } + } +); diff --git a/services/fetchSystemspannung5VplusService.ts b/services/fetchSystemspannung5VplusService.ts new file mode 100644 index 0000000..5fda26b --- /dev/null +++ b/services/fetchSystemspannung5VplusService.ts @@ -0,0 +1,25 @@ +// services/fetchSystemspannung5VplusService.ts + +type Typ = "DIA0" | "DIA1" | "DIA2"; + +/** + * Holt Messwerte für +5V aus der passenden JSON-Datei über die API + * @param typ - Typ der Daten: DIA0 = alle, DIA1 = stündlich, DIA2 = täglich + */ +export const fetchSystemspannung5VplusService = async (typ: Typ) => { + try { + const res = await fetch( + `/api/cpl/getSystemspannung5VplusHandler?typ=${typ}` + ); + + if (!res.ok) { + throw new Error(`Fehler beim Abrufen: ${res.status}`); + } + + const data = await res.json(); + return data; + } catch (err) { + console.error("❌ Fehler in fetchSystemspannung5VplusService:", err); + return null; + } +};