+
+ {/* ✅ Neuen Benutzer hinzufügen */}
+
- setNewUser({ ...newUser, username: e.target.value })
- }
- className="p-2 border rounded mr-2"
+ value={newUsername}
+ onChange={(e) => setNewUsername(e.target.value)}
+ className="p-2 border rounded w-1/3"
/>
- setNewUser({ ...newUser, password: e.target.value })
- }
- className="p-2 border rounded mr-2"
+ value={newPassword}
+ onChange={(e) => setNewPassword(e.target.value)}
+ className="p-2 border rounded w-1/3"
/>
diff --git a/config/webVersion.ts b/config/webVersion.ts
index 0800972..ecd1f86 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.91";
+const webVersion = "1.6.92";
export default webVersion;
diff --git a/redux/slices/opcuaSettingsSlice.ts b/redux/slices/opcuaSettingsSlice.ts
new file mode 100644
index 0000000..492ea4c
--- /dev/null
+++ b/redux/slices/opcuaSettingsSlice.ts
@@ -0,0 +1,76 @@
+// redux/slices/opcuaSettingsSlice.ts
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+
+interface OPCUAUser {
+ id: number;
+ username: string;
+ password: string;
+}
+
+interface OPCUASettingsState {
+ isEnabled: boolean;
+ encryption: string;
+ opcUaZustand: string;
+ opcUaActiveClientCount: number;
+ opcUaNodesetName: string;
+ users: OPCUAUser[];
+}
+
+const initialState: OPCUASettingsState = {
+ isEnabled: true,
+ encryption: "None",
+ opcUaZustand: "Offline",
+ opcUaActiveClientCount: 0,
+ opcUaNodesetName: "DefaultNodeset",
+ users: [
+ { id: 1, username: "admin", password: "admin123" },
+ { id: 2, username: "user1", password: "user123" },
+ ],
+};
+
+const opcuaSettingsSlice = createSlice({
+ name: "opcuaSettings",
+ initialState,
+ reducers: {
+ toggleOpcUaServer(state) {
+ state.isEnabled = !state.isEnabled;
+ },
+ setOpcUaEncryption(state, action: PayloadAction) {
+ state.encryption = action.payload;
+ },
+ setOpcUaZustand(state, action: PayloadAction) {
+ state.opcUaZustand = action.payload;
+ },
+ setOpcUaActiveClientCount(state, action: PayloadAction) {
+ state.opcUaActiveClientCount = action.payload;
+ },
+ setOpcUaNodesetName(state, action: PayloadAction) {
+ state.opcUaNodesetName = action.payload;
+ },
+ addOpcUaUser(
+ state,
+ action: PayloadAction<{ username: string; password: string }>
+ ) {
+ const newUser = {
+ id: state.users.length + 1,
+ ...action.payload,
+ };
+ state.users.push(newUser);
+ },
+ removeOpcUaUser(state, action: PayloadAction) {
+ state.users = state.users.filter((user) => user.id !== action.payload);
+ },
+ },
+});
+
+export const {
+ toggleOpcUaServer,
+ setOpcUaEncryption,
+ setOpcUaZustand,
+ setOpcUaActiveClientCount,
+ setOpcUaNodesetName,
+ addOpcUaUser,
+ removeOpcUaUser,
+} = opcuaSettingsSlice.actions;
+
+export default opcuaSettingsSlice.reducer;
diff --git a/redux/store.ts b/redux/store.ts
index 75a1543..2d278b6 100644
--- a/redux/store.ts
+++ b/redux/store.ts
@@ -8,6 +8,7 @@ import digitalInputsReducer from "./slices/digitalInputsSlice";
import kabelueberwachungChartReducer from "./slices/kabelueberwachungChartSlice";
import dashboardReducer from "./slices/dashboardSlice";
import systemSettingsReducer from "./slices/systemSettingsSlice";
+import opcuaSettingsReducer from "./slices/opcuaSettingsSlice";
const store = configureStore({
reducer: {
@@ -19,6 +20,7 @@ const store = configureStore({
kabelueberwachungChart: kabelueberwachungChartReducer,
dashboard: dashboardReducer,
systemSettings: systemSettingsReducer,
+ opcuaSettings: opcuaSettingsReducer,
},
});
diff --git a/utils/loadWindowVariables.ts b/utils/loadWindowVariables.ts
index 2b814b5..cedcb12 100644
--- a/utils/loadWindowVariables.ts
+++ b/utils/loadWindowVariables.ts
@@ -1,5 +1,15 @@
+// /utils/loadWindowVariables.ts
import store from "../redux/store";
import { setSystemSettings } from "../redux/slices/systemSettingsSlice";
+import {
+ toggleOpcUaServer,
+ setOpcUaEncryption,
+ setOpcUaZustand,
+ setOpcUaActiveClientCount,
+ setOpcUaNodesetName,
+ addOpcUaUser,
+ removeOpcUaUser,
+} from "../redux/slices/opcuaSettingsSlice";
// ✅ Interface für `window`-Objekt zur TypeScript-Sicherheit
interface CustomWindow extends Window {
@@ -21,6 +31,16 @@ interface SystemSettings {
ntpActive: boolean;
}
+// ✅ Interface für OPC-UA Einstellungen im Redux-Store
+interface OpcUaSettings {
+ isEnabled: boolean;
+ encryption: string;
+ opcUaZustand: string;
+ opcUaActiveClientCount: number;
+ opcUaNodesetName: string;
+ users: { id: number; username: string; password: string }[];
+}
+
// ✅ Hauptfunktion zum Laden von `window`-Variablen
export async function loadWindowVariables(): Promise> {
return new Promise((resolve, reject) => {
@@ -73,11 +93,13 @@ export async function loadWindowVariables(): Promise> {
"win_analogeEingaenge6",
"win_analogeEingaenge7",
"win_analogeEingaenge8",
+ "win_da_state",
+ "win_da_bezeichnung",
"win_opcUaZustand",
"win_opcUaActiveClientCount",
"win_opcUaNodesetName",
- "win_da_state",
- "win_da_bezeichnung",
+ "win_opcUaEncryption", // ✅ NEU: Verschlüsselung von OPC-UA
+ "win_opcUaUsers", // ✅ NEU: OPC-UA Benutzerliste
];
const scripts: string[] = [
@@ -127,6 +149,7 @@ export async function loadWindowVariables(): Promise> {
// ✅ Redux mit Systemvariablen aktualisieren
loadAndStoreSystemSettings(win);
+ loadAndStoreOpcUaSettings(win);
resolve(variablesObj);
})
@@ -155,3 +178,59 @@ const loadAndStoreSystemSettings = (win: CustomWindow) => {
store.dispatch(setSystemSettings(settings));
};
+
+// ✅ Funktion zum Speichern von OPC-UA Variablen in Redux
+const loadAndStoreOpcUaSettings = (win: CustomWindow) => {
+ // ✅ Aktuellen Redux-Status holen
+ const currentState = store.getState().opcuaSettings;
+
+ // ✅ Nur setzen, wenn sich der Zustand geändert hat
+ if (currentState.opcUaZustand !== win.win_opcUaZustand) {
+ store.dispatch(setOpcUaZustand(win.win_opcUaZustand || "Offline"));
+ }
+
+ // ✅ Nur setzen, wenn sich die Verschlüsselung geändert hat
+ if (currentState.encryption !== win.win_opcUaEncryption) {
+ store.dispatch(setOpcUaEncryption(win.win_opcUaEncryption || "None"));
+ }
+
+ // ✅ Nur setzen, wenn sich die Anzahl der aktiven Clients geändert hat
+ if (currentState.opcUaActiveClientCount !== win.win_opcUaActiveClientCount) {
+ store.dispatch(
+ setOpcUaActiveClientCount(win.win_opcUaActiveClientCount || 0)
+ );
+ }
+
+ // ✅ Nur setzen, wenn sich der Nodeset-Name geändert hat
+ if (currentState.opcUaNodesetName !== win.win_opcUaNodesetName) {
+ store.dispatch(
+ setOpcUaNodesetName(win.win_opcUaNodesetName || "DefaultNodeset")
+ );
+ }
+
+ // ✅ Benutzer synchronisieren (aber nicht überschreiben, wenn manuell hinzugefügt)
+ if (Array.isArray(win.win_opcUaUsers) && win.win_opcUaUsers.length > 0) {
+ const newUsers = win.win_opcUaUsers;
+ const currentUsers = currentState.users;
+
+ // ✅ Vorhandene Benutzer entfernen, die nicht mehr in `window` sind
+ currentUsers.forEach((user) => {
+ if (!newUsers.some((newUser) => newUser.username === user.username)) {
+ store.dispatch(removeOpcUaUser(user.id));
+ }
+ });
+
+ // ✅ Nur neue Benutzer hinzufügen, falls sie nicht existieren
+ newUsers.forEach((user) => {
+ if (
+ !currentUsers.some(
+ (existingUser) => existingUser.username === user.username
+ )
+ ) {
+ store.dispatch(
+ addOpcUaUser({ username: user.username, password: user.password })
+ );
+ }
+ });
+ }
+};