- OPC-UA bezogene Variablen aus `variablesSlice` entfernt und in `opcuaSettingsSlice` ausgelagert
- Neue Redux Actions für:
- `setOpcUaZustand` (OPC-UA Zustand setzen)
- `setOpcUaEncryption` (Verschlüsselung setzen)
- `setOpcUaActiveClientCount` (Anzahl aktiver Clients setzen)
- `setOpcUaNodesetName` (Nodeset-Name setzen)
- `addOpcUaUser` & `removeOpcUaUser` (Benutzerverwaltung)
- `loadWindowVariables.ts` angepasst, um OPC-UA-Daten in `opcuaSettingsSlice` zu speichern
- Benutzerverwaltung optimiert:
- Manuell hinzugefügte Benutzer bleiben erhalten
- Benutzer werden nur aktualisiert, wenn sich `window.win_opcUaUsers` ändert
- Keine automatische Statusumschaltung mehr beim OPC-UA-Server-Button
Jetzt ist die OPC-UA Verwaltung sauber getrennt und stabil! 🚀
237 lines
6.8 KiB
TypeScript
237 lines
6.8 KiB
TypeScript
// /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 {
|
|
[key: string]: any;
|
|
}
|
|
|
|
// ✅ Interface für System-Einstellungen im Redux-Store
|
|
interface SystemSettings {
|
|
deviceName: string;
|
|
mac1: string;
|
|
ip: string;
|
|
subnet: string;
|
|
gateway: string;
|
|
cplInternalTimestamp: string;
|
|
ntp1: string;
|
|
ntp2: string;
|
|
ntp3: string;
|
|
ntpTimezone: string;
|
|
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<Record<string, any>> {
|
|
return new Promise((resolve, reject) => {
|
|
const requiredVars: string[] = [
|
|
"win_last20Messages",
|
|
"win_deviceName",
|
|
"win_mac1",
|
|
"win_ip",
|
|
"win_subnet",
|
|
"win_gateway",
|
|
"win_cplInternalTimestamp",
|
|
"win_ntp1",
|
|
"win_ntp2",
|
|
"win_ntp3",
|
|
"win_systemZeit",
|
|
"win_ntpTimezone",
|
|
"win_ntpActive",
|
|
"win_de_state",
|
|
"win_counter",
|
|
"win_flutter",
|
|
"win_kueOnline",
|
|
"win_kueID",
|
|
"win_kuePSTmMinus96V",
|
|
"win_kueAlarm1",
|
|
"win_kueAlarm2",
|
|
"win_kueIso",
|
|
"win_kueResidence",
|
|
"win_kueCableBreak",
|
|
"win_kueGroundFault",
|
|
"win_kueLimit1",
|
|
"win_kueLimit2Low",
|
|
"win_kueDelay1",
|
|
"win_kueLoopInterval",
|
|
"win_kueVersion",
|
|
"win_tdrAtten",
|
|
"win_tdrPulse",
|
|
"win_tdrSpeed",
|
|
"win_tdrAmp",
|
|
"win_tdrTrigger",
|
|
"win_tdrLocation",
|
|
"win_tdrActive",
|
|
"win_kueOverflow",
|
|
"win_tdrLast",
|
|
"win_appVersion",
|
|
"win_analogeEingaenge1",
|
|
"win_analogeEingaenge2",
|
|
"win_analogeEingaenge3",
|
|
"win_analogeEingaenge4",
|
|
"win_analogeEingaenge5",
|
|
"win_analogeEingaenge6",
|
|
"win_analogeEingaenge7",
|
|
"win_analogeEingaenge8",
|
|
"win_da_state",
|
|
"win_da_bezeichnung",
|
|
"win_opcUaZustand",
|
|
"win_opcUaActiveClientCount",
|
|
"win_opcUaNodesetName",
|
|
"win_opcUaEncryption", // ✅ NEU: Verschlüsselung von OPC-UA
|
|
"win_opcUaUsers", // ✅ NEU: OPC-UA Benutzerliste
|
|
];
|
|
|
|
const scripts: string[] = [
|
|
"da.js",
|
|
"de.js",
|
|
"ae.js",
|
|
"kueData.js",
|
|
"Start.js",
|
|
"System.js",
|
|
"opcua.js",
|
|
];
|
|
|
|
const loadScript = (src: string): Promise<void> => {
|
|
return new Promise((resolve, reject) => {
|
|
const script = document.createElement("script");
|
|
const environment = process.env.NEXT_PUBLIC_NODE_ENV || "production";
|
|
script.src =
|
|
environment === "production"
|
|
? `/CPL?/CPL/SERVICE/${src}`
|
|
: `/CPLmockData/SERVICE/${src}`;
|
|
script.async = true;
|
|
script.onload = () => resolve();
|
|
script.onerror = () => reject(new Error(`Script load error: ${src}`));
|
|
document.head.appendChild(script);
|
|
});
|
|
};
|
|
|
|
// ✅ Lade alle Skripte nacheinander
|
|
scripts
|
|
.reduce(
|
|
(promise, script) => promise.then(() => loadScript(script)),
|
|
Promise.resolve()
|
|
)
|
|
.then(() => {
|
|
const win = window as unknown as CustomWindow;
|
|
|
|
// ✅ Erstelle ein Objekt mit allen geladenen Variablen
|
|
const variablesObj: Record<string, any> = requiredVars.reduce(
|
|
(acc, variable) => {
|
|
if (win[variable] !== undefined) {
|
|
acc[variable.replace("win_", "")] = win[variable];
|
|
}
|
|
return acc;
|
|
},
|
|
{}
|
|
);
|
|
|
|
// ✅ Redux mit Systemvariablen aktualisieren
|
|
loadAndStoreSystemSettings(win);
|
|
loadAndStoreOpcUaSettings(win);
|
|
|
|
resolve(variablesObj);
|
|
})
|
|
.catch((error) => {
|
|
console.error("Fehler beim Laden eines Skripts:", error);
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// ✅ Funktion zum Speichern von System-Variablen in Redux
|
|
const loadAndStoreSystemSettings = (win: CustomWindow) => {
|
|
const settings: SystemSettings = {
|
|
deviceName: win.win_deviceName || "",
|
|
mac1: win.win_mac1 || "",
|
|
ip: win.win_ip || "",
|
|
subnet: win.win_subnet || "",
|
|
gateway: win.win_gateway || "",
|
|
cplInternalTimestamp: win.win_cplInternalTimestamp || "",
|
|
ntp1: win.win_ntp1 || "",
|
|
ntp2: win.win_ntp2 || "",
|
|
ntp3: win.win_ntp3 || "",
|
|
ntpTimezone: win.win_ntpTimezone || "",
|
|
ntpActive: win.win_ntpActive || false,
|
|
};
|
|
|
|
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 })
|
|
);
|
|
}
|
|
});
|
|
}
|
|
};
|