Skriptbeispiele
Vollständige TapHome-Skripte: sichere Division, 0 statt eines unbekannten Wertes, Dimmen mit LINEAR, Modbus-Alarme und Service-Attribute, HTTP und JSON, MQTT-Listener und Wake on LAN.
Vollständige Skripte für häufige Aufgaben. Die Rezepte für smart rules funktionieren in jeder Installation; die Modbus- und Packet-Parser-Beispiele stammen aus den offiziellen Vorlagen-Repositorys für Modbus und Packet Parser. Kurze Namen wie Se, va1 oder St sind Kürzel von Gerätewerten, die im Skripteditor ausgewählt wurden; Namen wie StatusJson oder plugTopic sind Modulvariablen.
Rezepte für smart rules
Zwei Werte sicher teilen
Eine Division durch einen Gerätewert, der 0 ist, hält das Skript mit Line in script: 1 Message: Division by zero an. Schließen Sie die Division va1/va2 in die Funktionsform von IF ein. Sie wertet nur den gewählten Zweig aus, daher läuft die Division nur, wenn der Divisor größer als 0 ist:
IF(va2 > 0, va1/va2, 0);
# Result: 0 when va2 is 0, otherwise va1 divided by va2Wenn der Divisor negativ sein kann, prüfen Sie stattdessen va2 <> 0. Mehr unter Fehler.
0 statt eines unbekannten Wertes schreiben
Ein unbekannter Gerätewert, zum Beispiel von einem Sensor im Fehlerzustand, ist NaN. Um stattdessen 0 zu schreiben, prüfen Sie ihn mit ISNAN — das Muster lautet IF(ISNAN(x), 0, x):
IF(ISNAN(Se), 0, Se);
# Result: 0 while the value of Se is unknown, otherwise the value of SeEin Vergleich wie Se = NaN ist ein Parserfehler. Wenn der Wert auch Null (kein Wert) sein kann, prüfen Sie zuerst ISNULL; OR überspringt seine rechte Seite, sobald die linke TRUE ist:
IF(ISNULL(Se) OR ISNAN(Se), 0, Se);Dimmen mit LINEAR
LINEAR bildet einen Bereich von Eingangswerten auf einen Bereich von Ausgangswerten ab, was der übliche Weg ist, eine Dimmstufe zu berechnen. Die Stufe eines Dimmers reicht von 0 (aus) bis 1 (100 %). In einer smart rule Formel mit einem Dimmer als Ausgang dimmt dieses Skript die Leuchte, während das Tageslicht von 0 auf 500 lx steigt (Se ist der Lichtsensor):
LINEAR(Se, 0, 1, 500, 0);
# Result: 1 at 0 lx, 0.5 at 250 lx, 0 at 500 lx and moreAußerhalb des Eingangsbereichs bleibt das Ergebnis am nächstgelegenen Ende (BOUNDS, der Standard). Um eine Mindesthelligkeit zu halten, erhöhen Sie den unteren Ausgangswert: LINEAR(Se, 0, 1, 500, 0.1) fällt nie unter 10 %. Details unter LINEAR.
Modbus-Beispiele
Gerätefehler aus einem Alarmregister
Ein Leseskript eines Solax-Wechselrichters macht aus einem Statusregister und einem 32-Bit-Alarmwort Gerätefehler:
VAR reg := MODBUSR(A, 0x09, UInt16);
IF(reg = 3, ADDERROR("Run Mode Fault"));
IF(reg = 4, ADDERROR("Run Mode Permanent Fault"));
VAR x3 := MODBUSR(A, 0x0040, Uint32);
IF(GETBIT(x3, 0) = 1, ADDERROR("TZ Protect Fault"));
IF(GETBIT(x3, 1) = 1, ADDERROR("Grid Lost Fault"));
IF(GETBIT(x3, 2) = 1, ADDERROR("Grid Volt Fault"));
IF(GETBIT(x3, 15) = 1, ADDERROR("Off-grid Overload"));Service-Attribut aus Bitfeldern
Ein Service-Attribut von Komfovent zeigt die vier Bytes eines 32-Bit-Registers als Text mit Punkten an:
VAR reg := MODBUSR(H, 22, Uint32);
VAR first := GETBITS(reg, 0, 8);
VAR second := GETBITS(reg, 8, 8);
VAR third := GETBITS(reg, 16, 8);
VAR last := GETBITS(reg, 24, 8);
RETURN(last + "." + third + "." + second + "." + first);
# Result: text such as "1.2.3.4"Service-Aktion mit einem Parameter
Parameter einer Service-Aktion sind Variablen, die nach ihrem Kürzel benannt sind. Eine Aktion des Eastron SDM120 schreibt ihren Parameter ID in das Holding-Register 20:
MODBUSW(H, 20, Float, ID)Eine Aufzählung dekodieren
Ein Statusregister des Huawei SUN2000 wird mit SWITCH zu lesbarem Text:
VAR state := MODBUSR(H, 32089, Uint16);
SWITCH(state,
0, "Idle: Initializing",
1, "Idle: Detecting ISO",
256, "Starting",
512, "On-Grid",
768, "Shutdown: Fault",
"Unknown");Packet-Parser-Beispiele
HTTP-Anfrage mit Fehlerbehandlung
SENDHTTPREQUEST gibt ein httpresponse-Objekt zurück. Dieses Leseskript (Forecast.solar) speichert den Body der Antwort zum späteren Parsen in der Variablen output und meldet eine fehlgeschlagene Anfrage als Gerätefehler:
VAR response := SENDHTTPREQUEST("/estimate/" + Latitude + "/" + Longitude + "/"
+ PV_declination + "/" + PV_azimuth + "/" + PV_kWp,
"GET", "", "Accept: application/json");
IF response.IsSuccess
output := response.Content;
ELSE
ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
ENDBetriebszeit aus JSON
Ein Service-Attribut des Shelly 1PM formatiert die Betriebszeit in Sekunden aus dem zwischengespeicherten Status-JSON:
VAR upTimeSeconds := PARSEJSON(StatusJson, "uptime");
VAR days := FLOOR(upTimeSeconds / 86400, 1);
upTimeSeconds := MOD(upTimeSeconds, 86400);
VAR hours := FLOOR(upTimeSeconds / 3600, 1);
upTimeSeconds := MOD(upTimeSeconds, 3600);
VAR minutes := FLOOR(upTimeSeconds / 60, 1);
days + " day(s) " + hours + "h " + minutes + "m";
# Result: for 191820 seconds "2 day(s) 5h 17m"Spotpreis für den aktuellen Zeitraum
Ein Leseskript lädt die heutigen Preise von okte.sk herunter:
VAR today := TOSTRING(NOW(), "yyyy-MM-dd");
VAR response := SENDHTTPREQUEST("/api/v1/dam/results?deliveryDayFrom=" + today
+ "&deliveryDayTo=" + today);
IF response.IsSuccess
output := response.Content;
ELSE
ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
ENDEin Service-Attribut wählt dann mit einem JSONPath-Filter einen Zeitraum aus:
PARSEJSON(output, "$[?(@.period == 1)].price") + " EUR"Schleife über ein JSON-Array
Mit TRUE als drittem Argument gibt PARSEJSON nach dem letzten Element Null zurück, statt fehlzuschlagen, was die Schleife beendet:
VAR response := SENDHTTPREQUEST("/api/taphomeapi/v1/discovery", "GET", "",
"Authorization: TapHome " + API_token);
IF response.IsSuccess
VAR ret := "";
VAR i := 0;
VAR id := PARSEJSON(response.Content, "$.devices[0].deviceId", TRUE);
WHILE !ISNULL(id)
ret := ret + "(" + id + ") ";
ret := ret + PARSEJSON(response.Content, "$.devices[" + TOSTRING(i) + "].name", TRUE);
ret := ret + " - " + PARSEJSON(response.Content, "$.devices[" + TOSTRING(i) + "].type", TRUE);
ret := ret + "\n";
i := i + 1;
id := PARSEJSON(response.Content, "$.devices[" + TOSTRING(i) + "].deviceId", TRUE);
LOOP
RETURN(ret);
ENDEine Modulvariable in einem Listener-Skript prüfen
Ein MQTT-Listener-Skript für Shelly prüft zuerst, ob die Modulvariable plugTopic ausgefüllt ist, und rechnet dann die Leistung von W in kW um:
IF(INDEXOF(plugTopic, "shelly1pm-deviceid") = 0)
ADDERROR("Set correct 'plugTopic' value in module variables. "
+ "Topic format is 'shelly1pm-<deviceid>'.");
RETURN(-1);
END
IF(RECEIVEDMSG.TOPIC = "shellies/" + plugTopic + "/relay/0/power")
VAR valueP := TOSTRING(RECEIVEDMSG.PAYLOAD);
Ed := IF(ISNULL(valueP), NaN, TODOUBLE(valueP) / 1000.0);
ENDWake on LAN
Ein UDP-Taster sendet ein Magic Packet. Die Modulvariable MAC enthält die Adresse als Text ("12 34 56 78 9a bc"); BYTECOLLECTION ignoriert die Leerzeichen:
VAR magicPacket := BYTECOLLECTION("FF FF FF FF FF FF " + MAC + MAC + MAC + MAC
+ MAC + MAC + MAC + MAC + MAC + MAC + MAC + MAC + MAC + MAC + MAC + MAC);
SENDDATA(magicPacket);