Shelly Pro 3em + 4 relays

  • Hallo,

    Ich habe das folgende Skript entworfen und auf meinem Shelly Pro 3em eingelesen, das Skript wird akzeptiert und funktioniert, allerdings wird keines der 4 Relais angesteuert und ich habe schon alles Mögliche versucht, um Fehler zu finden. Kann mir jemand von euch sagen, wo der Fehler liegt?

    Kurz gesagt, das unten stehende Skript sollte sicherstellen, dass für jede -2000W Energieexport, 1 Relais hinzugefügt wird. so für -2000w aktivieren Relais 1, für -4000W aktivieren Relais 2 usw. Die Relais werden stufenweise in Kombination mit einer Verzögerungszeit aktiviert und deaktiviert.

    // ===== CONFIGURATION =====

    let relay_ips = [
    "192.168.1.97",
    "192.168.1.52",
    "192.168.1.32",
    "192.168.1.26"
    ];

    let watt_per_relay = 2000;
    let check_interval = 15 * 1000; // every 15 seconds
    let delay_time = 2 * 60 * 1000; // 2 minutes stabilisation time
    let max_retries = 3;
    let relay_delay_step = 300; // 300 ms between relays
    let max_data_timeout = 5 * 60 * 1000; // failsafe after 5 minutes

    let last_confirmed_count = -1;
    let pending_count = -1;
    let pending_since = 0;
    let last_update_time = Date.now();

    // ===== FUNCTIONS =====

    function setRelay(ip, turnOn, retry) {
    if (retry === undefined) retry = 0;
    let url = "http://" + ip + "/relay/0?turn=" + (turnOn ? "on" : "off");

    Shelly.call("HTTP.GET", { url: url, timeout: 5 }, function (res) {
    if (res && res.code === 200) {
    print("Relays on " + ip + " is nu " + (turnOn ? "on" : "off"));
    } else {
    let code = res && res.code ? res.code : "no connection";
    print("Error at " + ip + ": HTTP " + code);
    if (retry < max_retries) {
    Timer.set(2000, false, function () {
    setRelay(ip, turnOn, retry + 1);
    });
    } else {
    print("Maximum attempts reached for " + ip);
    }
    }
    });
    }

    function applyRelayState(count) {
    for (let i = 0; i < relay_ips.length; i++) {
    let shouldBeOn = i < count;
    Timer.set(i * relay_delay_step, false, function () {
    setRelay(relay_ips[i], shouldBeOn);
    });
    }
    last_confirmed_count = count;
    pending_count = -1;
    print(">> Number of active relays updated to: " + count);
    }

    function checkFailsafeTimeout() {
    let now = Date.now();
    if ((now - last_update_time) > max_data_timeout) {
    if (last_confirmed_count > 0) {
    print("⚠️ Failsafe: no data in 5 minutes. All relays are switched off.");
    applyRelayState(0);
    } else {
    print("⚠️ Failsafe activated, but relays are already out.");
    }
    }
    }

    function updateRelays() {
    let now = Date.now();

    // NOTE: adjust this if you are not using Shelly EM!
    Shelly.call("EM.GetStatus", { id: 0 }, function (res) {
    if (!res || typeof res.total_act_power !== 'number') {
    print("Fout: ongeldige respons van EM.GetStatus: " + JSON.stringify(res));
    checkFailsafeTimeout();
    return;
    }

    last_update_time = now;

    let exportW = res.total_act_power < 0 ? Math.abs(res.total_act_power) : 0;
    let neededCount = Math.min(relay_ips.length, Math.floor(exportW / watt_per_relay));

    if (neededCount !== last_confirmed_count) {
    if (neededCount !== pending_count) {
    pending_count = neededCount;
    pending_since = now;
    print("Stabilisation started for " + neededCount + " relays...");
    } else if ((now - pending_since) >= delay_time) {
    print("Stabilisation complete. Apply new status...");
    applyRelayState(pending_count);
    }
    } else if (pending_count !== -1) {
    print("No change required. Waiting status is reset.");
    pending_count = -1;
    }
    });
    }

    // ===== INIT =====

    print("Script started. Check every " + (check_interval / 1000) + " seconds.");
    print("Initial status: 0 relay active.");
    applyRelayState(0); // Start with everything off

    Timer.set(check_interval, true, updateRelays);

  • Hallo ArmandNizet es wäre super, wenn du zwecks besserer Lesbarkeit Skripte in einen Code-Block packst:

    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.

    Sonst passieren auch komische Dinge bei der Anzeige:

    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.

    Überwiegend PRO 3EM im Einsatz zur Haus und PV Überwachung

  • Ich habe mir dein Skript angeschaut:

    setRelay() wird in einem Timer Callback aufgerufen. Innerhalb dieser Callback-Funktion nutzt du Variablen, die vorher/außerhalb gesetzt wurden. Diese werden nicht beim Aufruf "eingefroren", sprich sie haben wenn der Timer feuert den aktuellen Wert und nicht den Wert beim Erzeugen des Timers.

    Daher ist i innerhalb der Callback-Funktion immer 4 - das ist der Wert am Ende des Schleifendurchlaufs. Damit ist die ip immer undefined.

    Um das Problem zu lösen benötigt man den Parameter userdata, der Teil von Timer.set ist:

    Bei Shelly.call gibt es auch noch eine Kleinigkeit, der Key id muss in Anführungszeichen:

    Code
    Shelly.call("EM.GetStatus", { "id": 0 }, function (res)

    Ich habe die Logik deines Skriptes nicht weiter analysiert, hoffe aber, das es entweder jetzt läuft oder du zumindest weiterkommst.

    Überwiegend PRO 3EM im Einsatz zur Haus und PV Überwachung

  • Bei Shelly.call gibt es auch noch eine Kleinigkeit, der Key id muss in Anführungszeichen:

    <Pedantenmodus EIN>

    Anführungszeichen sind hier nicht nötig. Bei Attributnamen werden Anführungszeichen nur dann benötigt, wenn der Name nicht den JavaScript-Konventionen für Variablennamen entspricht (z. B. weil er Leerzeichen oder Bindestriche enthält).

    <Pedantenmodus AUS>

  • <Pedantenmodus EIN>

    Anführungszeichen sind hier nicht nötig.

    Natürlich absolut korrekt.

    Ich mache hier routinemäßig immer Anführungszeichen drum, dann muss man nicht nachdenken, ob der Key erlaubt ist oder ggf. nicht :saint:

    Das hätte ich dazu schreiben sollen.

    Überwiegend PRO 3EM im Einsatz zur Haus und PV Überwachung

  • Dieses Thema enthält 3 weitere Beiträge, die nur für registrierte Benutzer sichtbar sind.