gen3-gen4/2PM/detached-script.js bijwerken

This commit is contained in:
bes-r 2026-06-06 21:33:30 +02:00
parent 73500389e5
commit 9c1865d423

View file

@ -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");