Skip to content

Instantly share code, notes, and snippets.

@matteohoeren
Last active November 24, 2025 18:17
Show Gist options
  • Select an option

  • Save matteohoeren/73fe435023db98fa467cfe277742c98f to your computer and use it in GitHub Desktop.

Select an option

Save matteohoeren/73fe435023db98fa467cfe277742c98f to your computer and use it in GitHub Desktop.
/**
* Shelly Plus 1PM Script - Absaugungssteuerung
* Logik: Relais EIN wenn (Input EIN) ODER (API arbeitet)
* Relais AUS nach Timeout wenn (Input AUS) UND (API Idle)
*/
let xtool_ip = "10.30.0.77";
let xtool_path = "http://" + xtool_ip + ":8080/status";
let poll_interval = 1000; // 1 Sekunde
let idle_timeout_ms = 60000; // 60 Sekunden
let idle_timer = null;
// Status-Tracking
let isInputActive = false;
let isApiActive = false;
// Zentrale Logik zur Steuerung des Relais
function updateRelayState() {
let shouldBeOn = isInputActive || isApiActive;
if (shouldBeOn) {
// Bedingung erfüllt: Sofort EINschalten
Shelly.call("Switch.Set", { id: 0, on: true });
// Laufenden Ausschalt-Timer abbrechen
if (idle_timer) {
Timer.clear(idle_timer);
idle_timer = null;
print(
"Timer abgebrochen. System aktiv (Input: " +
isInputActive +
", API: " +
isApiActive +
")"
);
}
} else {
// Bedingung nicht erfüllt: Ausschalt-Timer starten, falls noch nicht läuft
if (!idle_timer) {
print("System Idle. Starte " + idle_timeout_ms / 1000 + "s Timer.");
idle_timer = Timer.set(idle_timeout_ms, false, function () {
Shelly.call("Switch.Set", { id: 0, on: false });
print("Idle Timeout erreicht -> Relais AUS");
idle_timer = null;
});
}
}
}
function checkXtoolStatus() {
Shelly.call(
"HTTP.GET",
{ url: xtool_path, timeout: 5 },
function (res, error_code, error_msg) {
if (error_code !== 0) {
print("HTTP Fehler:", error_msg);
} else {
try {
let data = JSON.parse(res.body);
let mode = data.mode || "";
let subMode = data.subMode || "";
// API-Status ermitteln
let currentlyWorking = false;
if (mode === "Work" && (subMode === "working" || subMode === "")) {
currentlyWorking = true;
}
// Nur aktualisieren und auswerten, wenn sich der Status geändert hat (Log-Spam reduzieren)
if (isApiActive !== currentlyWorking) {
isApiActive = currentlyWorking;
print(
"API Status geändert zu: " + (isApiActive ? "Working" : "Idle")
);
updateRelayState();
} else {
// EIN-Zustand erzwingen wenn arbeitend, falls extern geschaltet wurde
if (isApiActive) {
Shelly.call("Switch.Set", { id: 0, on: true });
}
}
} catch (e) {
print("JSON Parse Fehler:", e);
}
}
// Nächste Abfrage erst planen, wenn diese abgeschlossen ist
Timer.set(poll_interval, false, checkXtoolStatus);
}
);
}
// 1. API-Abfrage-Schleife starten (Einmalig, rekursiv)
checkXtoolStatus();
print("xTool Überwachung gestartet");
// 2. Input-Schalten behandeln
Shelly.addStatusHandler(function (e) {
if (e.component === "input:0") {
if (e.delta.state === true) {
print("Input eingeschaltet");
isInputActive = true;
} else if (e.delta.state === false) {
print("Input ausgeschaltet");
isInputActive = false;
}
updateRelayState();
}
});
// 3. Initialen Input-Status prüfen (Shelly triggert Handler nicht immer beim Boot)
Shelly.call("Input.GetStatus", { id: 0 }, function (res, err) {
if (!err && res) {
isInputActive = res.state;
print("Initialer Input Status: " + isInputActive);
updateRelayState();
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment