SoftCreatR geht das technisch?
Ich bin eigentlich im Urlaub
VPN/Proxy erkannt
Es scheint, dass Sie einen VPN- oder Proxy-Dienst verwenden. Bitte beachten Sie, dass die Nutzung eines solchen Dienstes die Funktionalität dieser Webseite einschränken kann.
SoftCreatR geht das technisch?
Ich bin eigentlich im Urlaub
Danke für den Code -- leider stoppt der mit 'ner Fehlermeldung:
Ah, die (ES6-)Syntax scheint bei Shelly-Scripts nicht zu funktionieren. Gut zu wissen Ersetze in dem Script:
durch:
Ich habe mir noch einmal die Definition des Begriffs "Kollaborateur" zu Gemüte geführt und mich dazu entschieden, diesen in "Schreiberling" abzuändern. Welche Trophäen es wofür gibt, siehst du hier: https://shelly-forum.com/trophy-list/
Ich habe mir das jetzt nochmal angesehen, vor allem die auskommentierten Teile. Ich habe mir einmal die Dokumentationen dazu angesehen:
Demnach sollte sollte transition_duration grundsätzlich funktionieren. Aber kann es sein, dass der Shelly diese Option nicht so akzeptiert, wie Du es erwartest. Nicht jede Shelly-Version oder jedes Firmware-Update unterstützt alle Parameter wie transition_duration. Bei einigen Geräten oder Firmwares musst Du möglicherweise den Parameter anders nennen oder er wird gar nicht unterstützt. Das müsste man genauer "beleuchten".
Und zum eigentlichen Code: Ich habe mir mal die Mühe gemacht, diesen umzuschreiben, wie ich denke, dass es funktionieren könnte. Disclaimer: Ich hab kein Shelly-Gerät und kenne mich nicht mit der Programmierung selbiger aus. Meine Aussagen berufen sich auf meine Javascript-Kenntnisse, sowie die API-Dokumentation
Kurz und schmerzlos:
// Ampelsteuerung für Shelly Plus RGBW PM
// ===================================================
//
// Ampel-Zustände:
// 0 = alles aus
// Gelb blinken: 101 (gelb ein), 102 (gelb aus, dann zurück zu 101)
// Normale Ampel: 201...208 (Grün -> Gelb -> Rot -> Rot+Gelb)
// Lauflicht: 301...308 (Rot -> Gelb -> Grün -> Rot ... zyklisch)
//
// Eingänge (Schalter) bestimmen, in welchem Modus die Ampel läuft:
// Schalter-Kombinationen (summe der aktivierten Eingänge):
// 0 = alles aus
// 1 = Gelb blinkend
// 2 = normale Ampel
// 3 = Lauflicht
// 4 = alles aus
//
// Die Eingänge werden einzeln abgefragt (S1...S4) und über einfache
// Additionen zu einer "Schalter"-Variable kombiniert, um den Modus zu wählen.
// ============================
// Konfiguration & Konstanten
// ============================
const BRIGHTNESS = 15; // Standard-Helligkeit
const LOOP_INTERVAL = 500; // Intervall für den Hauptloop (ms)
// Zustände definieren (Konstanten für bessere Lesbarkeit)
const STATES = {
OFF: 0,
YELLOW_BLINK_ON: 101,
YELLOW_BLINK_OFF: 102,
NORMAL_GREEN_START: 201,
NORMAL_GREEN: 202,
NORMAL_YELLOW_START: 203,
NORMAL_YELLOW: 204,
NORMAL_RED_START: 205,
NORMAL_RED: 206,
NORMAL_RED_YELLOW_START: 207,
NORMAL_RED_YELLOW: 208,
RUN_START: 301,
RUN_WAIT_1: 302,
RUN_SWITCH_YELLOW: 303,
RUN_WAIT_2: 304,
RUN_SWITCH_GREEN: 305,
RUN_WAIT_3: 306,
RUN_SWITCH_RED: 307,
RUN_WAIT_4: 308,
};
// Dauer der einzelnen Phasen (wie oft Loop durchlaufen wird, bis nächster Schritt)
const TIMINGS = {
NORMAL_GREEN: 6,
NORMAL_YELLOW: 4,
NORMAL_RED: 6,
NORMAL_RED_YELLOW: 2,
RUN_PHASE: 2, // Wartezeit für jede Lauflicht-Zwischenphase
};
// ============================
// Globale Variablen
// ============================
let Ampel = STATES.OFF;
let LoopCount = 0;
let oldSchalter = 10; // Startwert für Schalter, um initialen Wechsel zu erkennen
// ============================
// Hilfsfunktionen
// ============================
// Alle Kanäle ausschalten
function AlleAus() {
for (let i = 0; i < 4; i++) {
Shelly.call("Light.set", { id: i, on: false, brightness: BRIGHTNESS });
}
}
// Eingänge (Schalter) auslesen und kombinierten Wert zurückgeben
function readInputs() {
const S1 = Shelly.getComponentStatus("input:0").state ? 1 : 0;
const S2 = Shelly.getComponentStatus("input:1").state ? 2 : 0;
const S3 = Shelly.getComponentStatus("input:2").state ? 3 : 0;
const S4 = Shelly.getComponentStatus("input:3").state ? 4 : 0;
// Summe bildet den "Schalter"-Wert
return S1 + S2 + S3 + S4;
}
// Ampel-Wert anpassen, wenn sich der Schalterzustand ändert
function updateAmpelFromInputs() {
const Schalter = readInputs();
if (oldSchalter !== Schalter) {
switch (Schalter) {
case 0:
Ampel = STATES.OFF;
break;
case 1:
Ampel = STATES.YELLOW_BLINK_ON;
break;
case 2:
Ampel = STATES.NORMAL_GREEN_START;
break;
case 3:
Ampel = STATES.RUN_START;
break;
case 4:
Ampel = STATES.OFF;
break;
default:
Ampel = STATES.OFF; // Fallback, falls unerwarteter Wert
break;
}
print(`Old: ${oldSchalter} Neu: ${Schalter} Ampel: ${Ampel} (${typeof Ampel})`);
oldSchalter = Schalter;
}
}
// Zustandslogik anwenden, abhängig von Ampel
function applyState() {
switch (Ampel) {
case STATES.OFF:
AlleAus();
break;
// Gelb blinken
case STATES.YELLOW_BLINK_ON:
print("Blinklicht AN");
Shelly.call("Light.set", { id: 1, on: true });
Ampel = STATES.YELLOW_BLINK_OFF;
break;
case STATES.YELLOW_BLINK_OFF:
Shelly.call("Light.setAll", { on: false });
Ampel = STATES.YELLOW_BLINK_ON;
break;
// Normale Ampel
case STATES.NORMAL_GREEN_START:
print("Normale Ampel: Grünphase starten");
Shelly.call("Light.set", { id: 2, on: true }); // Grün an
Shelly.call("Light.set", { id: 1, on: false }); // Gelb aus
Shelly.call("Light.set", { id: 0, on: false }); // Rot aus
LoopCount = 0;
Ampel = STATES.NORMAL_GREEN;
break;
case STATES.NORMAL_GREEN:
LoopCount++;
if (LoopCount > TIMINGS.NORMAL_GREEN) {
Ampel = STATES.NORMAL_YELLOW_START;
}
break;
case STATES.NORMAL_YELLOW_START:
Shelly.call("Light.set", { id: 1, on: true }); // Gelb an
Shelly.call("Light.set", { id: 2, on: false }); // Grün aus
LoopCount = 0;
Ampel = STATES.NORMAL_YELLOW;
break;
case STATES.NORMAL_YELLOW:
LoopCount++;
if (LoopCount > TIMINGS.NORMAL_YELLOW) {
Ampel = STATES.NORMAL_RED_START;
}
break;
case STATES.NORMAL_RED_START:
Shelly.call("Light.set", { id: 0, on: true }); // Rot an
Shelly.call("Light.set", { id: 1, on: false }); // Gelb aus
LoopCount = 0;
Ampel = STATES.NORMAL_RED;
break;
case STATES.NORMAL_RED:
LoopCount++;
if (LoopCount > TIMINGS.NORMAL_RED) {
Ampel = STATES.NORMAL_RED_YELLOW_START;
}
break;
case STATES.NORMAL_RED_YELLOW_START:
LoopCount = 0;
Shelly.call("Light.set", { id: 1, on: true }); // Gelb an
Ampel = STATES.NORMAL_RED_YELLOW;
break;
case STATES.NORMAL_RED_YELLOW:
LoopCount++;
if (LoopCount > TIMINGS.NORMAL_RED_YELLOW) {
Ampel = STATES.NORMAL_GREEN_START; // Zyklus von vorn (Grünphase)
}
break;
// Lauflicht
case STATES.RUN_START:
print("Lauflicht starten");
AlleAus();
LoopCount = 0;
Shelly.call("Light.set", { id: 0, on: true }); // Rot an
Ampel = STATES.RUN_WAIT_1;
break;
case STATES.RUN_WAIT_1:
LoopCount++;
if (LoopCount > TIMINGS.RUN_PHASE) {
Ampel = STATES.RUN_SWITCH_YELLOW;
}
break;
case STATES.RUN_SWITCH_YELLOW:
Shelly.call("Light.set", { id: 0, on: false });
Shelly.call("Light.set", { id: 1, on: true });
LoopCount = 0;
Ampel = STATES.RUN_WAIT_2;
break;
case STATES.RUN_WAIT_2:
LoopCount++;
if (LoopCount > TIMINGS.RUN_PHASE) {
Ampel = STATES.RUN_SWITCH_GREEN;
}
break;
case STATES.RUN_SWITCH_GREEN:
Shelly.call("Light.set", { id: 1, on: false });
Shelly.call("Light.set", { id: 2, on: true });
LoopCount = 0;
Ampel = STATES.RUN_WAIT_3;
break;
case STATES.RUN_WAIT_3:
LoopCount++;
if (LoopCount > TIMINGS.RUN_PHASE) {
Ampel = STATES.RUN_SWITCH_RED;
}
break;
case STATES.RUN_SWITCH_RED:
Shelly.call("Light.set", { id: 2, on: false });
Shelly.call("Light.set", { id: 0, on: true });
LoopCount = 0;
Ampel = STATES.RUN_WAIT_4;
break;
case STATES.RUN_WAIT_4:
LoopCount++;
if (LoopCount > TIMINGS.RUN_PHASE) {
Ampel = STATES.RUN_WAIT_1; // Zurück zum Start des Laufs (Endlos-Schleife)
}
break;
default:
// Unerwarteter Zustand: Sicherheitshalber alles aus und zurück auf OFF
AlleAus();
Ampel = STATES.OFF;
break;
}
}
// Haupt-Schleifenfunktion, wird alle LOOP_INTERVAL ms aufgerufen
function loop() {
updateAmpelFromInputs();
applyState();
}
// Initialisierung: alles aus
AlleAus();
// Timer setzen für die Hauptschleife
Timer.set(LOOP_INTERVAL, true, loop);
Alles anzeigen
Generell sollte Ampel nur ein einziges Mal definiert- und im nachfolgenden nur der Wert gesetzt werden. Denn wenn z.B. Schalter einen Zustand erreicht, der von dir nicht gehändelt wird, ist Ampel undefiniert, erst recht, weil es in deinem Switch/Case keinen Default gibt. Ist Schalter also z.B. NaN, oder größer als 5 bzw. kleiner als 0, ist Ampel zwangsläufig undefiniert.
Also:
let Schalter = 1 * S1 + 2 * S2 + 3 * S3 + 4 * S4;
let Ampel = 0; // Standardwert
// ....
Ampel = 123;
// ...
Ampel = 456;
Andererseits hätte ich vermutlich noch eine Vielzahl von Optimierungen vorzuschlagen
Für Schalter bitte auch Punkt vor Strich beachten
Versuchs so:
// 🌡️ Skript zur einmaligen Anzeige der aktuellen Temperatur vom AM2301A
Shelly.call(
"HTTP.GET",
{ url: "http://127.0.0.1/rpc/Shelly.GetStatus" },
function(response, error_code, error_message) {
if (error_code === 0) {
let data = JSON.parse(response.body);
// Abhängig von der Shelly-Firmware kann der Key unterschiedlich sein.
// Bei Shelly Plus/Pro Geräten werden Sensoren meist als "sensor:0" benannt.
let sensorData = data.status && data.status["sensor:0"];
if (sensorData && 'temperature' in sensorData) {
let temperature = sensorData.temperature;
print("🌡️ Aktuelle Temperatur: " + temperature + "°C");
} else {
print("❌ Temperaturdaten nicht verfügbar.");
}
} else {
print("❌ Fehler beim Abrufen der Temperatur: " + error_message);
}
}
);
print("📢 Das Skript wurde erfolgreich ausgeführt.");
Alles anzeigen
Hat das tatsächlich schon mal jemand mit den oben angegebenen Quellen funktionieren umgesetzt?
Entweder ich bin blind, oder ein "HowTo" um ein Script von extern nachladen wird nicht aufgeführt.
Selbst ein js ex-/import funktioniert bei mir nicht...
Nach meinem Verständnis sind Script.Create, Script.PutCode und Script.Eval nicht dafür gedacht, von innerhalb eines laufenden Shelly-Skriptes zusätzlichen Code dynamisch zu laden. Sie dienen als externe Management- und Deployment-Tools über die RPC-Schnittstelle. Innerhalb eines Skriptes bleibt man meist auf den initial geladenen Code beschränkt.
Wie an anderer Stelle bereits erwähnt, hab ich von Shelly-Scripting keine Ahnung. Aber ich hab mir die Doku gerade kurz angesehen und hätte zumindest eine Idee, die man testen könnte:
const externalJsUrl = "https://domain.de/script/test.js";
Shelly.call("HTTP.GET", { url: externalJsUrl }, function(result, error_code, error_message) {
if (error_code === 0 && result && result.body) {
try {
eval(result.body);
// Nach erfolgreichem eval können nun Funktionen/Variablen aus dem geladenen Code genutzt werden.
Shelly.call("Sys.Log", { message: "Externer Code erfolgreich geladen und ausgeführt." });
} catch (e) {
Shelly.call("Sys.Log", { message: `Fehler beim Ausführen des externen Codes: ${e}` });
}
} else {
Shelly.call("Sys.Log", { message: `Fehler beim Abrufen des externen Codes: ${error_msg}` });
}
});
Alles anzeigen
Bsp url: url
Das ist in der Form vollkommen legitim. Links steht der Parameter-Name, der übergeben wird und rechts der Wert dessen. Dass die Variable (für den Wert) denselben Namen hat, ist vielleicht etwas undienlich für die Lesbarkeit, aber nicht per se schlechter Programmierstil
Ich kenne mich mit Shelly-Scripting nicht aus, aber das ist in erster Linie ja Vanilla-Javascript, weshalb ich behaupte, dass das Problem die angegebene Webhook-URL ist, denn eine URL darf nur ein Fragezeichen für Parameter enthalten, beim Zusammensetzen wird aber ?humidity an die angegebene Webhook-URL gehangen, was im Ergebnis eine ungültige URL erzeugt.
Außerdem gibt es eine kleine Diskrepanz an dieser Stelle:
// Überprüfen, ob die Feuchtigkeit über 40% gestiegen ist und höher als der vorherige Wert ist
if (humidity > 35 && humidity > lastHumidity) {
print(`🚀 Feuchtigkeit ist über 40% gestiegen! Sende Webhook...`);
sendWebhook(humidity);
}
Denn sowohl im Kommentar, als auch in der ausgegebenen Nachricht steht 40%, geprüft wird aber auf > 35%. Das ist kein Fehler, aber halt auch nicht ganz korrekt
Eine korrekte Version des Scripts könnte z.B. so aussehen:
// -------------------------------
// 🌡️ Skript für Shelly Plus 1 mit AM2301A Addon
// 🔥 Sendet Webhook, wenn die Feuchtigkeit > 40% steigt
// -------------------------------
// Konfiguriere die URL deines Webhooks
var webhookUrl = "http://192.168.178.89/api/v2/webhook_trigger?webhooks_key=OKVVRKIQLMHAVLDPIXSNENBECCXIBYWKNARVLOEFRUITPWIMVMORVFPJVFTVPWNJ&event=Keller";
// Aktueller Feuchtigkeitswert speichern, um nur bei Änderung zu reagieren
var lastHumidity = null;
// Event-Listener, der auf Sensor-Änderungen lauscht
Shelly.addStatusHandler(function(event) {
// Überprüfe, ob der Sensor-Status geändert wurde
if (event.component === "sensor_0" && event.delta && ("humidity" in event.delta)) {
var humidity = event.delta.humidity; // Neuer Feuchtigkeitswert
print("💧 Neue Feuchtigkeit: " + humidity + "%");
// Überprüfen, ob die Feuchtigkeit über 40% gestiegen ist und höher als der vorherige Wert ist
if (humidity > 40 && (lastHumidity === null || humidity > lastHumidity)) {
print("🚀 Feuchtigkeit ist über 40% gestiegen! Sende Webhook...");
sendWebhook(humidity);
}
// Speichere den letzten Feuchtigkeitswert
lastHumidity = humidity;
}
});
// Funktion zum Senden des Webhooks
function sendWebhook(humidity) {
var url = webhookUrl + (webhookUrl.indexOf("?") !== -1 ? "&" : "?") + "humidity=" + encodeURIComponent(humidity);
Shelly.call(
"HTTP.GET",
{ url: url },
function(response, error_code, error_message) {
if (error_code === 0) {
print("✅ Webhook erfolgreich gesendet: " + url);
} else {
print("❌ Fehler beim Senden des Webhooks: " + error_message);
}
}
);
}
Alles anzeigen
Um zu verhindern, dass bei kleinen, schnellen Änderungen mehrfach Webhooks gesendet werden, kannst du ein einfaches Debouncing implementieren. Hier ein Beispiel:
// -------------------------------
// 🌡️ Skript für Shelly Plus 1 mit AM2301A Addon
// 🔥 Sendet Webhook, wenn die Feuchtigkeit > 40% steigt
// -------------------------------
// Konfiguriere die URL deines Webhooks
var webhookUrl = "http://192.168.178.89/api/v2/webhook_trigger?webhooks_key=OKVVRKIQLMHAVLDPIXSNENBECCXIBYWKNARVLOEFRUITPWIMVMORVFPJVFTVPWNJ&event=Keller";
// Aktueller Feuchtigkeitswert speichern, um nur bei Änderung zu reagieren
var lastHumidity = null;
// Event-Listener, der auf Sensor-Änderungen lauscht
Shelly.addStatusHandler(function(event) {
// Überprüfe, ob der Sensor-Status geändert wurde
if (event.component === "sensor_0" && event.delta && ("humidity" in event.delta)) {
var humidity = event.delta.humidity; // Neuer Feuchtigkeitswert
print("💧 Neue Feuchtigkeit: " + humidity + "%");
// Überprüfen, ob die Feuchtigkeit über 40% gestiegen ist und höher als der vorherige Wert ist
if (humidity > 40 && (lastHumidity === null || humidity > lastHumidity)) {
print("🚀 Feuchtigkeit ist über 40% gestiegen! Sende Webhook...");
sendWebhook(humidity);
}
// Speichere den letzten Feuchtigkeitswert
lastHumidity = humidity;
}
});
var webhookTimeout = null;
var debounceDelay = 30000; // 30 Sekunden
function sendWebhook(humidity) {
if (webhookTimeout !== null) {
print("🚫 Webhook bereits gesendet. Warte auf das nächste Intervall.");
return;
}
var url = webhookUrl + (webhookUrl.indexOf("?") !== -1 ? "&" : "?") + "humidity=" + encodeURIComponent(humidity);
Shelly.call(
"HTTP.GET",
{ url: url },
function(response, error_code, error_message) {
if (error_code === 0) {
print("✅ Webhook erfolgreich gesendet: " + url);
// Setze das Timeout, um weitere Webhooks für die nächste Zeitspanne zu blockieren
webhookTimeout = Timer.set(debounceDelay, false, function() {
webhookTimeout = null;
});
} else {
print("❌ Fehler beim Senden des Webhooks: " + error_message);
}
}
);
}
Alles anzeigen
Dieses Debouncing stellt sicher, dass nach dem Senden eines Webhooks eine bestimmte Zeit (z.B. 30 Sekunden) gewartet wird, bevor ein weiterer Webhook gesendet werden kann. Dies verhindert übermäßige Webhook-Aufrufe bei häufigen Feuchtigkeitsänderungen.
weil welcher Hacker will schon was von uns 0815 User?
Mal in deinen Spam-Ordner geguckt? Gelegenheit macht Diebe, egal ob 0815, oder 0900-User. Und wenn es bei dir nichts zu holen gibt, kann man dich auch noch anderweitig als Ressource nutzen (z.B. für DDos-Angriffe), wofür du am Ende haftbar gemacht werden kannst.
Naja, dass es die jetzt gibt heißt nicht, dass das Repertoire nicht noch erweitert wird.
Mir fehlt es als einiges. Die Frage ist, ob ich es will.
Etwas ernüchternd, wenn man innerhalb einer Stunde alles abgeräumt hat, was geht.
Hast du ja nicht 😊 Da die Trophäen gestern eingeführt wurden und gemäß ihrer Vergabebedingungen vergeben wurden, haben einige von euch halt binnen kürzester Zeit mehrere Trophäen erhalten.
Das sollte auf der Übersichtsseite ersichtlich sein 😅 Zwei-Faktor-Authentifizierung fehlt dir zum Beispiel noch.
Eine Auflistung erhältlicher Trophäen gibt es übrigens hier: https://shelly-forum.com/trophy-list/
Und hier könnt ihr festlegen, welche Trophäen bei euch angezeigt werden sollen: https://shelly-forum.com/settings/
wo kann ich das in € umtauschen?
Das ist Katzengold, dafür bekommst du nicht einmal 100 Rubel.
Moin Moin, liebe Shelly-Jünger und Smart-Home-Apostel,
ich dachte mir, bevor ihr euch fragt, wer dieser Typ im Hintergrund ist, der hin und wieder die Forenlampe an- und ausschaltet, stelle ich mich mal vor. Also schnallt euch an, hier kommt die Enthüllung des Jahrhunderts: Mein Name ist Sascha, 36 Jahre alt, beruflich Software-Zauberer (Selbstständig und in Vollzeit), privat eine Mischung aus Superheld und Schlafentzugskünstler (dank zweier kleiner Nachwuchs-Profis in der Kategorie „Wie halte ich Papa wach“). Und ja, das Leben hat mich auch schon auf einige turbulente Achterbahnfahrten mitgenommen – ich bin seit letztem Jahr verwitwet.
Was das Thema Smarthome angeht, habe ich mein Haus in eine halbwegs selbstständige Tech-Festung verwandelt. (Hinweis: Die Kaffeemaschine weigert sich immer noch, Kaffee zu kochen, wenn ich verschlafen „Bitte“ sage – da muss ich noch dran arbeiten.) Was Shelly angeht, muss ich zugeben: Den Namen kenne ich länger, als ich tatsächlich kapiert habe, was diese Geräte machen. Aber hey, seit mich der vorige Betreiber dieses Forums irgendwann vor gefühlt einem Jahrhundert gefragt hat, ob ich „mal kurz helfen“ könnte (Spoiler: Es wurde kein „kurz“), bin ich hier fester Bestandteil. Eine Art digitaler Hausmeister mit Server-Schlüsselbund und HTML-Schraubenzieher.
Meine Aufgabe? Ich halte die Software am Laufen, kümmere mich um das schicke Design und sorge dafür, dass euch der Server nicht plötzlich mit einem Bluescreen grüßt. Also falls ihr mal eine geniale Idee habt, wie wir die Community noch großartiger machen können, oder ihr Fragen zur Bedienung habt – immer her damit. Ich beiße nicht, versprochen. Außer der Toaster dreht wieder durch, dann könnte ich schlecht gelaunt sein.
In diesem Sinne: Frohes Shelly-Basteln, bleibt smart und denkt dran – die einzige dumme Frage ist die, die man nicht stellt (außer sie lautet „Warum funktioniert mein Smarthome nicht, obwohl ich es nicht eingeschaltet habe?“)
Könnten noch welche hinzukommen. Aktuell werden pro Minute 1.000 Trophäen vergeben
Warum bringt Apple Jahr für Jahr ein neues IPhone heraus?
Nicht, weil es etwas neues gibt 😂
Da habt ihr euren Daumen 😜
Ich hab die 1:1 aus der Community übernommen 😅 Ihr könnt ruhig ein bisschen Liebe da lassen 💖