Skip to content

Instantly share code, notes, and snippets.

@percontation
Last active September 18, 2024 15:40
Show Gist options
  • Save percontation/af3af5b9c9e6a95a9c04b9473cab443b to your computer and use it in GitHub Desktop.
Save percontation/af3af5b9c9e6a95a9c04b9473cab443b to your computer and use it in GitHub Desktop.
const CONFIG = {
// Lights stay on this many seconds BEFORE the shutoff-warning flicker.
shortShutoff: 60,
longShutoff: 60*60*2,
shutoffDelay: 60, // Lights stay on this many seconds after the flicker.
clickWait: 500, // Maximum milliseconds between clicks to register as multi-click.
flicker: 150 // Milliseconds between flickers.
};
function flicker(n) {
if(n < 0.5)
return;
Shelly.call("Switch.Toggle", {id: 0}, function() {
Timer.set(CONFIG.flicker, false, flicker, n - 0.5);
});
}
// Timer that manages the auto shutoff.
var shutoffTimer = null;
function startShutoffTimer(seconds) {
if(shutoffTimer)
Timer.clear(shutoffTimer);
shutoffTimer = Timer.set(seconds*1000, false, function() {
shutoffTimer = Timer.set(CONFIG.shutoffDelay*1000, false, function () {
shutoffTimer = null;
Shelly.call("Switch.Set", {id: 0, on: false});
});
flicker(3);
});
}
function clearShutoffTimer() {
if(shutoffTimer) {
Timer.clear(shutoffTimer);
shutoffTimer = null;
}
}
function singleClick() {
if(Shelly.getComponentStatus("switch:0").output)
startShutoffTimer(CONFIG.shortShutoff);
else
clearShutoffTimer();
}
function doubleClick() {
// No special double-click behavior. But, if the lights
// are currently on and you want to reset the short shutoff,
// your first click turns the lights off and your second click
// might get registered as a double-click.
singleClick();
}
function tripleClick() {
Shelly.call("Switch.Set", {id: 0, on: true}, function(res) {
startShutoffTimer(CONFIG.longShutoff);
if(res.was_on)
flicker(1);
});
}
// Timer that fires after the last click.
var clicks = 0;
var clickTimer = null;
function startClickTimer() {
if(clickTimer)
Timer.clear(clickTimer);
clickTimer = Timer.set(CONFIG.clickWait, false, function() {
clickTimer = null;
if(clicks == 1) {
singleClick();
}
else if(clicks == 2) {
doubleClick();
}
else if(clicks == 3) {
tripleClick();
}
clicks = 0;
});
}
// Timer that fires shortly after the lights have been left off,
// to ensure that we haven't left an auto shutoff timer dangling.
// This is for compatibility with other automation.
var darkTimer = null;
function startDarkTimer() {
if(darkTimer)
Timer.clear(darkTimer);
// 5 seconds should be sufficient that flicker() and multi-clicks
// won't leave the switch dark long enough to trigger this.
darkTimer = Timer.set(5*1000, false, function () {
darkTimer = null;
if(!Shelly.getComponentStatus("switch:0").output)
clearShutoffTimer();
});
}
function clearDarkTimer() {
if(darkTimer) {
Timer.clear(darkTimer);
darkTimer = null;
}
}
Shelly.addStatusHandler(function(event) {
if(event.component == "input:0") {
// Count any switch change as a click. The timer runs the
// appropriate singleClick()/doubleClick()/tripleClick()
// function after the clicks have stopped coming.
if(event.delta.state != undefined) {
clearShutoffTimer(); // Any action cancels a pending shutoff.
clicks++;
startClickTimer();
}
}
else if(event.component == "switch:0") {
// This is an extra bit of code to be compatible with any other
// automation that can change the state of the switch.
// Note that any flip of the input switch, as well as our own
// shutoff & flicker timers will also trigger this event.
if(event.delta.output != undefined) {
if(event.delta.output) {
clearDarkTimer();
// If the light turns on for any reason, and there isn't already
// a shutoff timer running, start a short shutoff timer.
if(!shutoffTimer)
startShutoffTimer(CONFIG.shortShutoff);
} else {
// If the light turns off for any reason, and stays that way
// (i.e. isn't a flicker), then cancel any shutoff timer.
startDarkTimer();
}
}
}
});
if(Shelly.getComponentStatus("switch:0").output)
startShutoffTimer(CONFIG.shortShutoff);
@percontation
Copy link
Author

Note: This was written for a switch in Edge mode, but Toggle mode should also have sane behavior. Detached mode would require modifications to work (e.g. change singleClick() to turn the light on, like tripleClick() currently does).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment