Vielen Dank Euch beiden.
Ich habe das Script nun fertig und läuft.
DeepSeek hat mir dabei geholfen...
// Konfiguration
const SOURCE_DATAPOINT_PROGRAM_MODE = 'homeconnect.0.xxxxxxxxxxxxxxxxxx.programs.active.options.LaundryCare_WasherDryer_Option_ProgramMode';
const SOURCE_DATAPOINT_PROCESS_PHASE = 'homeconnect.0.xxxxxxxxxxxxxxxxxx.programs.active.options.LaundryCare_Common_Option_ProcessPhase';
const SOURCE_DATAPOINT_STATUS = 'homeconnect.0.xxxxxxxxxxxxxxxxxx.status.BSH_Common_Status_OperationState';
const SOURCE_DATAPOINT_DOOR_STATE = 'homeconnect.0.xxxxxxxxxxxxxxxxxx.status.BSH_Common_Status_DoorState'; // Datenpunkt für Türstatus
const SOURCE_DATAPOINT_ACTIVE_PROGRAM = 'homeconnect.0.xxxxxxxxxxxxxxxxxx.programs.active.BSH_Common_Root_ActiveProgram'; // Neuer Datenpunkt
const TARGET_DATAPOINT_PROGRAM_MODE = 'Geräte.0.Waschtrockner-Bosch.Programm';
const TARGET_DATAPOINT_PROCESS_PHASE = 'Geräte.0.Waschtrockner-Bosch.ProgrammPhase';
const TARGET_DATAPOINT_STATUS = 'Geräte.0.Waschtrockner-Bosch.Status';
const TARGET_DATAPOINT_DOOR_STATE = 'Geräte.0.Waschtrockner-Bosch.Türstatus'; // Ziel-Datenpunkt für Türstatus
const TARGET_DATAPOINT_ACTIVE_PROGRAM = 'Geräte.0.Waschtrockner-Bosch.Programm-Läuft'; // Neuer Ziel-Datenpunkt
const RETRY_DELAY_1 = 7000; // Verzögerung für den 1. Versuch
const RETRY_DELAY_2 = 5000; // Verzögerung für den 2. Versuch
const STATUS_CHECK_DELAY = 2000; // Verzögerung für die Statusüberprüfung
// Globale Variablen
let programModeListenerId;
let processPhaseListenerId;
let statusListenerId;
let doorStateListenerId;
let activeProgramListenerId;
let triggerActive = false;
let programModeDatapointExists = false;
let processPhaseDatapointExists = false;
let washingMachineRunning = false;
let retryTimeoutId; // Timeout-ID für den 2. Versuch
// Funktion zum Extrahieren des Werts und Schreiben in den Ziel-Datenpunkt
function updateValue(state, targetDatapoint) {
if (state && state.val !== undefined && state.val !== null && state.val !== '') {
let value = state.val;
if (typeof value === 'string') {
// Extrahiere den letzten Teil des Strings (z. B. "Open" aus "BSH.Common.EnumType.DoorState.Open")
value = value.substring(value.lastIndexOf('.') + 1);
}
console.log(`Schreibe Wert in ${targetDatapoint}: ${value}`); // Wert wird hier protokolliert
setState(targetDatapoint, value, true);
} else {
console.log(`Fehler: state oder state.val ist undefined, null oder leer für ${targetDatapoint}. Setze Standardwert.`);
setState(targetDatapoint, 'Unbekannt', true); // Setze einen Standardwert
}
}
// Funktion zum Extrahieren des aktiven Programms
function updateActiveProgram(state, targetDatapoint) {
if (state && state.val !== undefined && state.val !== null && state.val !== '') {
let value = state.val;
if (typeof value === 'string') {
// Entferne die Punkte am Ende des Strings
value = value.replace(/\.+$/, '');
// Extrahiere den letzten Teil des Strings (z. B. "EasyCare" aus "LaundryCare.WasherDryer.Program.EasyCare")
value = value.substring(value.lastIndexOf('.') + 1);
}
console.log(`Schreibe Wert in ${targetDatapoint}: ${value}`); // Wert wird hier protokolliert
setState(targetDatapoint, value, true);
} else {
console.log(`Fehler: state oder state.val ist undefined, null oder leer für ${targetDatapoint}. Setze Standardwert.`);
setState(targetDatapoint, 'Unbekannt', true); // Setze einen Standardwert
}
}
// Funktion zum Einrichten eines Listeners für einen Datenpunkt
function setupListener(sourceDatapoint, targetDatapoint, updateFunction = updateValue) {
getObject(sourceDatapoint, (err, obj) => {
if (!err && obj) {
console.log(`Datenpunkt ${sourceDatapoint} existiert. Listener wird eingerichtet.`);
// Initialen Wert abrufen und schreiben
getState(sourceDatapoint, (err, state) => {
if (!err && state && state.val !== undefined && state.val !== null && state.val !== '') {
updateFunction(state, targetDatapoint);
} else {
console.log(`Fehler beim Lesen des initialen Zustands für ${sourceDatapoint}. Setze Standardwert.`);
setState(targetDatapoint, 'Unbekannt', true); // Setze einen Standardwert
}
});
// Listener für Änderungen am Datenpunkt
const listenerId = on({ id: sourceDatapoint, change: 'any' }, (state) => {
console.log(`Änderung erkannt für ${sourceDatapoint}:`, state);
if (state.val === undefined || state.val === null || state.val === '') {
console.log(`Warnung: Der Wert für ${sourceDatapoint} ist undefined, null oder leer.`);
// Versuche, den Wert erneut abzurufen
getState(sourceDatapoint, (err, state) => {
if (!err && state && state.val !== undefined && state.val !== null && state.val !== '') {
updateFunction(state, targetDatapoint);
} else {
console.log(`Fehler beim erneuten Abruf des Zustands für ${sourceDatapoint}.`);
}
});
} else {
updateFunction(state, targetDatapoint);
}
});
if (sourceDatapoint === SOURCE_DATAPOINT_PROGRAM_MODE) {
programModeListenerId = listenerId;
programModeDatapointExists = true;
} else if (sourceDatapoint === SOURCE_DATAPOINT_PROCESS_PHASE) {
processPhaseListenerId = listenerId;
processPhaseDatapointExists = true;
} else if (sourceDatapoint === SOURCE_DATAPOINT_STATUS) {
statusListenerId = listenerId;
} else if (sourceDatapoint === SOURCE_DATAPOINT_DOOR_STATE) {
doorStateListenerId = listenerId;
console.log(`Listener für Türstatus (${sourceDatapoint}) erfolgreich eingerichtet.`);
} else if (sourceDatapoint === SOURCE_DATAPOINT_ACTIVE_PROGRAM) {
activeProgramListenerId = listenerId;
console.log(`Listener für aktives Programm (${sourceDatapoint}) erfolgreich eingerichtet.`);
}
} else {
console.log(`Datenpunkt ${sourceDatapoint} existiert nicht oder Fehler:`, err);
}
});
}
// Funktion zum Stoppen des Skripts und Aufräumen
function stopScript() {
console.log("Skript wird gestoppt und aufgeräumt.");
washingMachineRunning = false;
triggerActive = false;
programModeDatapointExists = false;
processPhaseDatapointExists = false;
if (programModeListenerId) {
clearTimeout(programModeListenerId);
programModeListenerId = null;
}
if (processPhaseListenerId) {
clearTimeout(processPhaseListenerId);
processPhaseListenerId = null;
}
if (statusListenerId) {
clearTimeout(statusListenerId);
statusListenerId = null;
}
if (doorStateListenerId) {
clearTimeout(doorStateListenerId);
doorStateListenerId = null;
}
if (activeProgramListenerId) {
clearTimeout(activeProgramListenerId);
activeProgramListenerId = null;
}
if (retryTimeoutId) {
clearTimeout(retryTimeoutId); // Stoppe den 2. Versuch, falls er aktiv ist
retryTimeoutId = null;
}
}
// Funktion zum Überprüfen des Trigger-Zustands
function checkTrigger(state) {
// Überprüfen, ob state oder state.val undefined oder null ist
if (!state || state.val === undefined || state.val === null || state.val === '') {
console.log("Status ist leer, undefined oder null. Warte...");
setTimeout(() => {
getState(SOURCE_DATAPOINT_STATUS, (err, state) => {
if (!err && state && state.val !== undefined && state.val !== null && state.val !== '') {
checkTrigger(state); // Erneut versuchen, wenn ein gültiger Status verfügbar ist
} else {
console.log("Status immer noch nicht verfügbar. Warte weiter...");
}
});
}, STATUS_CHECK_DELAY); // Verzögerung vor dem erneuten Versuch
return;
}
const status = state.val;
// Überprüfen, ob der Status ein gültiger String ist
if (typeof status !== 'string') {
console.log("Status ist kein gültiger String. Warte...");
return;
}
// Schreibe jeden Statuswert in den Ziel-Datenpunkt
updateValue(state, TARGET_DATAPOINT_STATUS);
// Starte oder stoppe das Skript basierend auf dem Status
if (status === 'BSH.Common.EnumType.OperationState.Inactive') {
console.log("Waschmaschine inaktiv. Skript wird gestoppt.");
stopScript();
} else if (status === 'BSH.Common.EnumType.OperationState.Ready') {
console.log(`Waschmaschine bereit (Status: ${status}). Listener für OperationState und DoorState werden gestartet.`);
if (!statusListenerId) {
setupListener(SOURCE_DATAPOINT_STATUS, TARGET_DATAPOINT_STATUS);
}
if (!doorStateListenerId) {
setupListener(SOURCE_DATAPOINT_DOOR_STATE, TARGET_DATAPOINT_DOOR_STATE);
}
} else if (status === 'BSH.Common.EnumType.OperationState.Run') {
console.log(`Waschmaschine läuft (Status: ${status}). Listener für ProgramMode, ProcessPhase und ActiveProgram werden gestartet.`);
if (!programModeDatapointExists || !processPhaseDatapointExists) {
setTimeout(() => {
console.log('Überprüfe und starte Listener für Datenpunkte (1. Versuch)...');
if (!programModeDatapointExists) {
setupListener(SOURCE_DATAPOINT_PROGRAM_MODE, TARGET_DATAPOINT_PROGRAM_MODE);
programModeDatapointExists = true; // Flag direkt setzen
}
if (!processPhaseDatapointExists) {
setupListener(SOURCE_DATAPOINT_PROCESS_PHASE, TARGET_DATAPOINT_PROCESS_PHASE);
processPhaseDatapointExists = true; // Flag direkt setzen
}
if (!activeProgramListenerId) {
setupListener(SOURCE_DATAPOINT_ACTIVE_PROGRAM, TARGET_DATAPOINT_ACTIVE_PROGRAM, updateActiveProgram);
}
// Überprüfen, ob der zweite Versuch notwendig ist
if (!programModeDatapointExists || !processPhaseDatapointExists) {
retryTimeoutId = setTimeout(() => {
console.log('Überprüfe und starte Listener für Datenpunkte (2. Versuch)...');
if (!programModeDatapointExists) {
setupListener(SOURCE_DATAPOINT_PROGRAM_MODE, TARGET_DATAPOINT_PROGRAM_MODE);
}
if (!processPhaseDatapointExists) {
setupListener(SOURCE_DATAPOINT_PROCESS_PHASE, TARGET_DATAPOINT_PROCESS_PHASE);
}
if (!activeProgramListenerId) {
setupListener(SOURCE_DATAPOINT_ACTIVE_PROGRAM, TARGET_DATAPOINT_ACTIVE_PROGRAM, updateActiveProgram);
}
}, RETRY_DELAY_2);
}
}, RETRY_DELAY_1);
}
}
}
// Überwache den Status-Datenpunkt
on({ id: SOURCE_DATAPOINT_STATUS, change: 'any' }, (state) => {
checkTrigger(state);
});
// Initiale Überprüfung des Status
setTimeout(() => {
getState(SOURCE_DATAPOINT_STATUS, (err, state) => {
if (!err && state && state.val !== undefined && state.val !== null && state.val !== '') {
checkTrigger(state);
} else {
console.log("Initialer Status ist leer, undefined oder null. Überprüfe später erneut.");
setTimeout(() => {
getState(SOURCE_DATAPOINT_STATUS, (err, state) => {
if (!err && state && state.val !== undefined && state.val !== null && state.val !== '') {
checkTrigger(state);
} else {
console.log("Immer noch kein initialer Status. Skript wird beendet.");
}
});
}, STATUS_CHECK_DELAY); // Verzögerung vor dem erneuten Versuch
}
});
}, STATUS_CHECK_DELAY); // Verzögerung vor der initialen Überprüfung
// Listener für den Status-Datenpunkt direkt starten
setupListener(SOURCE_DATAPOINT_STATUS, TARGET_DATAPOINT_STATUS);
// Listener für den Türstatus-Datenpunkt starten
setupListener(SOURCE_DATAPOINT_DOOR_STATE, TARGET_DATAPOINT_DOOR_STATE);
// Listener für den aktiven Programm-Datenpunkt starten
setupListener(SOURCE_DATAPOINT_ACTIVE_PROGRAM, TARGET_DATAPOINT_ACTIVE_PROGRAM, updateActiveProgram);