NEWS
Neuer Alexa-Skill "iobroker.assistant"
-
exakt die prozentuale Position angeben.
Echte Prozent?
Oder zB. 0.6 von max 1@Homoran
Das ist etwas verrückt. In der Alexa App geht es gar nicht einen ordentlichen Stand des Rollos auszuwählen. Somit kann ich Alexa-basierte Szenen schon mal nicht erstellen. Ich habe aktuell ein kleines Script geschrieben, welches mir die Zustände spiegelt. Damit sowohl actual als auch set in die Config ordentlich übernommen werden. Wenn ich nun die Datenpunkte des Scriptes nehme, dann kann ich zumindest per Spracheingabe "Alexa, setze Wohnzimmer Rollo rechts auf 50|40|30(etc)" das Rollo halb hoch fahren. Richtig elegant ist das nicht, funktioniert aber für's erste.Du bringst mich aber auf eine Idee. Wenn die Alexa App keine Prozentwerte, sondern dezimalwerte übergibt, geht es natürlich so gut wie immer auf 0. Ich teste mal, ob ich irgendwas schlaues mitloggen kann.
/************************************************************ * Shelly Cover -> Alexa V3 Alias (SET / ACTUAL) * Debug-Version mit ausführlichem Logging ************************************************************/ const CONFIG = { name: 'Wohnzimmer_Rollo_Rechts', SHELLY_ACTUAL_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.Position', SHELLY_WRITE_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.TargetPosition', BASE_PATH: '0_userdata.0.Alexa.blinds.Wohnzimmer_Rollo_Rechts', LOG: true, DEBUG: true }; const DP = { SET: `${CONFIG.BASE_PATH}.set`, ACTUAL: `${CONFIG.BASE_PATH}.actual`, INFO: `${CONFIG.BASE_PATH}.info.lastCommand`, DEBUG: `${CONFIG.BASE_PATH}.info.lastRawEvent` }; let suppressActualEchoUntil = 0; let lastForwardedTarget = null; let lastForwardedTs = 0; function logx(msg, level = 'info') { if (CONFIG.LOG) log(`[AlexaBlind] ${msg}`, level); } function debugLog(msg) { if (CONFIG.DEBUG) log(`[AlexaBlind][DEBUG] ${msg}`, 'info'); } function clampPercent(val) { let n = Number(val); if (isNaN(n)) return null; if (n < 0) n = 0; if (n > 100) n = 100; return Math.round(n); } function fmtState(obj) { if (!obj || !obj.state) return 'kein state'; return JSON.stringify({ val: obj.state.val, ack: obj.state.ack, from: obj.state.from, ts: obj.state.ts, lc: obj.state.lc, user: obj.state.user, q: obj.state.q }); } // States anlegen createState(DP.SET, 0, { name: `${CONFIG.name} SET`, type: 'number', role: 'level.blind', read: true, write: true, unit: '%', min: 0, max: 100, def: 0, desc: 'Sollwert für Alexa / Blind' }, async () => { createState(DP.ACTUAL, 0, { name: `${CONFIG.name} ACTUAL`, type: 'number', role: 'value.blind', read: true, write: false, unit: '%', min: 0, max: 100, def: 0, desc: 'Istwert für Alexa / Blind' }, async () => { createState(DP.INFO, '', { name: `${CONFIG.name} Last Command`, type: 'string', role: 'text', read: true, write: false, def: '' }, async () => { createState(DP.DEBUG, '', { name: `${CONFIG.name} Last Raw Event`, type: 'string', role: 'text', read: true, write: false, def: '' }, init); }); }); }); function init() { logx(`Initialisierung für "${CONFIG.name}" gestartet`); logx(`SET-State: ${DP.SET}`); logx(`ACTUAL-State: ${DP.ACTUAL}`); logx(`SHELLY_WRITE_ID: ${CONFIG.SHELLY_WRITE_ID}`); logx(`SHELLY_ACTUAL_ID: ${CONFIG.SHELLY_ACTUAL_ID}`); // Initialen ACTUAL-Wert vom Shelly übernehmen const current = getState(CONFIG.SHELLY_ACTUAL_ID); if (current && current.val !== null && current.val !== undefined) { const pos = clampPercent(current.val); if (pos !== null) { setState(DP.ACTUAL, pos, true); setState(DP.SET, pos, true); logx(`Initialposition übernommen: ${pos}%`); } } else { logx(`Warnung: ACTUAL-State nicht lesbar: ${CONFIG.SHELLY_ACTUAL_ID}`, 'warn'); } /******************************************************** * MONITOR: Alles loggen, was auf dem SET-State passiert ********************************************************/ on({ id: DP.SET, change: 'any' }, obj => { const oldVal = obj.oldState ? obj.oldState.val : undefined; const newVal = obj.state ? obj.state.val : undefined; const msg = `RAW EVENT auf SET: alt=${oldVal}, neu=${newVal}, ack=${obj.state.ack}, from=${obj.state.from}, user=${obj.state.user}, ts=${obj.state.ts}, lc=${obj.state.lc}, q=${obj.state.q}`; debugLog(msg); setState(DP.DEBUG, msg, true); }); /******************************************************** * AKTION: Jede echte Wertänderung auf SET verarbeiten * Wichtig: erstmal OHNE Filter ack:false ********************************************************/ on({ id: DP.SET, change: 'ne' }, obj => { const target = clampPercent(obj.state.val); debugLog(`Trigger auf DP.SET(change:ne) -> ${fmtState(obj)}`); if (target === null) { logx(`Ungültiger SET-Wert empfangen: ${obj.state.val}`, 'warn'); return; } // Endlosschleifen vermeiden: // Wenn wir selbst eben genau diesen Wert bestätigt haben, nicht nochmal schreiben const now = Date.now(); if ( obj.state.ack === true && lastForwardedTarget === target && (now - lastForwardedTs) < 5000 ) { debugLog(`Ignoriere Echo auf SET (${target}%), weil es sehr wahrscheinlich von uns selbst kommt.`); return; } suppressActualEchoUntil = now + 3000; lastForwardedTarget = target; lastForwardedTs = now; logx(`SET empfangen: ${target}% | ack=${obj.state.ack} | from=${obj.state.from} -> schreibe an Shelly (${CONFIG.SHELLY_WRITE_ID})`); setState(DP.INFO, `SET ${target}% | ack=${obj.state.ack} | from=${obj.state.from} @ ${new Date().toISOString()}`, true); // SET-State bestätigt zurückschreiben, aber nur wenn noch nicht ack=true if (obj.state.ack !== true) { setState(DP.SET, target, true); } // An Shelly schreiben setState(CONFIG.SHELLY_WRITE_ID, target); }); /******************************************************** * Shelly meldet echte Position zurück -> ACTUAL aktualisieren ********************************************************/ on({ id: CONFIG.SHELLY_ACTUAL_ID, change: 'ne' }, obj => { const actual = clampPercent(obj.state.val); debugLog(`Shelly ACTUAL Event -> ${fmtState(obj)}`); if (actual === null) { logx(`Ungültiger ACTUAL-Wert vom Shelly: ${obj.state.val}`, 'warn'); return; } setState(DP.ACTUAL, actual, true); // optional den SET-State nachziehen, aber nur wenn gerade kein frischer Fahrbefehl läuft if (Date.now() > suppressActualEchoUntil) { setState(DP.SET, actual, true); } logx(`Shelly ACTUAL aktualisiert: ${actual}%`); }); /******************************************************** * Optional: Direktes Logging des Shelly-Target-States ********************************************************/ on({ id: CONFIG.SHELLY_WRITE_ID, change: 'any' }, obj => { debugLog(`Shelly WRITE/TARGET Event -> ${fmtState(obj)}`); }); logx(`Fertig initialisiert.`); } -
@Homoran
Das ist etwas verrückt. In der Alexa App geht es gar nicht einen ordentlichen Stand des Rollos auszuwählen. Somit kann ich Alexa-basierte Szenen schon mal nicht erstellen. Ich habe aktuell ein kleines Script geschrieben, welches mir die Zustände spiegelt. Damit sowohl actual als auch set in die Config ordentlich übernommen werden. Wenn ich nun die Datenpunkte des Scriptes nehme, dann kann ich zumindest per Spracheingabe "Alexa, setze Wohnzimmer Rollo rechts auf 50|40|30(etc)" das Rollo halb hoch fahren. Richtig elegant ist das nicht, funktioniert aber für's erste.Du bringst mich aber auf eine Idee. Wenn die Alexa App keine Prozentwerte, sondern dezimalwerte übergibt, geht es natürlich so gut wie immer auf 0. Ich teste mal, ob ich irgendwas schlaues mitloggen kann.
/************************************************************ * Shelly Cover -> Alexa V3 Alias (SET / ACTUAL) * Debug-Version mit ausführlichem Logging ************************************************************/ const CONFIG = { name: 'Wohnzimmer_Rollo_Rechts', SHELLY_ACTUAL_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.Position', SHELLY_WRITE_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.TargetPosition', BASE_PATH: '0_userdata.0.Alexa.blinds.Wohnzimmer_Rollo_Rechts', LOG: true, DEBUG: true }; const DP = { SET: `${CONFIG.BASE_PATH}.set`, ACTUAL: `${CONFIG.BASE_PATH}.actual`, INFO: `${CONFIG.BASE_PATH}.info.lastCommand`, DEBUG: `${CONFIG.BASE_PATH}.info.lastRawEvent` }; let suppressActualEchoUntil = 0; let lastForwardedTarget = null; let lastForwardedTs = 0; function logx(msg, level = 'info') { if (CONFIG.LOG) log(`[AlexaBlind] ${msg}`, level); } function debugLog(msg) { if (CONFIG.DEBUG) log(`[AlexaBlind][DEBUG] ${msg}`, 'info'); } function clampPercent(val) { let n = Number(val); if (isNaN(n)) return null; if (n < 0) n = 0; if (n > 100) n = 100; return Math.round(n); } function fmtState(obj) { if (!obj || !obj.state) return 'kein state'; return JSON.stringify({ val: obj.state.val, ack: obj.state.ack, from: obj.state.from, ts: obj.state.ts, lc: obj.state.lc, user: obj.state.user, q: obj.state.q }); } // States anlegen createState(DP.SET, 0, { name: `${CONFIG.name} SET`, type: 'number', role: 'level.blind', read: true, write: true, unit: '%', min: 0, max: 100, def: 0, desc: 'Sollwert für Alexa / Blind' }, async () => { createState(DP.ACTUAL, 0, { name: `${CONFIG.name} ACTUAL`, type: 'number', role: 'value.blind', read: true, write: false, unit: '%', min: 0, max: 100, def: 0, desc: 'Istwert für Alexa / Blind' }, async () => { createState(DP.INFO, '', { name: `${CONFIG.name} Last Command`, type: 'string', role: 'text', read: true, write: false, def: '' }, async () => { createState(DP.DEBUG, '', { name: `${CONFIG.name} Last Raw Event`, type: 'string', role: 'text', read: true, write: false, def: '' }, init); }); }); }); function init() { logx(`Initialisierung für "${CONFIG.name}" gestartet`); logx(`SET-State: ${DP.SET}`); logx(`ACTUAL-State: ${DP.ACTUAL}`); logx(`SHELLY_WRITE_ID: ${CONFIG.SHELLY_WRITE_ID}`); logx(`SHELLY_ACTUAL_ID: ${CONFIG.SHELLY_ACTUAL_ID}`); // Initialen ACTUAL-Wert vom Shelly übernehmen const current = getState(CONFIG.SHELLY_ACTUAL_ID); if (current && current.val !== null && current.val !== undefined) { const pos = clampPercent(current.val); if (pos !== null) { setState(DP.ACTUAL, pos, true); setState(DP.SET, pos, true); logx(`Initialposition übernommen: ${pos}%`); } } else { logx(`Warnung: ACTUAL-State nicht lesbar: ${CONFIG.SHELLY_ACTUAL_ID}`, 'warn'); } /******************************************************** * MONITOR: Alles loggen, was auf dem SET-State passiert ********************************************************/ on({ id: DP.SET, change: 'any' }, obj => { const oldVal = obj.oldState ? obj.oldState.val : undefined; const newVal = obj.state ? obj.state.val : undefined; const msg = `RAW EVENT auf SET: alt=${oldVal}, neu=${newVal}, ack=${obj.state.ack}, from=${obj.state.from}, user=${obj.state.user}, ts=${obj.state.ts}, lc=${obj.state.lc}, q=${obj.state.q}`; debugLog(msg); setState(DP.DEBUG, msg, true); }); /******************************************************** * AKTION: Jede echte Wertänderung auf SET verarbeiten * Wichtig: erstmal OHNE Filter ack:false ********************************************************/ on({ id: DP.SET, change: 'ne' }, obj => { const target = clampPercent(obj.state.val); debugLog(`Trigger auf DP.SET(change:ne) -> ${fmtState(obj)}`); if (target === null) { logx(`Ungültiger SET-Wert empfangen: ${obj.state.val}`, 'warn'); return; } // Endlosschleifen vermeiden: // Wenn wir selbst eben genau diesen Wert bestätigt haben, nicht nochmal schreiben const now = Date.now(); if ( obj.state.ack === true && lastForwardedTarget === target && (now - lastForwardedTs) < 5000 ) { debugLog(`Ignoriere Echo auf SET (${target}%), weil es sehr wahrscheinlich von uns selbst kommt.`); return; } suppressActualEchoUntil = now + 3000; lastForwardedTarget = target; lastForwardedTs = now; logx(`SET empfangen: ${target}% | ack=${obj.state.ack} | from=${obj.state.from} -> schreibe an Shelly (${CONFIG.SHELLY_WRITE_ID})`); setState(DP.INFO, `SET ${target}% | ack=${obj.state.ack} | from=${obj.state.from} @ ${new Date().toISOString()}`, true); // SET-State bestätigt zurückschreiben, aber nur wenn noch nicht ack=true if (obj.state.ack !== true) { setState(DP.SET, target, true); } // An Shelly schreiben setState(CONFIG.SHELLY_WRITE_ID, target); }); /******************************************************** * Shelly meldet echte Position zurück -> ACTUAL aktualisieren ********************************************************/ on({ id: CONFIG.SHELLY_ACTUAL_ID, change: 'ne' }, obj => { const actual = clampPercent(obj.state.val); debugLog(`Shelly ACTUAL Event -> ${fmtState(obj)}`); if (actual === null) { logx(`Ungültiger ACTUAL-Wert vom Shelly: ${obj.state.val}`, 'warn'); return; } setState(DP.ACTUAL, actual, true); // optional den SET-State nachziehen, aber nur wenn gerade kein frischer Fahrbefehl läuft if (Date.now() > suppressActualEchoUntil) { setState(DP.SET, actual, true); } logx(`Shelly ACTUAL aktualisiert: ${actual}%`); }); /******************************************************** * Optional: Direktes Logging des Shelly-Target-States ********************************************************/ on({ id: CONFIG.SHELLY_WRITE_ID, change: 'any' }, obj => { debugLog(`Shelly WRITE/TARGET Event -> ${fmtState(obj)}`); }); logx(`Fertig initialisiert.`); }Was ist SlatPos für ein Datenpunkt ?
Der steht bei dir bei Actual im Screenshot . -
Was ist SlatPos für ein Datenpunkt ?
Der steht bei dir bei Actual im Screenshot .@haselchen Gute Frage. Den Datenpunkt übernimmt der IOT Adapter "SlatPos" automatisch, wenn man nur "position" angibt. Mit meinen neuen Datenpunkten übernimmt der IOT Adapter nur den Set Datenpunkt:

Unabhängig davon stelle ich fest, dass bei der Auswahl über die Alexa-App wird immer
0auf den SET-State geschrieben wird, während ich per Spracheingabe tatsächlich numerische Werte bekomme.Der aus der Alexa-App kommende Wert ist nicht 0.5, 0.6 oder ein anderer Dezimalwert, sondern tatsächlich numerisch 0.
Hier mein Debug Script:
/************************************************************ * Shelly Cover -> Alexa V3 Alias (SET / ACTUAL) * MAX DEBUG VERSION ************************************************************/ const CONFIG = { name: 'Wohnzimmer_Rollo_Rechts', SHELLY_ACTUAL_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.Position', SHELLY_WRITE_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.TargetPosition', BASE_PATH: '0_userdata.0.Alexa.blinds.Wohnzimmer_Rollo_Rechts', LOG: true, DEBUG: true }; const DP = { SET: `${CONFIG.BASE_PATH}.set`, ACTUAL: `${CONFIG.BASE_PATH}.actual`, INFO: `${CONFIG.BASE_PATH}.info.lastCommand`, DEBUG: `${CONFIG.BASE_PATH}.info.lastRawEvent` }; let suppressActualEchoUntil = 0; let lastForwardedTarget = null; let lastForwardedTs = 0; function logx(msg, level = 'info') { if (CONFIG.LOG) log(`[AlexaBlind] ${msg}`, level); } function debugLog(msg) { if (CONFIG.DEBUG) log(`[AlexaBlind][DEBUG] ${msg}`, 'info'); } function clampPercent(val) { let n = Number(val); if (isNaN(n)) return null; if (n < 0) n = 0; if (n > 100) n = 100; return Math.round(n); } function describeValue(val) { return `value=${JSON.stringify(val)} | typeof=${typeof val} | Number()=${Number(val)} | parseFloat=${parseFloat(val)}`; } function fmtState(obj) { if (!obj || !obj.state) return 'kein state'; return JSON.stringify({ val: obj.state.val, valJson: JSON.stringify(obj.state.val), typeOfVal: typeof obj.state.val, numberVal: Number(obj.state.val), parseFloatVal: parseFloat(obj.state.val), ack: obj.state.ack, from: obj.state.from, ts: obj.state.ts, lc: obj.state.lc, user: obj.state.user, q: obj.state.q, c: obj.state.c }); } function logObjectInfo(id) { try { const obj = getObject(id); if (!obj) { debugLog(`getObject(${id}) -> kein Objekt gefunden`); return; } debugLog(`Objektinfo ${id}: ${JSON.stringify({ type: obj.type, common: obj.common, native: obj.native })}`); } catch (e) { logx(`Fehler bei getObject(${id}): ${e}`, 'warn'); } } // States anlegen createState(DP.SET, 0, { name: `${CONFIG.name} SET`, type: 'number', role: 'level.blind', read: true, write: true, unit: '%', min: 0, max: 100, def: 0, desc: 'Sollwert für Alexa / Blind' }, async () => { createState(DP.ACTUAL, 0, { name: `${CONFIG.name} ACTUAL`, type: 'number', role: 'value.blind', read: true, write: false, unit: '%', min: 0, max: 100, def: 0, desc: 'Istwert für Alexa / Blind' }, async () => { createState(DP.INFO, '', { name: `${CONFIG.name} Last Command`, type: 'string', role: 'text', read: true, write: false, def: '' }, async () => { createState(DP.DEBUG, '', { name: `${CONFIG.name} Last Raw Event`, type: 'string', role: 'text', read: true, write: false, def: '' }, init); }); }); }); function init() { logx(`Initialisierung für "${CONFIG.name}" gestartet`); logx(`SET-State: ${DP.SET}`); logx(`ACTUAL-State: ${DP.ACTUAL}`); logx(`SHELLY_WRITE_ID: ${CONFIG.SHELLY_WRITE_ID}`); logx(`SHELLY_ACTUAL_ID: ${CONFIG.SHELLY_ACTUAL_ID}`); logObjectInfo(DP.SET); logObjectInfo(DP.ACTUAL); logObjectInfo(CONFIG.SHELLY_WRITE_ID); logObjectInfo(CONFIG.SHELLY_ACTUAL_ID); const current = getState(CONFIG.SHELLY_ACTUAL_ID); if (current && current.val !== null && current.val !== undefined) { const pos = clampPercent(current.val); if (pos !== null) { setState(DP.ACTUAL, pos, true); setState(DP.SET, pos, true); logx(`Initialposition übernommen: ${pos}%`); } } else { logx(`Warnung: ACTUAL-State nicht lesbar: ${CONFIG.SHELLY_ACTUAL_ID}`, 'warn'); } /******************************************************** * 1) GLOBAL DEBUG auf ganzen Alexa-Zweig ********************************************************/ on({ id: new RegExp('^' + CONFIG.BASE_PATH.replace(/\./g, '\\.') + '\\..*'), change: 'any' }, obj => { const oldVal = obj.oldState ? obj.oldState.val : undefined; const newVal = obj.state ? obj.state.val : undefined; const msg = `BRANCH EVENT | id=${obj.id} | ` + `old=${JSON.stringify(oldVal)} | new=${JSON.stringify(newVal)} | ` + `typeof=${typeof newVal} | Number=${Number(newVal)} | parseFloat=${parseFloat(newVal)} | ` + `ack=${obj.state.ack} | from=${obj.state.from} | user=${obj.state.user} | ` + `ts=${obj.state.ts} | lc=${obj.state.lc} | q=${obj.state.q} | c=${obj.state.c}`; debugLog(msg); if (obj.id === DP.SET) { setState(DP.DEBUG, msg, true); } }); /******************************************************** * 2) Speziell DP.SET überwachen ********************************************************/ on({ id: DP.SET, change: 'any' }, obj => { debugLog(`SET RAW -> ${fmtState(obj)}`); }); /******************************************************** * 3) Jede echte Wertänderung auf SET verarbeiten ********************************************************/ on({ id: DP.SET, change: 'ne' }, obj => { debugLog(`SET Trigger(change:ne) -> ${fmtState(obj)}`); debugLog(`SET Detail -> ${describeValue(obj.state.val)}`); const target = clampPercent(obj.state.val); if (target === null) { logx(`Ungültiger SET-Wert empfangen: ${JSON.stringify(obj.state.val)}`, 'warn'); return; } const now = Date.now(); if ( obj.state.ack === true && lastForwardedTarget === target && (now - lastForwardedTs) < 5000 ) { debugLog(`Ignoriere Echo auf SET (${target}%), vermutlich von uns selbst.`); return; } suppressActualEchoUntil = now + 3000; lastForwardedTarget = target; lastForwardedTs = now; logx(`SET empfangen: ${target}% | raw=${JSON.stringify(obj.state.val)} | ack=${obj.state.ack} | from=${obj.state.from} -> schreibe an Shelly (${CONFIG.SHELLY_WRITE_ID})`); setState(DP.INFO, `SET ${target}% | raw=${JSON.stringify(obj.state.val)} | ack=${obj.state.ack} | from=${obj.state.from} @ ${new Date().toISOString()}`, true); if (obj.state.ack !== true) { setState(DP.SET, target, true); } setState(CONFIG.SHELLY_WRITE_ID, target); }); /******************************************************** * 4) Shelly ACTUAL ********************************************************/ on({ id: CONFIG.SHELLY_ACTUAL_ID, change: 'any' }, obj => { debugLog(`Shelly ACTUAL Event -> ${fmtState(obj)}`); }); on({ id: CONFIG.SHELLY_ACTUAL_ID, change: 'ne' }, obj => { const actual = clampPercent(obj.state.val); if (actual === null) { logx(`Ungültiger ACTUAL-Wert vom Shelly: ${JSON.stringify(obj.state.val)}`, 'warn'); return; } setState(DP.ACTUAL, actual, true); if (Date.now() > suppressActualEchoUntil) { setState(DP.SET, actual, true); } logx(`Shelly ACTUAL aktualisiert: ${actual}%`); }); /******************************************************** * 5) Shelly WRITE/TARGET ********************************************************/ on({ id: CONFIG.SHELLY_WRITE_ID, change: 'any' }, obj => { debugLog(`Shelly WRITE/TARGET Event -> ${fmtState(obj)}`); }); logx(`Fertig initialisiert.`); } -
@haselchen Gute Frage. Den Datenpunkt übernimmt der IOT Adapter "SlatPos" automatisch, wenn man nur "position" angibt. Mit meinen neuen Datenpunkten übernimmt der IOT Adapter nur den Set Datenpunkt:

Unabhängig davon stelle ich fest, dass bei der Auswahl über die Alexa-App wird immer
0auf den SET-State geschrieben wird, während ich per Spracheingabe tatsächlich numerische Werte bekomme.Der aus der Alexa-App kommende Wert ist nicht 0.5, 0.6 oder ein anderer Dezimalwert, sondern tatsächlich numerisch 0.
Hier mein Debug Script:
/************************************************************ * Shelly Cover -> Alexa V3 Alias (SET / ACTUAL) * MAX DEBUG VERSION ************************************************************/ const CONFIG = { name: 'Wohnzimmer_Rollo_Rechts', SHELLY_ACTUAL_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.Position', SHELLY_WRITE_ID: 'shelly.0.shellyplus2pm#e86beae602b0#1.Cover0.TargetPosition', BASE_PATH: '0_userdata.0.Alexa.blinds.Wohnzimmer_Rollo_Rechts', LOG: true, DEBUG: true }; const DP = { SET: `${CONFIG.BASE_PATH}.set`, ACTUAL: `${CONFIG.BASE_PATH}.actual`, INFO: `${CONFIG.BASE_PATH}.info.lastCommand`, DEBUG: `${CONFIG.BASE_PATH}.info.lastRawEvent` }; let suppressActualEchoUntil = 0; let lastForwardedTarget = null; let lastForwardedTs = 0; function logx(msg, level = 'info') { if (CONFIG.LOG) log(`[AlexaBlind] ${msg}`, level); } function debugLog(msg) { if (CONFIG.DEBUG) log(`[AlexaBlind][DEBUG] ${msg}`, 'info'); } function clampPercent(val) { let n = Number(val); if (isNaN(n)) return null; if (n < 0) n = 0; if (n > 100) n = 100; return Math.round(n); } function describeValue(val) { return `value=${JSON.stringify(val)} | typeof=${typeof val} | Number()=${Number(val)} | parseFloat=${parseFloat(val)}`; } function fmtState(obj) { if (!obj || !obj.state) return 'kein state'; return JSON.stringify({ val: obj.state.val, valJson: JSON.stringify(obj.state.val), typeOfVal: typeof obj.state.val, numberVal: Number(obj.state.val), parseFloatVal: parseFloat(obj.state.val), ack: obj.state.ack, from: obj.state.from, ts: obj.state.ts, lc: obj.state.lc, user: obj.state.user, q: obj.state.q, c: obj.state.c }); } function logObjectInfo(id) { try { const obj = getObject(id); if (!obj) { debugLog(`getObject(${id}) -> kein Objekt gefunden`); return; } debugLog(`Objektinfo ${id}: ${JSON.stringify({ type: obj.type, common: obj.common, native: obj.native })}`); } catch (e) { logx(`Fehler bei getObject(${id}): ${e}`, 'warn'); } } // States anlegen createState(DP.SET, 0, { name: `${CONFIG.name} SET`, type: 'number', role: 'level.blind', read: true, write: true, unit: '%', min: 0, max: 100, def: 0, desc: 'Sollwert für Alexa / Blind' }, async () => { createState(DP.ACTUAL, 0, { name: `${CONFIG.name} ACTUAL`, type: 'number', role: 'value.blind', read: true, write: false, unit: '%', min: 0, max: 100, def: 0, desc: 'Istwert für Alexa / Blind' }, async () => { createState(DP.INFO, '', { name: `${CONFIG.name} Last Command`, type: 'string', role: 'text', read: true, write: false, def: '' }, async () => { createState(DP.DEBUG, '', { name: `${CONFIG.name} Last Raw Event`, type: 'string', role: 'text', read: true, write: false, def: '' }, init); }); }); }); function init() { logx(`Initialisierung für "${CONFIG.name}" gestartet`); logx(`SET-State: ${DP.SET}`); logx(`ACTUAL-State: ${DP.ACTUAL}`); logx(`SHELLY_WRITE_ID: ${CONFIG.SHELLY_WRITE_ID}`); logx(`SHELLY_ACTUAL_ID: ${CONFIG.SHELLY_ACTUAL_ID}`); logObjectInfo(DP.SET); logObjectInfo(DP.ACTUAL); logObjectInfo(CONFIG.SHELLY_WRITE_ID); logObjectInfo(CONFIG.SHELLY_ACTUAL_ID); const current = getState(CONFIG.SHELLY_ACTUAL_ID); if (current && current.val !== null && current.val !== undefined) { const pos = clampPercent(current.val); if (pos !== null) { setState(DP.ACTUAL, pos, true); setState(DP.SET, pos, true); logx(`Initialposition übernommen: ${pos}%`); } } else { logx(`Warnung: ACTUAL-State nicht lesbar: ${CONFIG.SHELLY_ACTUAL_ID}`, 'warn'); } /******************************************************** * 1) GLOBAL DEBUG auf ganzen Alexa-Zweig ********************************************************/ on({ id: new RegExp('^' + CONFIG.BASE_PATH.replace(/\./g, '\\.') + '\\..*'), change: 'any' }, obj => { const oldVal = obj.oldState ? obj.oldState.val : undefined; const newVal = obj.state ? obj.state.val : undefined; const msg = `BRANCH EVENT | id=${obj.id} | ` + `old=${JSON.stringify(oldVal)} | new=${JSON.stringify(newVal)} | ` + `typeof=${typeof newVal} | Number=${Number(newVal)} | parseFloat=${parseFloat(newVal)} | ` + `ack=${obj.state.ack} | from=${obj.state.from} | user=${obj.state.user} | ` + `ts=${obj.state.ts} | lc=${obj.state.lc} | q=${obj.state.q} | c=${obj.state.c}`; debugLog(msg); if (obj.id === DP.SET) { setState(DP.DEBUG, msg, true); } }); /******************************************************** * 2) Speziell DP.SET überwachen ********************************************************/ on({ id: DP.SET, change: 'any' }, obj => { debugLog(`SET RAW -> ${fmtState(obj)}`); }); /******************************************************** * 3) Jede echte Wertänderung auf SET verarbeiten ********************************************************/ on({ id: DP.SET, change: 'ne' }, obj => { debugLog(`SET Trigger(change:ne) -> ${fmtState(obj)}`); debugLog(`SET Detail -> ${describeValue(obj.state.val)}`); const target = clampPercent(obj.state.val); if (target === null) { logx(`Ungültiger SET-Wert empfangen: ${JSON.stringify(obj.state.val)}`, 'warn'); return; } const now = Date.now(); if ( obj.state.ack === true && lastForwardedTarget === target && (now - lastForwardedTs) < 5000 ) { debugLog(`Ignoriere Echo auf SET (${target}%), vermutlich von uns selbst.`); return; } suppressActualEchoUntil = now + 3000; lastForwardedTarget = target; lastForwardedTs = now; logx(`SET empfangen: ${target}% | raw=${JSON.stringify(obj.state.val)} | ack=${obj.state.ack} | from=${obj.state.from} -> schreibe an Shelly (${CONFIG.SHELLY_WRITE_ID})`); setState(DP.INFO, `SET ${target}% | raw=${JSON.stringify(obj.state.val)} | ack=${obj.state.ack} | from=${obj.state.from} @ ${new Date().toISOString()}`, true); if (obj.state.ack !== true) { setState(DP.SET, target, true); } setState(CONFIG.SHELLY_WRITE_ID, target); }); /******************************************************** * 4) Shelly ACTUAL ********************************************************/ on({ id: CONFIG.SHELLY_ACTUAL_ID, change: 'any' }, obj => { debugLog(`Shelly ACTUAL Event -> ${fmtState(obj)}`); }); on({ id: CONFIG.SHELLY_ACTUAL_ID, change: 'ne' }, obj => { const actual = clampPercent(obj.state.val); if (actual === null) { logx(`Ungültiger ACTUAL-Wert vom Shelly: ${JSON.stringify(obj.state.val)}`, 'warn'); return; } setState(DP.ACTUAL, actual, true); if (Date.now() > suppressActualEchoUntil) { setState(DP.SET, actual, true); } logx(`Shelly ACTUAL aktualisiert: ${actual}%`); }); /******************************************************** * 5) Shelly WRITE/TARGET ********************************************************/ on({ id: CONFIG.SHELLY_WRITE_ID, change: 'any' }, obj => { debugLog(`Shelly WRITE/TARGET Event -> ${fmtState(obj)}`); }); logx(`Fertig initialisiert.`); }sondern tatsächlich numerisch 0.
Möglicherweise ist das ein 0/1 für false/true
-
sondern tatsächlich numerisch 0.
Möglicherweise ist das ein 0/1 für false/true
-
sondern tatsächlich numerisch 0.
Möglicherweise ist das ein 0/1 für false/true
Nope, da kommt immer 0 raus. Egal, ob ich 0, 20,40,60,80,100 drücke.
Nope, da kommt immer 0 raus
Ja und?
Das kann trotzdem false bedeuten.Ich weiß ja nicht was die Dame versteht
-
Nope, da kommt immer 0 raus
Ja und?
Das kann trotzdem false bedeuten.Ich weiß ja nicht was die Dame versteht
-
@Homoran Von Alexa kommt 0 bei Iobroker als Zahl an.
Ich bin mir nicht sicher, ob der IOT Skill irgendetwas falsch umrechnet.Von Alexa kommt 0 bei Iobroker als Zahl an
Das habe ich verstanden!
Könnte an der implizite Typumwandlung liegen -
Von Alexa kommt 0 bei Iobroker als Zahl an
Das habe ich verstanden!
Könnte an der implizite Typumwandlung liegen -
@Homoran okay, sollte ich dafür ein Github issue öffnen? Ich bin mit meinem Troubleshooting irgendwie am Ende.
Ich bin mit meinem Troubleshooting irgendwie am Ende.
Und bei mir hat Alexa Hausverbot.
Natürlich ist ein issue immer der beste Weg, allerdings wäre es schön, wenn hier zu deinem Problem jemand mit Erfahrung mit der Alexa App und dem Adapter dieses Verhalten reproduzieren oder entkräften kann.
Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.
Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.
Mit deinem Input könnte dieser Beitrag noch besser werden 💗
Registrieren Anmelden