Und an euch beide: 10 s sind 10000 ms und nicht etwa 6000 ms.
Ich habe keine Ahnung, warum du mir das sagst - ich habe den 6000er Timer aus dem Originalscript übernommen und weder angenommen noch behauptet, dass das zehn Sekunden sind.
Und an euch beide: 10 s sind 10000 ms und nicht etwa 6000 ms.
Ich habe keine Ahnung, warum du mir das sagst - ich habe den 6000er Timer aus dem Originalscript übernommen und weder angenommen noch behauptet, dass das zehn Sekunden sind.
Titty-Twister Ah, ok - hab noch mal geschaut und da ist ein kleines Hoppala drin. Ich hab versehentlich den Timer auf 60000 gesetzt - damit würde das Script nur in Abständen von einer Minute laufen. Wenn du willst, kannst du das korrigieren, in dem du Timer.set(60000, true, processTimer); auf Timer.set(6000, true, processTimer); änderst.
Titty-Twister Mein Script wäre als kompletter Ersatz für deine Version gedacht gewesen. Aber wenn das Script von eiche deine Anforderungen erfüllt passt das schon so und ich halte mich raus, um den Thread nicht weiter zu verkomplizieren (ich verstehe aus dem Gesprächsverlauf heraus schon nicht, wie wir jetzt bei boolescher Algebra gelandet sind...).
Ich habe das Script umformuliert, weil deine Version mit hoher Wahrscheinlichkeit nicht das tut, was du erwartest.
Das Problem ist (und darüber stolpern viele Neulinge), dass JavaScript nicht wartet, während du die Abfragen an den Pro2 schickst - statt dessen läuft das Script in der Zwischenzeit einfach weiter. Für dein Script bedeutet das:
function startControl() {
// Setze eine Funktion zur regelmäßigen Überprüfung alle 10 Sekunden
Timer.set(6000, true, function() {
updateSwitchStatus(); // Frage Switch 0 vom Pro2 ab
updateSwitchStatus2(); // Frage Switch 1 from Pro2 ab
// Die folgenden beiden Zeilen werden ausgeführt, bevor der PRO2 geantwortet hat
print("Das Netz wurde", switch_status ? "auf Netzbetrieb" : "auf Akkubetrieb", "umgeschaltet");
setRelayState(switch_status && switch_status2); // Aktualisiere den gewünschten Relaiszustand
});
}
Das bedeutet, dass dein Script nicht auf den aktuellen Stand des Pro2 reagiert, sondern auf den Stand vom letzten Durchlauf (also sechs Sekunden früher).
Wenn du das vermeiden willst, musst du die Statusabfrage im Callback der Abfrage verarbeiten (was die Hauptänderung in meiner geposteten Version ist). Wenn dich diese Verzögerung nicht stört, kannst du natürlich auch damit leben...
Der folgende Code sollte funktionieren und (auf etwas einfachere Art) exakt das tun, was deine derzeitige Version macht (machen sollte).
Allerdings sagst du, dass du den Pro 1 einschalten willst, wenn beide INPUTS des Pro2 AUS sind - derzeit fragst du aber ab, ob die OUTPUTS EIN sind. Ist das Absicht oder missverstehe ich da etwas?
const shelly2_ip = "192.168.120.161";
function processTimer() {
Shelly.call(
"HTTP.GET",
{ url: "http://" + shelly2_ip + "/rpc/Shelly.GetStatus" },
function (res1, error_code1, error_message1) {
if (error_code1 !== 0) {
print("Fehler beim Call:", error_code1, "-", error_message1);
return;
}
let response = JSON.parse(res1.body);
let switch_status = response["switch:0"].output;
print("Netzspannung1:", switch_status ? "Eingeschaltet" : "Ausgeschaltet");
let switch_status2 = response["switch:1"].output;
print("Netzspannung2:", switch_status2 ? "Eingeschaltet" : "Ausgeschaltet");
// ergibt diese Meldung Sinn?
print( "Das Netz wurde", switch_status ? "auf Netzbetrieb" : "auf Akkubetrieb", "umgeschaltet");
let state = switch_status && switch_status2;
Shelly.call("Switch.Set", { id: 0, on: state }, function (res2, error_code2, error_message2) {
if (error_code2 !== 0) {
print("Fehler beim Schalten des Relais Starkstrom:", error_message2);
} else {
print("Starkstrom:", state ? "Eingeschaltet" : "Ausgeschaltet");
}
});
},
);
}
// Setze eine Funktion zur regelmäßigen Überprüfung alle 10 Sekunden
Timer.set(60000, true, processTimer);
Alles anzeigen
Hallo Pit38 ,
Das Script sollte funktionieren - die Meldung "Call may not work as expected" ist eine Macke in der Firmware ohne reale Auswirkung. Das kannst du überprüfen, indem du schaust, ob der Output zu den angegebenen Zeiten ein- und ausgeschaltet wird. Falls dem nicht so ein sollte, melde dich bitte!
Kurzer Hinweis für alle österreichischen Benutzer des Scriptes:
Derzeit funktioniert die Kalkulation in der aktuellen Version des Scriptes nicht, weil das API keine Preisdaten für Österreich (und einige andere Länder) liefert. Für Benutzer in Deutschland tritt das Problem nicht auf.
Ich werde das weiter beobachten...
Unter der Annahme, dass du mit Timer.set() arbeitest:
intern nutzen die shellys zur zeitbasierten Ausführung einen cron deamon.
Für Timer stimmt das nicht - die arbeiten mit der Uptime des Gerätes. Das geht auch implizit aus der Dokumentation der (in FW 1.5.x neuen) Timer.getInfo() Methode hervor:
Das macht ja auch Sinn, weil Timer damit auch auf Geräten funktionieren, die mangels Internetzugang keine Zeitsynchronisation durchführen können.
Meine Vermutung ist, dass die interne Uhr des Shellys zu schnell läuft und daher ein Drift zwischen Uptime und Realzeit auftritt. Das könntest du überprüfen, indem du z. B. die Differenz in der Uptime innerhalb von exakt 24 Stunden misst.
Wenn diese Vermutung zutrifft, wäre die Lösung - wie von thgoebel vorgeschlagen - ein Schedule, weil der natürlich an der Systemzeit hängt.
Hallo Coloschni ,
Eine Berechnung nach dem Durchschnittspreis wird vom Script nicht unterstützt.
Du könntest ein ähnliches Resultat erzielen, indem du das Script so aufsetzt, dass es nur die zwölf günstigsten Stunden des Tages schaltet:
let switchOnDuration = 12; // minimum 1, maximum 24
let timeWindowStartHour = 0; // minimum 0, maximum 23
let timeWindowEndHour = 0; // minimum 0, maximum 23
let blockMode = false; // set calculation mode
let priceLimit = Infinity; // in cent/kWh
Das liefert natürlich andere Resultate als eine Durchschnittspreisberechnung, bei der die Anzahl der geschalteten Stunden abhängig von der Preisstruktur des Tages schwanken würde - aber vielleicht reicht es ja für deine Zwecke.
Es kann passieren, dass ein Script die Shelly-CPU derartig auslastet, dass sie nicht mehr antworten kann. Das könnte z. B. durch eine Endlosschleife im Script ausgelöst werden (die hier offensichtlich nicht vorliegt). Und wenn das Script auf Autostart steht, geht es nach einem Reboot sofort wieder los.
Keine Ahnung warum der Shelly bei diesem Script so rumzickt, aber um ihn wieder ansprechbar zu machen könntest du versuchen, das Script mittels RPC zu stoppen.
Dazu müsstest du den RPC http://192.168.1.126/rpc/Script.Stop?id=1 (unter der Annahme, dass das Script die ID 1 hat) via Browser/curl/iwr so oft aufrufen, bis er durchkommt - das kann durchaus ein paar Versuche benötigen...
Um einen Schedule auf demselben Gerät anzulegen, würde ich übrigens nicht über HTTP.GET gehen, sondern den RPC direkt aufrufen - das würde dann so aussehen:
Der Hinweis von tvbshell für die CONFIG ist völlig richtig - jetzt musst du nur noch die geschweiften Klammern beim Call weglassen. Statt Shelly.call("Switch.Set", {CONFIG.Switch1_On}); muss es Shelly.call("Switch.Set", CONFIG.Switch1_On); sein.
No shame - passiert den besten ;-). Aber die Frage bleibt trotzdem, ob das Ding dann tut, was du willst...
Bist du sicher, dass du das let in der Funktion weggelassen hast?
Du kannst keine Werte aus dem Shelly.call ins Hauptprogramm zurückgeben. Du kannst allerdings die Variablen im Hauptprogramm anlegen und sie dann aus dem Shelly.call heraus updaten:
let Aussentemperatur = 0; // Definition im globalen Teil
let Aussenhumidity = 0;
let Aussentaupunkt = 0;
function getTemperature() {
Shelly.call(
"HTTP.GET",
{ url: "http://192.168.2.55/rpc/Shelly.GetStatus" },
function (result, error) {
if (error == 0) {
let body = JSON.parse(result.body);
Aussentemperatur = body["temperature:100"].tC; // kein let!
Aussenhumidity = body["humidity:100"].rh;
Aussentaupunkt = Aussentemperatur - (100 - Aussenhumidity) / 5;
print("Aussenemperatur: " + Aussentemperatur + " °C und " + "Aussen Rel.Luftfeuchtigkeit: " + Aussenhumidity + " %" + " = " + "Aussentaupunkt: " + Aussentaupunkt + "°C",);
} else {
print("Error=" + error + " Aussenshelly keine Antwortt");
}
},
);
}
//Hauptprogramm
Timer.set(5000, true, function () {
getTemperature();
});
Alles anzeigen
In vielen Fällen ist das allerdings nicht das, was du willst.
Die Frage ist: soll direkt nach der Abfrage der Werte eine Aktion mit diesen Werten ausgeführt werden?
Wenn die Antwort darauf "ja" ist, solltest du die entsprechende Logik direkt in der Funktion ausführen und nicht im Hauptteil des Scriptes. Wenn du beschreibst, was du nach der Abfrage der Werte machen willst, können wir das noch genauer diskutieren.
Die Dokumentation lässt da eigentlich keinen Spielraum - eine wirksame Umgehungsmöglichkeit wäre wohl als Sicherheitslücke einzustufen:
Du könntest dem Benutzer einen Link geben, der die Autorisierung mit der URL in der Form http://admin:password@x.x.x.x/script/x/Dauerbetrieb mitschickt - damit wäre das Passwort natürlich dem Benutzer gegenüber exponiert.
Ansonsten fiele mir nur ein Zwischenschritt ein - z. B. ein minimaler Webserver, der das HTML ausliefert und im Hintergrund dann den autorisierten Aufruf an den Shelly schickt...
Grundsätzlich sollte das funktionieren - Fehler -104 ist ein Timeout und deutet stark darauf hin, dass die IP-Adresse nicht korrekt ist.
Es ist aber generell keine gute Praxis, das eigene Gerät über seine Netzwerkadresse abzufragen. Es gibt zwei Möglichkeiten, wie du das anders lösen kannst:
1. Könntest du einfach die IP-Adresse 127.0.0.1 verwenden - das ist die Loopbackadresse, die immer auf das eigene Gerät verweist:
Shelly.call(
"HTTP.GET",
{
url: "http://127.0.0.1/rpc/Shelly.GetStatus",
},
function (result, error) {
print(result);
print(error);
},
);
2. Könntest du GetStatus direkt und ohne Umweg über HTTP.GET aufrufen:
Shelly.call("Shelly.GetStatus", {}, function (result, error) {
print(result);
print(error);
});
Diese Variante hätte den Vorteil, dass in result schon ein fertiges JSON-Objekt steckt und du nicht JSON.Parse() verwenden musst, um die Antwort in ein JSON zu konvertieren.
Beide Möglichkeiten sollten dich ans Ziel bringen...
Da das Script in mehreren Testinstallationen reibungslos funktioniert, habe ich nun die neue Version ohne Änderung in den Hauptzweig übernommen.
Version 2.0 ist damit offiziell freigegeben!
Sehr schön - danke für das Feedback!