Zum Inhalt

Benutzerdefinierter Code

Der Funktionsblock Benutzerdefinierter Code ermöglicht es, eigene Python-Logik innerhalb eines Wetterrelais-Programms auszuführen.

Benutzerdefinierter Code im Wetterrelais Programmeditor mit Code-Editor und Blockeigenschaften 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:

  1. Init-Code
  2. Update-Code
  3. 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.
  • *args und **kwargs sind 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:

  • and
  • or
  • not

Bedingungen müssen ein echtes logisches Ergebnis liefern. Zahlen werden nicht automatisch als Wahrheitswerte interpretiert.

Literale

Erlaubt sind:

  • None
  • True
  • False
  • 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_code
  • response.ok
  • response.headers
  • response.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, .internal oder .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:

  • url
  • timeout
  • headers
  • data
  • json
  • auth

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, network oder socket
  • 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
  • lambda
  • for-Schleifen
  • while-Schleifen
  • List-, Dict- und Set-Comprehensions
  • try, except und raise
  • with
  • assert
  • async, await und yield
  • global und nonlocal
  • del
  • 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.