From 9c1865d42334b9f25943f6802050d372d0529f5e Mon Sep 17 00:00:00 2001 From: bes-r Date: Sat, 6 Jun 2026 21:33:30 +0200 Subject: [PATCH] gen3-gen4/2PM/detached-script.js bijwerken --- gen3-gen4/2PM/detached-script.js | 72 ++++++-------------------------- 1 file changed, 12 insertions(+), 60 deletions(-) diff --git a/gen3-gen4/2PM/detached-script.js b/gen3-gen4/2PM/detached-script.js index c45eae0..8f1f89d 100644 --- a/gen3-gen4/2PM/detached-script.js +++ b/gen3-gen4/2PM/detached-script.js @@ -1,28 +1,25 @@ // ============================================================================= // Shelly 2PM Detached Script v3.5 // ============================================================================= -// More stable version: counts only btn_down events. -// This reduces ghost triggers caused by extra btn_up / bounce events. +// Telt alleen btn_down events om valse meldingen van Gira Systeem 55 +// (of andere wipknoppen) te verminderen. +// Crosstalk-beveiliging voorkomt dat één knop van een dubbele schakelaar +// de andere knop triggert. +// Geschikt voor: Gen4 2PM, Gen3 2PM // ============================================================================= - var CONFIG = { channels: [ { inputId: 0, outputId: 0 }, { inputId: 1, outputId: 1 } ], - SETTLE_MS: 300, CROSSTALK_MS: 300, - COUNT_SIGNAL: "btn_down", - LONG_ENABLED: true, LONG_MIN_MS: 800, LONG_MAX_MS: 1800, - EMERGENCY_COUNT: 5, EMERGENCY_WINDOW_MS: 2500, - names: { single: "single", double: "double", @@ -63,10 +60,8 @@ for (var si = 0; si < CONFIG.channels.length; si++) { function fireEvent(chIndex, logicalType, toggles) { var ch = CONFIG.channels[chIndex]; var eventType = CONFIG.names[logicalType] || logicalType; - print(">>> " + ch.name + ": " + eventType + " (" + JSON.stringify(toggles) + " toggles)"); - Shelly.emitEvent("toggle_event", { input: ch.inputId, input_name: ch.name, @@ -76,7 +71,6 @@ function fireEvent(chIndex, logicalType, toggles) { logical_type: logicalType, toggles: toggles }); - if (logicalType === "single") { var w = Shelly.getComponentStatus("wifi"); if (w === null || w.sta_ip === null || w.sta_ip === "") { @@ -90,7 +84,6 @@ function resetEmergency(chIndex) { var s = chState[chIndex]; s.emergencyCount = 0; s.emergencyLocked = false; - if (s.emergencyTimer !== null) { Timer.clear(s.emergencyTimer); s.emergencyTimer = null; @@ -99,10 +92,8 @@ function resetEmergency(chIndex) { function registerEmergency(chIndex, toggles) { var s = chState[chIndex]; - if (toggles < 1) return false; if (s.emergencyLocked) return true; - if (s.emergencyCount === 0) { s.emergencyTimer = Timer.set(CONFIG.EMERGENCY_WINDOW_MS, false, function() { print("[Emergency] Timeout " + CONFIG.channels[chIndex].name + @@ -110,124 +101,92 @@ function registerEmergency(chIndex, toggles) { resetEmergency(chIndex); }); } - s.emergencyCount += toggles; - print("[Emergency] " + CONFIG.channels[chIndex].name + ": " + JSON.stringify(s.emergencyCount) + "/" + JSON.stringify(CONFIG.EMERGENCY_COUNT)); - if (s.emergencyCount >= CONFIG.EMERGENCY_COUNT) { s.emergencyLocked = true; - if (s.emergencyTimer !== null) { Timer.clear(s.emergencyTimer); s.emergencyTimer = null; } - fireEvent(chIndex, "emergency", s.emergencyCount); - Timer.set(1000, false, function() { resetEmergency(chIndex); }); - return true; } - return false; } function emitForToggles(chIndex, toggles) { if (registerEmergency(chIndex, toggles)) return; - var type = "single"; if (toggles >= 3) type = "triple"; else if (toggles >= 2) type = "double"; - fireEvent(chIndex, type, toggles); } function onBurstEnd(chIndex) { var s = chState[chIndex]; - s.settling = false; s.settleTimer = null; s.lastBurstEnd = Date.now(); - var changes = s.stateChanges; s.stateChanges = 0; - - // v3.5: one counted btn_down equals one physical toggle + // v3.5: één btn_down = één fysieke toggle var toggles = changes; if (toggles < 1) toggles = 1; - print("[Burst] " + CONFIG.channels[chIndex].name + ": " + JSON.stringify(changes) + " counted events -> " + JSON.stringify(toggles) + " toggles"); - if (s.waitingForLong) { var elapsed = Date.now() - s.singleTime; - s.waitingForLong = false; - if (s.longTimer !== null) { Timer.clear(s.longTimer); s.longTimer = null; } - if (toggles === 1 && elapsed >= CONFIG.LONG_MIN_MS && elapsed <= CONFIG.LONG_MAX_MS) { fireEvent(chIndex, "long", 1); return; } - fireEvent(chIndex, "single", 1); - if (toggles > 0) { emitForToggles(chIndex, toggles); } - return; } - if (toggles === 1 && CONFIG.LONG_ENABLED) { s.waitingForLong = true; s.singleTime = Date.now(); - print("[Long] Waiting for return toggle " + CONFIG.channels[chIndex].name); - s.longTimer = Timer.set(CONFIG.LONG_MAX_MS, false, function() { s.waitingForLong = false; s.longTimer = null; - print("[Long] Timeout -> single"); emitForToggles(chIndex, 1); }); - return; } - emitForToggles(chIndex, toggles); } Shelly.addEventHandler(function(event) { if (event.component === undefined) return; if (event.info === undefined) return; - var chIndex = -1; - for (var i = 0; i < CONFIG.channels.length; i++) { if (event.component === ("input:" + CONFIG.channels[i].inputId)) { chIndex = i; break; } } - if (chIndex === -1) return; - var signal = null; - if (event.info.state !== undefined) { signal = event.info.state; } else if (event.info.event !== undefined) { @@ -235,42 +194,36 @@ Shelly.addEventHandler(function(event) { } else { return; } - var now = Date.now(); var s = chState[chIndex]; var other = chState[(chIndex === 0) ? 1 : 0]; - + // Crosstalk-beveiliging: blokkeer het eerste event van dit kanaal als het + // andere kanaal net actief was. Voorkomt vals triggeren bij Gira Systeem 55 + // dubbele schakelaars. if (s.stateChanges === 0 && !s.settling) { if (other.settling) return; if (now - other.lastBurstEnd < CONFIG.CROSSTALK_MS) return; } - - // Count only selected signal. Default: btn_down. + // Tel alleen het ingestelde signaal. Standaard: btn_down. if (signal === CONFIG.COUNT_SIGNAL || event.info.state !== undefined) { s.stateChanges += 1; s.settling = true; - print("[State] " + CONFIG.channels[chIndex].name + " = " + JSON.stringify(signal) + " (#" + JSON.stringify(s.stateChanges) + ")"); - if (s.settleTimer !== null) { Timer.clear(s.settleTimer); } - s.settleTimer = Timer.set(CONFIG.SETTLE_MS, false, function() { onBurstEnd(chIndex); }); - return; } - if (signal === "btn_up") { print("[Ignored] " + CONFIG.channels[chIndex].name + " = " + JSON.stringify(signal)); return; } - if (signal === "single_push" || signal === "double_push" || signal === "triple_push" || @@ -280,7 +233,8 @@ Shelly.addEventHandler(function(event) { } }); -print("=== Shelly Detached v3.5 ==="); +print("=== Shelly 2PM Detached v3.5 ==="); +print("Geschikt voor: Gen4 2PM, Gen3 2PM"); print("Device: " + deviceName); print("Timing: settle=" + JSON.stringify(CONFIG.SETTLE_MS) + "ms crosstalk=" + JSON.stringify(CONFIG.CROSSTALK_MS) + "ms"); @@ -288,12 +242,10 @@ print("Counting only: " + CONFIG.COUNT_SIGNAL); print("Long: " + (CONFIG.LONG_ENABLED ? "enabled" : "disabled")); print("Emergency: " + CONFIG.EMERGENCY_COUNT + " toggles / " + CONFIG.EMERGENCY_WINDOW_MS + "ms"); - for (var pi = 0; pi < CONFIG.channels.length; pi++) { var ch = CONFIG.channels[pi]; print(" " + ch.name + " input:" + ch.inputId + " -> output:" + ch.outputId); } - print("[Script] Active"); \ No newline at end of file