This is my version that I use as a fallback in case Home Assistant is unavailable (for whatever reason) (no power, WiFi down, etc.).
The script distinguishes between smart lights (ZigBee) and “classic” lights, which are simply “dumb” lights that can only be switched on and off.
In the case of smart lights, it is ensured that a necessary power cycle is carried out if the switch is ON but the lamps are not lit.
The connection to HA is only checked when the button is pressed, hence the 2-second waiting time (timeout) until the switch does something.
Debugging is currently still included in the script, but I will remove it for performance reasons.
What do you think about the script?
// ======================================================
// Home Assistant Watchdog (Shelly Script)
// ======================================================
//
// Features:
// - Monitors Home Assistant (HA) availability
// - Supports two relay operation modes:
// • "classic" → Local toggle if HA is offline
// • "smart" → Relay always ON; external system controls the load (HA/Zigbee)
// - Provides local fallback control if HA is offline
// - Detects unexpected smart-light behavior and performs power-cycling
// - Ensures relay consistency when HA is online
// - Debug output enabled for testing
//
// ======================================================
// -------------------------
// Configuration Parameters
// -------------------------
let relayMode = "smart"; // "classic" or "smart"
let homeAssistantUrl = "http://192.168.188.10:8123";
let powerThresholdW = 3; // Load threshold in Watts
let switchId = 0; // Switch/Input ID (default: 0)
// -------------------------
// Helper Function: Check HA Availability
// -------------------------
function checkHaStatus(callback) {
Shelly.call("HTTP.GET", { url: homeAssistantUrl, timeout: 2 }, function(response, error) {
let haIsAvailable = false;
if (error) {
print("[HA-Watchdog] HTTP error →", JSON.stringify(error));
} else if (response && response.code === 200) {
haIsAvailable = true;
}
print("[HA-Watchdog] Connectivity =", haIsAvailable);
callback(haIsAvailable);
});
}
// -------------------------
// Helper Function: Smart-Light Fallback
// -------------------------
function handleSmartLightFallback() {
Shelly.call("Switch.GetStatus", {id: switchId}, function(status, error) {
if (error) {
print("[Smart-Light] Error reading relay status:", JSON.stringify(error));
return;
}
let relayOn = !!status.output;
let loadPower = (status.apower !== undefined) ? status.apower : 0;
print("[Smart-Light] Relay =", relayOn, "Power =", loadPower);
if (!relayOn) {
print("[Smart-Light] Relay OFF → turning ON");
Shelly.call("Switch.Set", {id: switchId, on: true});
} else if (loadPower > powerThresholdW) {
print("[Smart-Light] Relay ON but load > threshold → turning OFF");
Shelly.call("Switch.Set", {id: switchId, on: false});
} else {
print("[Smart-Light] Relay ON, Power ≤ threshold → performing Power-Cycle");
Shelly.call("Switch.Set", {id: switchId, on: false}, function() {
Timer.set(2000, false, function() {
print("[Smart-Light] Relay ON after Power-Cycle");
Shelly.call("Switch.Set", {id: switchId, on: true});
});
});
}
});
}
// -------------------------
// Event Handler: Input Events
// -------------------------
Shelly.addEventHandler(function(event) {
if (event.name !== "input") return;
print("[Event] Received:", JSON.stringify(event));
if (!event.info || event.info.event !== "single_push") return;
// -------------------------
// Classic-Light Mode
// -------------------------
if (relayMode === "classic") {
if (event.id === switchId && event.info.component === "input:" + switchId) {
checkHaStatus(function(haAvailable) {
if (haAvailable) {
print("[Classic-Light] HA online → no local action");
return;
}
// HA offline → toggle relay
Shelly.call("Switch.GetStatus", {id: switchId}, function(status, error) {
if (error) {
print("[Classic-Light] Error reading relay status:", JSON.stringify(error));
return;
}
let relayOn = !!status.output;
Shelly.call("Switch.Set", {id: switchId, on: !relayOn});
print("[Classic-Light] Relay toggled → now", !relayOn);
});
});
}
return;
}
// -------------------------
// Smart-Light Mode
// -------------------------
if (relayMode === "smart") {
if (event.id === switchId && event.info.component === "input:" + switchId) {
checkHaStatus(function(haAvailable) {
if (haAvailable) {
// HA online → ensure relay ON
Shelly.call("Switch.GetStatus", {id: switchId}, function(status, error) {
if (error) {
print("[Smart-Light] Error reading relay status:", JSON.stringify(error));
return;
}
if (!status.output) {
print("[Smart-Light] HA online & relay OFF → turning ON");
Shelly.call("Switch.Set", {id: switchId, on: true});
} else {
print("[Smart-Light] HA online & relay ON → nothing to do");
}
});
} else {
// HA offline → apply fallback behavior
print("[Smart-Light] HA offline → executing fallback");
handleSmartLightFallback();
}
});
}
return;
}
});