Benutzerdefinierter Code
Der Funktionsblock Benutzerdefinierter Code ermöglicht es, eigene Python-Logik innerhalb eines Wetterrelais-Programms auszuführen.
Damit lassen sich beispielsweise individuelle Berechnungen, Filter, Zustände, Zeitfunktionen, JSON-Verarbeitung und HTTP-Anfragen umsetzen.
Der Code wird dabei nicht als uneingeschränktes Python-Programm ausgeführt. Es steht bewusst nur ein begrenzter und kontrollierter Funktionsumfang zur Verfügung. Dadurch kann eigener Code verwendet werden, ohne direkten Zugriff auf Dateien, Hardware, Relais, Netzwerk-Sockets oder interne Programmteile des Wetterrelais zu erhalten.
Hinweis: Der Funktionsblock eignet sich zur Erweiterung der Programmlogik. Er ist kein Ersatz für eine vollständige Python- oder MicroPython-Umgebung.
Funktionsblock einfügen
Der Code-Block befindet sich im Programmeditor in der Toolbox in der Gruppe Costum unter der Bezeichnung Code.
Er kann auf zwei Arten eingefügt werden:
- Code in der Toolbox anklicken. Der Block wird in der Mitte des sichtbaren Arbeitsbereichs eingefügt.
- Code aus der Toolbox an die gewünschte Position auf der Arbeitsfläche ziehen.
Ein neu eingefügter Block erhält automatisch einen Namen wie Code 1, Code 2 oder Code 3. Dieser Name kann in den Eigenschaften geändert werden.
Oberhalb des Blocks wird zusätzlich die feste Operatornummer angezeigt, beispielsweise N4. Sie dient zur eindeutigen Zuordnung des Funktionsblocks und ist unabhängig vom frei vergebenen Namen.
Ein- und Ausgang festlegen
Der Funktionsblock besitzt einen frei konfigurierbaren Ausgang und optional einen Eingang.
Die Typen werden in den Eigenschaften des Blocks über Eingangstyp und Ausgangstyp festgelegt.
Eingangstyp
| Einstellung | Bedeutung |
|---|---|
| Kein Eingang | Der Block arbeitet selbstständig und benötigt keinen Wert von einem anderen Funktionsblock. |
| Logik | Der Eingang verarbeitet True oder False. |
| Wert | Der Eingang verarbeitet einen einzelnen Zahlenwert. |
| Daten | Der Eingang verarbeitet mehrere zusammengehörige numerische Werte. |
Bei Kein Eingang wird auf der linken Seite des Blocks kein Anschluss angezeigt.
Bei Logik, Wert oder Daten erscheint der entsprechende Eingang und kann mit einem anderen Funktionsblock verbunden werden.
Ausgangstyp
| Einstellung | Rückgabewert |
|---|---|
| Logik | True oder False |
| Wert | Ein einzelner Zahlenwert, beispielsweise 12, 25.5 oder -4 |
| Daten | Eine numerische Datenreihe oder eine verschachtelte numerische Datenstruktur |
Der im Handler mit return zurückgegebene Wert muss zum gewählten Ausgangstyp passen.
Beispiel für Logik:
return True
Beispiel für Wert:
return 25.5
Beispiel für Daten:
return [10, 20, None, 40]
True und False werden dabei ausschließlich als logische Werte behandelt und nicht als Zahlen.
Wird der Eingangs- oder Ausgangstyp nachträglich geändert, können bestehende Verbindungen entfernt werden, wenn sie mit dem neuen Typ nicht mehr zulässig sind. Nach einer Typänderung sollten deshalb die Verbindungen des Blocks geprüft werden.
Die drei Codebereiche
Jeder Code-Block besitzt drei getrennte Codebereiche:
- Init-Code
- Update-Code
- Handler-Code
Die Aufteilung ist notwendig, weil diese Bereiche zu unterschiedlichen Zeitpunkten ausgeführt werden.
| Bereich | Ausführung | Typische Aufgabe |
|---|---|---|
| Init-Code | Einmal beim Start bzw. Laden des Programms | Dauerhafte Variablen und Einstellungen anlegen |
| Update-Code | Einmal zu Beginn jedes Programmzyklus | Zyklusbezogene Vorbereitungen durchführen |
| Handler-Code | Nach dem Update und bei Bedarf erneut innerhalb des Zyklus | Ausgangswert berechnen |
Init-Code
Der Init-Code wird einmal ausgeführt, wenn der Code-Block beim Laden des Programms angelegt wird.
Er eignet sich für:
- Startwerte
- Zähler
- feste Einstellungen
- URLs
- Grenzwerte
- Listen oder Dictionaries, die über mehrere Programmzyklen erhalten bleiben sollen
Beispiel:
self.limit = 25
self.counter = 0
self.url = "https://api.example.com/value"
Variablen, die später im Update- oder Handler-Code benötigt werden, sollten als Eigenschaft von self angelegt werden:
self.limit = 25
Später kann darauf wieder zugegriffen werden:
return self.limit
Kein Eingang im Init-Code
Der Init-Code darf nicht auf den Eingang des Funktionsblocks zugreifen.
Beim Programmstart ist nicht sichergestellt, dass ein vorgeschalteter Funktionsblock bereits einen gültigen Ausgang berechnet hat. Die Verarbeitung von Eingangsdaten gehört deshalb in den Handler-Code.
Lebensdauer von self-Variablen
Mit self angelegte Variablen bleiben über mehrere Programmzyklen erhalten:
self.counter = 0
Sie bleiben erhalten, solange der Funktionsblock existiert. Sie werden jedoch nicht dauerhaft im Gerät gespeichert.
Nach einem Neustart des Wetterrelais oder einem erneuten Laden des Programms wird der Init-Code erneut ausgeführt und die Variablen werden neu angelegt.
Update-Code
Der Update-Code wird einmal zu Beginn jedes Programmzyklus ausgeführt.
Er eignet sich für Arbeiten, die genau einmal pro Zyklus erfolgen sollen, beispielsweise:
- Zähler erhöhen
- Merker verändern
- zyklusbezogene Werte vorbereiten
- Zustände zurücksetzen
- einmalige Berechnungen durchführen
Beispiel:
self.counter += 1
Nach dem Update-Code wird der Handler automatisch ausgeführt.
Für viele Anwendungen wird deshalb kein eigener Update-Code benötigt. In diesem Fall genügt:
pass
Wichtig:
handler()darf im eigenen Code nicht direkt aufgerufen werden. Der Programmeditor übernimmt den Handler-Aufruf automatisch.
Handler-Code
Der Handler-Code berechnet den eigentlichen Ausgang des Funktionsblocks.
Ein Handler kann innerhalb eines einzigen Programmzyklus mehrfach ausgeführt werden. Das ist erforderlich, weil ein vorgeschalteter Funktionsblock seinen Ausgang möglicherweise noch nicht berechnet hat.
Eingang verwenden
Der Wert des Eingangs steht im Handler über die Variable input zur Verfügung.
Beispiel:
if input == None:
return None
else:
return input + 5
Solange kein Eingangswert vorliegt, wird None zurückgegeben.
Bedeutung von return None
return None
bedeutet:
Der Funktionsblock kann seinen Ausgang im aktuellen Moment noch nicht bestimmen.
Der Handler kann danach innerhalb desselben Programmzyklus erneut ausgeführt werden.
Sobald ein Wert ungleich None zurückgegeben wurde, gilt der Ausgang des Blocks für den aktuellen Programmzyklus als berechnet.
None ist dabei weder die Zahl 0 noch der logische Zustand False.
Ausgang zurückgeben
Der Benutzer gibt ausschließlich den eigentlichen Wert zurück.
Beispiel:
return 25
Es muss kein zusätzliches Datenobjekt oder eine Typinformation erzeugt werden. Der Programmeditor ordnet dem Rückgabewert automatisch den eingestellten Ausgangstyp zu.
Block ohne Eingang
Bei Kein Eingang kann der Handler seinen Wert selbstständig bestimmen.
Typische Anwendungen sind:
- feste Werte
- eigene Berechnungen
- Zähler
- Zeitfunktionen
- HTTP-Abfragen
- JSON-Auswertungen
- eigene Zustände über mehrere Programmzyklen
Ein Block ohne Eingang sollte normalerweise nicht dauerhaft None zurückgeben, da sein Ausgang sonst nicht berechnet werden kann.
Dauerhafte und zyklusbezogene Variablen
Dauerhafte Variablen
Variablen mit self bleiben über mehrere Programmzyklen erhalten:
self.counter = 0
self.values = []
Ein einfacher Zähler kann beispielsweise so aufgebaut werden.
Init-Code
self.counter = 0
Update-Code
self.counter += 1
Handler-Code
return self.counter
Der Ausgang liefert anschließend nacheinander:
1, 2, 3, 4, ...
Die Erhöhung erfolgt bewusst im Update-Code. Würde der Zähler im Handler verändert, könnte die Änderung innerhalb eines Programmzyklus mehrfach ausgeführt werden.
Zykluslokale Variablen
Variablen ohne self, die im Update- oder Handler-Code angelegt werden, gelten nur für den aktuellen Programmzyklus.
Beispiel:
current_value = 10
Sie können bei mehreren Handler-Aufrufen innerhalb desselben Zyklus erhalten bleiben, werden jedoch beim nächsten Programmzyklus entfernt.
Eigene Funktionen
Eigene Funktionen sind innerhalb des Custom Codes erlaubt.
Beispiel:
def scale_percent(value):
return int(value * 65535 / 100)
if input == None:
return None
else:
return scale_percent(input)
Dabei gelten folgende Regeln:
- Funktionen müssen auf oberster Ebene des jeweiligen Codebereichs definiert werden.
- Eine Funktion ist nur in dem Codebereich verfügbar, in dem sie definiert wurde.
- Eine Funktion aus dem Init-Code steht deshalb nicht automatisch im Handler-Code zur Verfügung.
- Pro Codebereich sind maximal 8 Funktionen erlaubt.
- Eine Funktion darf maximal 8 Parameter besitzen.
- Positionsargumente und benannte Argumente sind erlaubt.
- Rekursion ist nicht erlaubt.
- Die maximale verschachtelte Funktionsaufruftiefe beträgt 4.
- Verschachtelte Funktionen sind nicht erlaubt.
- Default-Parameter sind nicht erlaubt.
- Typannotationen sind nicht erlaubt.
*argsund**kwargssind nicht erlaubt.- Dekoratoren sind nicht erlaubt.
Der Handler-Code selbst muss einen erreichbaren return enthalten. Ein return, das ausschließlich innerhalb einer Hilfsfunktion steht, reicht nicht aus.
Unterstützte Python-Syntax
Der Custom Code unterstützt bewusst nur einen ausgewählten Teil von Python.
Zuweisungen
value = 10
self.counter = 20
self.counter += 1
self.counter -= 1
self.counter *= 2
self.counter /= 2
self.counter %= 10
Unterstützt werden:
+=-=*=/=%=
Berechnungen
result = input * 2 + 5
result = input // 10
remainder = input % 10
Unterstützte Operatoren:
+-*///%
Mit + können außerdem Listen und Zeichenketten verbunden werden:
values = [1, 2] + [3, 4]
text = "temperature: " + str(input)
Vergleiche
Unterstützt werden:
==!=<<=>>=
Beispiel:
if input == None:
return None
else:
if input >= 100:
return 100
else:
return input
Logische Operationen
Unterstützt werden:
andornot
Bedingungen müssen ein echtes logisches Ergebnis liefern. Zahlen werden nicht automatisch als Wahrheitswerte interpretiert.
Literale
Erlaubt sind:
NoneTrueFalse- Integer
- Float
- Zeichenketten
- Listen
- Tupel
- Dictionaries
Listen, Dictionaries und Zeichenketten
Listen
Unterstützte lesende Methoden:
copy()count()index()
Unterstützte verändernde Methoden:
append()clear()extend()insert()remove()reverse()sort()
Beispiel:
self.values.append(input)
if len(self.values) > 10:
self.values.remove(self.values[0])
return self.values
Auch die Zuweisung über einen vorhandenen Index ist möglich:
self.values[0] = 5
Der verwendete Listenindex muss bereits vorhanden sein.
Dictionaries
Unterstützte lesende Methoden:
copy()get()items()keys()values()
Unterstützte verändernde Methoden:
clear()update()
Direkte Zuweisungen sind ebenfalls möglich:
self.data["temperature"] = input
Dictionary-Schlüssel dürfen Zeichenketten oder Integer sein.
Zeichenketten
Unterstützte Methoden:
count()endswith()find()isalnum()isalpha()isdigit()join()lower()lstrip()replace()rsplit()rstrip()split()startswith()strip()upper()
Beispiel:
parts = response.text.strip().split(";")
return float(parts[1])
Direkte Eingangsdaten und Literale dürfen nicht verändert werden. Für Änderungen sollte zuerst eine eigene Liste oder ein eigenes Dictionary erzeugt werden.
Verfügbare Hilfsfunktionen
Folgende allgemeine Funktionen stehen zur Verfügung:
abs()all()any()bool()clamp()float()int()len()max()min()round()str()sum()
Beispiel:
value = clamp(input, 0, 100)
return int(value * 65535 / 100)
Für clamp() muss die untere Grenze kleiner oder gleich der oberen Grenze sein.
Bei round(value, digits) muss digits zwischen -6 und 6 liegen.
Zeitfunktionen
Für Zeitfunktionen darf das Modul time verwendet werden:
import time
Verfügbar sind:
time.time()time.ticks_ms()time.ticks_diff()time.localtime()time.mktime()time.sleep()
Beispiel:
import time
time.sleep(0.5)
return time.time()
Begrenzung von time.sleep()
Für time.sleep() gelten folgende Grenzen:
- maximal 5 Sekunden pro Aufruf
- maximal 10 Sekunden insgesamt pro Funktionsblock und Programmzyklus
Beispiel:
time.sleep(5)
time.sleep(5)
ist noch zulässig.
Ein weiterer Sleep-Aufruf im selben Programmzyklus würde das Gesamtlimit überschreiten.
Mehrere Handler-Aufrufe innerhalb desselben Zyklus teilen sich dieses Limit.
Lange Wartezeiten blockieren die Programmausführung. Auch wenn bis zu 10 Sekunden pro Zyklus technisch möglich sind, sollten normalerweise deutlich kürzere Wartezeiten verwendet werden.
JSON verarbeiten
Für JSON kann json verwendet werden:
import json
Unterstützt werden:
json.loads()json.dumps()
Beispiel:
import json
data = json.loads('{"value": 25.5}')
return data.get("value")
Alternativ kann auf Systemen mit MicroPython auch folgende Schreibweise verwendet werden:
import ujson as json
Danach werden ebenfalls json.loads() und json.dumps() verwendet.
HTTP-Anfragen
Der Custom Code kann HTTP- und HTTPS-Anfragen ausführen.
Dazu wird requests importiert:
import requests
Auf MicroPython-Systemen ist außerdem folgende Schreibweise möglich:
import urequests as requests
Unterstützte Methoden:
requests.request()requests.head()requests.get()requests.post()requests.put()requests.patch()requests.delete()
Einfaches GET-Beispiel
import requests
response = requests.get(
"https://api.example.com/temperature",
timeout=5
)
response.raise_for_status()
data = response.json()
return data["temperature"]
POST mit JSON
import requests
body = {
"relay": True,
"source": "program"
}
response = requests.post(
"https://api.example.com/relay",
json=body,
timeout=5
)
response.raise_for_status()
return response.status_code
POST mit Benutzername und Passwort
import requests
response = requests.post(
"https://api.example.com/value",
json={"value": input},
auth=("username", "password"),
timeout=5
)
response.raise_for_status()
return response.status_code
Verfügbare Eigenschaften einer Antwort
response.status_coderesponse.okresponse.headersresponse.text
Verfügbare Methoden:
response.json()response.raise_for_status()response.close()
Die eigentliche Netzwerkverbindung wird intern kontrolliert. Der Custom Code erhält nur Zugriff auf die für ihn freigegebenen Informationen der Antwort.
Erlaubte HTTP-Ziele
Erlaubt sind:
http://https://- öffentliche Server
- private IPv4-Adressen im lokalen Netzwerk
Damit können beispielsweise Geräte im eigenen Netzwerk über ihre konkrete IPv4-Adresse angesprochen werden.
Nicht erlaubt sind unter anderem:
localhost- Loopback-Adressen wie
127.0.0.1 - Link-Local-Adressen
- Multicast-Adressen
- reservierte und Dokumentationsnetze
- Zugangsdaten direkt in der URL
- URL-Fragmente
- IPv6-Literale
- lokale Hostnamen wie
.local,.lan,.internaloder.home.arpa
Für Geräte im lokalen Netzwerk sollte deshalb die konkrete IPv4-Adresse verwendet werden.
Weiterleitungen sollten nach Möglichkeit vermieden werden. Für sicherheitsrelevante Anwendungen sollte direkt die endgültige URL angesprochen werden.
Die Zertifikatsprüfung bei HTTPS hängt von der im Wetterrelais eingesetzten Firmware ab.
HTTP-Grenzen
| Ressource | Grenze |
|---|---|
| HTTP-Anfragen pro Funktionsblock und Programmzyklus | 8 |
| Standard-Timeout | 5 Sekunden |
| Maximaler Timeout | 10 Sekunden |
| Maximale URL-Länge | 512 Zeichen |
| Request-Body | 16.384 Byte |
| Response-Body | 16.384 Byte |
| Eigene Request-Header | 16 |
| Response-Header | 64 |
| Länge eines Header-Namens | 64 Zeichen |
| Länge eines Header-Werts | 512 Zeichen |
| JSON-Verschachtelung | 8 Ebenen |
| JSON-Elemente | 256 |
Unterstützte Request-Argumente:
urltimeoutheadersdatajsonauth
data und json dürfen nicht gleichzeitig verwendet werden.
Nicht erlaubte Funktionen und Zugriffe
Der Custom Code wird absichtlich in einer eingeschränkten Umgebung ausgeführt.
Nicht erlaubt sind unter anderem:
- beliebige Imports wie
os,sys,machine,networkodersocket from ... import ...- Datei- und Flashzugriffe
- direkter Zugriff auf GPIOs
- direkter Zugriff auf Relais
- direkter Zugriff auf Busse oder andere Hardware
- Zugriff auf den übrigen Programmcode
exec()eval()__import__()getattr()globals()- private Attribute oder Namen mit führendem
_ - Klassen
lambdafor-Schleifenwhile-Schleifen- List-, Dict- und Set-Comprehensions
try,exceptundraisewithassertasync,awaitundyieldglobalundnonlocaldel- Rekursion
- direkte Socket-Zugriffe
- direkter Aufruf von
handler()
Schleifen sind bewusst nicht verfügbar. Wiederholte Abläufe können stattdessen über mehrere Programmzyklen, Listenmethoden oder geeignete Hilfsfunktionen umgesetzt werden.
Allgemeine Grenzen
Für jeden der drei Codebereiche gelten feste Ressourcenlimits.
| Ressource | Grenze |
|---|---|
| Zeichen pro Codebereich | 2.048 |
| Zeilen pro Codebereich | 64 |
| Tokens pro Ausdruck | 128 |
| Einrückung | maximal 16 Leerzeichen |
| Einrückungsstufe | 4 Leerzeichen |
| Ausgeführte Anweisungen pro Bereichsausführung | 128 |
| Eigene Funktionen pro Codebereich | 8 |
| Parameter pro Funktion | 8 |
| Verschachtelte Funktionsaufruftiefe | 4 |
| Elemente pro Liste, Tupel oder Dictionary | 128 |
| Verschachtelung eigener Werte | maximal 6 Ebenen |
| Länge einer Zeichenkette | 16.384 Zeichen |
| Größter zulässiger Zahlenbetrag | 9.007.199.254.740.991 |
| HTTP-Anfragen pro Zyklus | 8 |
time.sleep() pro Aufruf |
5 Sekunden |
time.sleep() insgesamt pro Zyklus |
10 Sekunden |
Leerzeilen und Kommentare zählen bei der Zeichen- und Zeilengrenze mit.
NaN ist als Zahlenwert nicht erlaubt.
Tabs sind im ausgeführten Code nicht zulässig. Einrückungen werden mit jeweils vier Leerzeichen dargestellt. Der Codeeditor unterstützt dabei die Tab-Taste und setzt die passende Einrückung automatisch als Leerzeichen um.
Code bearbeiten
Für jeden Bereich besitzt der Code-Block eine eigene Schaltfläche:
- Init-Code bearbeiten
- Update-Code bearbeiten
- Handler-Code bearbeiten
Die Schaltfläche zeigt zusätzlich an, ob der Bereich leer ist oder wie viele Zeilen Code enthalten sind.
Beim Anklicken öffnet sich ein größeres Codefenster. In dessen Kopfbereich wird angezeigt, wann der jeweilige Code ausgeführt wird.
Änderungen werden unmittelbar in den Code-Block übernommen. Es gibt keine zusätzliche Schaltfläche zum Übernehmen oder Abbrechen.
Das Fenster kann geschlossen werden über:
- das Schließen-Symbol oben rechts
- einen Klick außerhalb des Fensters
- die Escape-Taste
Das Schließen des Fensters verwirft keine Änderungen.
Die Änderungen befinden sich zunächst nur im aktuell bearbeiteten Programm. Damit der neue Code auf dem Wetterrelais ausgeführt wird, muss das Programm anschließend wie gewohnt mit Übertragen an das Gerät gesendet werden.
Einrückung im Codeeditor
Python verwendet Einrückungen zur Kennzeichnung zusammengehöriger Codebereiche.
Im Codeeditor gilt:
- Tab rückt um vier Leerzeichen ein.
- Umschalt + Tab entfernt eine Einrückungsstufe.
- Bei mehreren markierten Zeilen werden alle markierten Zeilen gemeinsam eingerückt oder ausgerückt.
Beispiele
Beispiel 1: Eingangswert begrenzen
Eingangstyp: Wert
Ausgangstyp: Wert
Init-Code
self.minimum = 0
self.maximum = 100
Update-Code
pass
Handler-Code
if input == None:
return None
else:
return clamp(input, self.minimum, self.maximum)
Der Funktionsblock wartet auf einen Eingangswert und begrenzt ihn anschließend auf den Bereich von 0 bis 100.
Beispiel 2: Prozentwert auf 16 Bit skalieren
Eingangstyp: Wert
Ausgangstyp: Wert
Init-Code
pass
Update-Code
pass
Handler-Code
def scale_percent(value):
value = clamp(value, 0, 100)
return int(value * 65535 / 100)
if input == None:
return None
else:
return scale_percent(input)
Ein Eingangswert von 0 bis 100 wird auf einen Zahlenbereich von 0 bis 65535 skaliert.
Beispiel 3: Zähler über mehrere Programmzyklen
Eingangstyp: Kein Eingang
Ausgangstyp: Wert
Init-Code
self.counter = 0
Update-Code
self.counter += 1
Handler-Code
return self.counter
Der Zähler wird bei jedem neuen Programmzyklus einmal erhöht.
Beispiel 4: Wert über HTTP abrufen
Eingangstyp: Kein Eingang
Ausgangstyp: Wert
Init-Code
self.url = "https://api.example.com/temperature"
Update-Code
pass
Handler-Code
import requests
response = requests.get(
self.url,
timeout=5
)
response.raise_for_status()
data = response.json()
return data["temperature"]
Der Funktionsblock ruft in jedem Programmzyklus einen Wert über HTTP ab und gibt ihn als Zahlenwert aus.
Fehlerverhalten
Der eingegebene Code wird geprüft, bevor er ausgeführt wird.
Fehler können beispielsweise entstehen durch:
- nicht erlaubte Imports
- falsche Einrückung
- einen fehlenden Rückgabewert im Handler
- Zugriff auf nicht angelegte
self-Variablen - Überschreiten der Code- oder Ressourcenlimits
- nicht erlaubte Funktionen oder Methoden
- einen Rückgabewert, der nicht zum eingestellten Ausgangstyp passt
Laufzeitfehler werden dem jeweiligen Code-Block zugeordnet, damit sich erkennen lässt, welcher Operator den Fehler verursacht hat.
Netzwerkfehler können dazu führen, dass eine Anfrage später erneut versucht wird. Programmier-, Typ- oder Validierungsfehler werden dagegen als Programmfehler behandelt.
Empfehlungen
Für die meisten Anwendungen hat sich folgende Aufteilung bewährt:
Init-Code
Dauerhafte Einstellungen und Zustände anlegen:
self.limit = 25
Update-Code
Arbeiten ausführen, die genau einmal pro Programmzyklus stattfinden sollen:
pass
Handler-Code
Eingang prüfen, Ergebnis berechnen und zurückgeben:
if input == None:
return None
else:
return input
Als Grundregel gilt:
- Init-Code: dauerhafte Variablen und Einstellungen anlegen.
- Update-Code: einmalige Arbeiten des aktuellen Programmzyklus durchführen.
- Handler-Code: den eigentlichen Ausgang berechnen.
return None: Der Ausgang kann momentan noch nicht bestimmt werden.- Jeder andere zum Ausgangstyp passende Rückgabewert bestimmt den Ausgang des Blocks für den aktuellen Programmzyklus.
- Zustände, die nur einmal pro Zyklus verändert werden sollen, gehören in den Update-Code und nicht in den Handler.
- HTTP-Anfragen und
time.sleep()sollten möglichst kurz gehalten werden, damit der Programmablauf nicht unnötig blockiert wird.
Zusammenfassung
Mit dem Funktionsblock Benutzerdefinierter Code kann die Programmlogik des Wetterrelais gezielt erweitert werden. Er eignet sich insbesondere für:
- individuelle Berechnungen
- Wertebegrenzung und Skalierung
- Filter
- Zähler und Zustände über mehrere Programmzyklen
- Verarbeitung von Listen, Dictionaries und Zeichenketten
- JSON-Auswertung
- Zeitfunktionen
- HTTP- und HTTPS-Anfragen
- Anbindung lokaler Geräte über IPv4
- eigene Hilfsfunktionen
Der Funktionsblock arbeitet dabei in einer kontrollierten Umgebung mit festen Grenzen. Direkte Zugriffe auf Hardware, Dateien, Betriebssystemfunktionen oder interne Bestandteile des Wetterrelais sind nicht möglich.