volangstdlibreferenzfunktionen

# Standardbibliothek

Die Volang-Standardbibliothek stellt einen umfassenden Satz eingebauter Funktionen bereit, die für das Bearbeiten von Text, das Ausführen mathematischer Operationen und andere gängige Aufgaben unerlässlich sind. Diese Funktionen stehen global in jedem Skript zur Verfügung.

# Eingabeoperationen

Dieser Abschnitt beschreibt Funktionen zum Lesen von Eingangsdaten innerhalb eines Logikbausteins. Jeder Logikbaustein kann einen oder mehrere Eingangskanäle definieren. Wenn sich ein Eingangswert ändert, wird das Skript des Bausteins ausgeführt. Diese Funktionen ermöglichen es dem Skript festzustellen, welcher Eingang die Ausführung ausgelöst hat, und die aktuellen Werte aller Eingänge zu lesen.

# input::channel

Gibt die Kennung des Eingangskanals zurück, der die aktuelle Skriptausführung ausgelöst hat. Wenn ein Baustein mehrere Eingänge hat, ist diese Funktion unerlässlich, um zu bestimmen, welcher Eingang den Baustein ausgeführt hat, sodass Sie jeden Eingang unterschiedlich behandeln können.

Parameter:

  • Keine.

Rückgabe:

  • Eine Zeichenkette mit der ID des Eingangs, der die Ausführung ausgelöst hat.

Beispiel:

channel = input::channel()

if (channel == "input") {
    // Der Haupt-Umschalteingang wurde ausgelöst
    ...
} else if (channel == "on") {
    // Der dedizierte "on"-Eingang wurde ausgelöst
    ...
} else if (channel == "off") {
    // Der dedizierte "off"-Eingang wurde ausgelöst
    ...
}

# input::value

Gibt den Wert des Eingangs zurück, der die aktuelle Skriptausführung ausgelöst hat. Der Rückgabetyp hängt vom definierten Typ des Eingangs ab (boolean, number oder string). Verwenden Sie diese Funktion zusammen mit input::channel(), um sowohl zu ermitteln, welcher Eingang sich geändert hat, als auch welchen neuen Wert er hat.

Parameter:

  • Keine.

Rückgabe:

  • Der aktuelle Wert des auslösenden Eingangs. Der Typ hängt von der Eingangsdefinition ab (boolean, number oder string).

Beispiel:

channel = input::channel()
value = input::value()

// Auf eine steigende Flanke an einem booleschen Eingang reagieren
if (channel == "input" and value) {
    output::toggle("output")
}

# input::get

Ruft den zuletzt bekannten Wert eines bestimmten Eingangs anhand seiner Kennung ab. Anders als input::value(), das nur den Wert des Eingangs zurückgibt, der die aktuelle Ausführung ausgelöst hat, kann diese Funktion den gespeicherten Wert jedes Eingangs jederzeit lesen.

Parameter:

  • id (string): Die Kennung des zu lesenden Eingangs.

Rückgabe:

  • Der zuletzt bekannte Wert des angegebenen Eingangs. Der Typ hängt von der Eingangsdefinition ab (boolean, number oder string).

Beispiel:

// Aktuelle Temperatur von einem Eingang lesen
current_temp = input::get("value")

// Den Wert in der Steuerlogik verwenden
if (current_temp > 25.0) {
    output::set("cooling", true)
}

# Ausgabeoperationen

Dieser Abschnitt beschreibt Funktionen zum Steuern der Ausgänge eines Logikbausteins. Jeder Baustein kann einen oder mehrere Ausgänge definieren, die Werte an andere verbundene Bausteine weitergeben.

# output::get

Ruft den aktuellen Wert eines bestimmten Ausgangs anhand seiner Kennung ab. Dies ist nützlich, um den aktuellen Zustand eines Ausgangs zu lesen, bevor entschieden wird, ob er geändert werden soll.

Parameter:

  • id (string): Die Kennung des zu lesenden Ausgangs.

Rückgabe:

  • Der aktuelle Wert des angegebenen Ausgangs. Der Typ hängt von der Ausgangsdefinition ab (boolean, number oder string).

Beispiel:

// Aktuellen Ausgangszustand vor dem Umschalten prüfen
prev = output::get("output")
if (prev) {
    std::print("Output is currently ON, turning OFF")
}
output::set("output", !prev)

# output::set

Setzt den Wert eines bestimmten Ausgangs anhand seiner Kennung. Der Werttyp muss dem für diesen Ausgang definierten Typ entsprechen (boolean, number oder string). Das Setzen eines Ausgangs gibt den neuen Wert an alle verbundenen Bausteine weiter.

Parameter:

  • id (string): Die Kennung des zu setzenden Ausgangs.
  • value: Der neue zuzuweisende Wert. Muss dem definierten Typ des Ausgangs entsprechen.

Rückgabe:

  • Keine.

Beispiel:

// Einen booleschen Ausgang setzen
output::set("output", true)

// Einen numerischen Ausgang basierend auf einer Berechnung setzen
midpoint = config::get("midpoint")
hysteresis = config::get("hysteresis")
value = input::get("value")

if (value >= midpoint + hysteresis) {
    output::set("output", true)
} else if (value <= midpoint - hysteresis) {
    output::set("output", false)
}

# output::toggle

Schaltet einen booleschen Ausgang um und kehrt seinen aktuellen Wert um. Ist der Ausgang aktuell true, wird er false und umgekehrt. Diese Funktion arbeitet nur mit Ausgängen vom Typ boolean.

Parameter:

  • id (string): Die Kennung des umzuschaltenden booleschen Ausgangs.

Rückgabe:

  • Keine.

Beispiel:

channel = input::channel()
value = input::value()

// Den Ausgang bei einer steigenden Flanke des Eingangs umschalten
if (channel == "input") {
    last_state = state::get("last_input_state")
    if (value and !last_state) {
        output::toggle("output")
    }
    state::set("last_input_state", value)
}

# Zustandsoperationen

Dieser Abschnitt beschreibt Funktionen zum Verwalten eines persistenten Zustands innerhalb eines Logikbausteins. Zustandsvariablen behalten ihre Werte zwischen Skriptausführungen bei, was sie unerlässlich macht, um Bedingungen über die Zeit zu verfolgen, etwa Flankenerkennung, Zähler oder Zeitinformationen. Die verfügbaren Zustandsvariablen und ihre Typen werden im Bausteindeskriptor definiert.

# state::get

Ruft den aktuellen Wert einer persistenten Zustandsvariablen anhand ihrer Kennung ab.

Parameter:

  • id (string): Die Kennung der zu lesenden Zustandsvariablen.

Rückgabe:

  • Der aktuelle Wert der Zustandsvariablen. Der Typ hängt von der Definition der Zustandsvariablen ab (boolean, number oder string).

Beispiel:

// Zustand verwenden, um eine steigende Flanke zu erkennen (Übergang von false zu true)
value = input::value()
last_state = state::get("last_input_state")

if (value and !last_state) {
    // Steigende Flanke erkannt - Aktion ausführen
    output::toggle("output")
}

state::set("last_input_state", value)

# state::set

Speichert einen Wert in einer persistenten Zustandsvariablen anhand ihrer Kennung. Der Wert bleibt zwischen Skriptausführungen erhalten, sodass sich der Baustein Informationen über mehrere Eingangsereignisse hinweg merken kann. Der Werttyp muss dem für diese Zustandsvariable definierten Typ entsprechen.

Parameter:

  • id (string): Die Kennung der zu aktualisierenden Zustandsvariablen.
  • value: Der neue zu speichernde Wert. Muss dem definierten Typ der Zustandsvariablen entsprechen.

Rückgabe:

  • Keine.

Beispiel:

// Den Zeitstempel der letzten Eingangsänderung verfolgen
channel = input::channel()
value = input::value()

if (channel == "input") {
    state::set("last_change_time", time::now())

    // Berechnen, wie lange der Eingang in seinem vorherigen Zustand war
    elapsed = time::now() - state::get("last_change_time")
    if (elapsed > 60) {
        std::print("Input was stable for over a minute")
    }
}

# Konfigurationsoperationen

Dieser Abschnitt beschreibt Funktionen zum Lesen der Konfigurationsparameter eines Bausteins. Konfigurationswerte werden vom Benutzer in Voldeno Studio gesetzt und sind aus dem Skript heraus nur lesbar. Sie erlauben es, Bausteine anzupassen, ohne den Code zu ändern, zum Beispiel um Schwellenwerte, Verzögerungen oder Betriebsmodi festzulegen.

# config::get

Ruft den Wert eines Konfigurationsparameters anhand seiner Kennung ab. Konfigurationsparameter werden im Bausteindeskriptor definiert und ihre Werte werden vom Benutzer in Voldeno Studio gesetzt. Das Skript kann diese Werte nur lesen, nicht verändern.

Parameter:

  • id (string): Die Kennung des zu lesenden Konfigurationsparameters.

Rückgabe:

  • Der Wert des Konfigurationsparameters. Der Typ hängt von der Definition des Parameters ab (number, string oder enum). Parameter vom Typ enum geben ihren nullbasierten numerischen Index zurück.

Beispiel:

// Verzögerungskonfiguration in Millisekunden lesen
delay_on_ms = config::get("delay_on_ms")
delay_off_ms = config::get("delay_off_ms")

// Eine enum-Konfiguration verwenden, um den Verhaltensmodus zu wählen
mode = config::get("mode") // Gibt 0, 1, 2... je nach gewählter Option zurück

if (mode == 0) {
    // Logik für den ersten Modus
    ...
} else if (mode == 1) {
    // Logik für den zweiten Modus
    ...
}

// Einen numerischen Schwellenwert aus der Konfiguration lesen
scale = config::get("scale")
offset = config::get("offset")
result = input::value() * scale + offset
output::set("value", result)

# Callback-Operationen

Dieser Abschnitt beschreibt Funktionen zum Planen aufgeschobener Funktionsaufrufe. Volang ist eine nicht blockierende Sprache und stellt keine sleep-Funktion bereit. Stattdessen bieten Callbacks einen Mechanismus für zeitbasierte Logik, indem sie eine benutzerdefinierte Funktion planen, die nach einer festgelegten Verzögerung aufgerufen wird.

Dies ist unerlässlich, um Verhaltensweisen wie Verzögerungen, zeitgesteuerte Impulse, Motorsteuerungssequenzen oder jede Logik umzusetzen, die nach Ablauf einer bestimmten Zeitspanne handeln muss. Ein Callback kann Argumente an die aufgerufene Funktion übergeben, und die Funktion kann weitere Callbacks planen, um mehrstufige Sequenzen zu erstellen.

Pro Baustein kann jeweils nur ein Callback aktiv sein. Das Planen eines neuen Callbacks, während bereits einer aussteht, erfordert, den bestehenden zuerst mit callback::clear() zu löschen.

# callback::set

Plant einen aufgeschobenen Aufruf einer benutzerdefinierten extern-Funktion nach einer festgelegten Verzögerung in Millisekunden. Die Funktion wird durch ihren Namen als Zeichenkette identifiziert. Zusätzliche Argumente können übergeben werden und werden der Callback-Funktion als ihre Parameter zugestellt.

Die Zielfunktion muss im Skript mit der Syntax extern fn deklariert sein. Wenn die Verzögerung abläuft, ruft das System diese Funktion mit den bereitgestellten Argumenten auf.

Parameter:

  • delay_ms (integer): Die Verzögerung in Millisekunden, bevor die Funktion aufgerufen wird.
  • function_name (string): Der Name der aufzurufenden extern fn.
  • ...args (optional): Zusätzliche Argumente, die an die Callback-Funktion übergeben werden. Sie können null oder mehr Werte beliebigen Typs übergeben.

Rückgabe:

  • Keine.

Beispiel:

// Einen einfachen Callback-Handler definieren
extern fn onTimeout() {
    output::set("output", true)
}

// Den Callback so planen, dass er nach einer konfigurierbaren Verzögerung auslöst
delay_ms = config::get("delay_ms")
callback::set(delay_ms, "onTimeout")

Beispiel - Argumente übergeben:

// Callback, der in den nächsten Schritt verkettet
extern fn onSequence(step) {
    if (step == 1) {
        output::set("output", true)
        // Schritt 2 nach einer Impulsdauer planen
        pulse_ms = config::get("pulse_ms")
        callback::set(pulse_ms, "onSequence", 2)
        return
    }
    if (step == 2) {
        output::set("output", false)
        return
    }
}

// Die Sequenz nach einer anfänglichen Verzögerung starten
callback::set(1000, "onSequence", 1)

# callback::clear

Bricht jeden aktuell geplanten Callback für den Baustein ab. Dies sollte aufgerufen werden, bevor ein neuer Callback geplant wird, oder wenn die ausstehende Aktion nicht mehr benötigt wird (z. B. wenn sich der Eingang geändert hat, bevor die Verzögerung abgelaufen ist).

Parameter:

  • Keine.

Rückgabe:

  • Keine.

Beispiel:

extern fn onCallback(value) {
    if (value == 1) {
        output::set("output", true)
    } else if (value == 2) {
        output::set("output", false)
    }
}

channel = input::channel()
value = input::value()

if (channel == "input") {
    last = state::get("last_input_state")
    if (value != last) {
        state::set("last_input_state", value)

        // Den vorherigen Callback immer löschen, bevor ein neuer geplant wird
        callback::clear()

        if (value) {
            delay_ms = config::get("delay_on_ms")
            if (delay_ms > 0) {
                callback::set(delay_ms, "onCallback", 1)
            } else {
                output::set("output", true)
            }
        } else {
            delay_ms = config::get("delay_off_ms")
            if (delay_ms > 0) {
                callback::set(delay_ms, "onCallback", 2)
            } else {
                output::set("output", false)
            }
        }
    }
}

# Zeichenkettenoperationen

Dieser Abschnitt beschreibt Funktionen, die Zeichenketten bearbeiten.

# str::len

Berechnet die Anzahl der Zeichen in einer gegebenen Zeichenkette.

Parameter:

  • text (string): Die zu messende Eingabezeichenkette.

Rückgabe:

  • Ein Ganzzahlwert, der die Anzahl der Zeichen in der Zeichenkette angibt.

Beispiel:

// Prüfen, ob der PIN-Code des Benutzers die erforderliche Länge hat
user_pin = "1234"
if (str::len(user_pin) == 4) {
    ...
}

# str::trim

Entfernt alle führenden und nachgestellten Leerraumzeichen (Leerzeichen, Tabulatoren, Zeilenumbrüche) aus der Zeichenkette. Dies ist unerlässlich, um Benutzereingaben zu bereinigen oder Befehle von externen Systemen zu parsen, bei denen zusätzliche Abstände auftreten können.

Parameter:

  • text (string): Die zu bereinigende Eingabezeichenkette.

Rückgabe:

  • Ein neuer Text, der den Text ohne umgebenden Leerraum enthält.

Beispiel:

// Einen von einem externen Modul empfangenen Befehl bereinigen
input = "  START  "
command = str::trim(input)

// Jetzt ist die Zeichenkette "START" und kann sicher verglichen werden
if (command == "START") {
    ....
}

# str::concat

Verkettet (verbindet) zwei oder mehr Zeichenketten zu einer einzigen Zeichenkette. Diese Funktion ist variadisch, das heißt, sie akzeptiert eine variable Anzahl von Argumenten, sodass Sie komplexe Nachrichten oder Befehle dynamisch aufbauen können.

Parameter:

  • ...strings: Eine Folge von Zeichenkettenargumenten, die miteinander verbunden werden sollen. Sie können so viele Argumente wie nötig übergeben, getrennt durch Kommas. Es kann auch ein einzelnes Argument angegeben werden; in diesem Fall gibt diese Funktion das Argument selbst zurück.

Rückgabe:

  • Eine neue Zeichenkette, die aus allen Eingabezeichenketten in der angegebenen Reihenfolge zusammengesetzt ist.

Beispiel:

room = "Living Room"
temp = "22.5"

// Eine vollständige Statusmeldung aus mehreren Argumenten aufbauen
message = str::concat("Status: ", room, " is currently ", temp, "°C")

// Ergebnis: "Status: Living Room is currently 22.5°C"

# str::count

Zählt die Anzahl der nicht überlappenden Vorkommen einer Teilzeichenkette innerhalb einer Zeichenkette. Optional kann die Suche mithilfe der Positionsargumente start und end auf einen bestimmten Bereich innerhalb der Zeichenkette beschränkt werden.

Parameter:

  • text (string): Die Zeichenkette, in der gesucht wird.
  • substring (string): Die Teilzeichenkette, deren Vorkommen gezählt werden.
  • start (integer, optional): Die Position, ab der die Suche beginnt. Standardwert ist 0.
  • end (integer, optional): Die Position, an der die Suche endet (exklusiv). Standardwert ist das Ende der Zeichenkette.

Rückgabe:

  • Ein Ganzzahlwert, der die Anzahl der nicht überlappenden Vorkommen der Teilzeichenkette angibt.

Beispiel:

// Alle Vorkommen eines Wortes zählen
text = "I love apples, apple are my favorite fruit"
count = str::count(text, "apple") // Gibt 2 zurück

// Vorkommen innerhalb eines Bereichs zählen
data = "abcabcabc"
count = str::count(data, "abc", 1)    // Gibt 2 zurück (überspringt das erste "abc")
count = str::count(data, "abc", 1, 7) // Gibt 1 zurück

// Leere Teilzeichenkette gibt Länge + 1 zurück
count = str::count("hello", "") // Gibt 6 zurück

// Nicht überlappend: "aaaa" enthält 2 nicht überlappende "aa"
count = str::count("aaaa", "aa") // Gibt 2 zurück

# str::replace

Ersetzt Vorkommen einer Teilzeichenkette innerhalb einer Zeichenkette durch eine neue Teilzeichenkette. Standardmäßig werden alle Vorkommen ersetzt. Ein optionaler Parameter count begrenzt die Anzahl der von links nach rechts durchgeführten Ersetzungen.

Parameter:

  • text (string): Die ursprüngliche Zeichenkette.
  • old (string): Die zu ersetzende Teilzeichenkette.
  • new (string): Die Teilzeichenkette, durch die ersetzt wird.
  • count (integer, optional): Maximale Anzahl der Ersetzungen. Wird er weggelassen, werden alle Vorkommen ersetzt.

Rückgabe:

  • Eine neue Zeichenkette mit den angewendeten Ersetzungen.

Beispiel:

// Alle Vorkommen ersetzen
result = str::replace("one one was a horse", "one", "three")
// Gibt "three three was a horse" zurück

// Nur das erste Vorkommen ersetzen
result = str::replace("one one was a horse", "one", "three", 1)
// Gibt "three one was a horse" zurück

// Durch Ersetzen mit leerer Zeichenkette löschen
result = str::replace("hello", "l", "") // Gibt "heo" zurück

// Eine leere old-Zeichenkette fügt zwischen jedes Zeichen ein
result = str::replace("abc", "", "-") // Gibt "-a-b-c-" zurück

# str::number

Parst ein Zeichenkettenargument und wandelt es in einen numerischen Wert um. Die Funktion erkennt das Format automatisch: Enthält die Zeichenkette einen Dezimalpunkt, gibt sie eine Gleitkommazahl zurück, andernfalls eine Ganzzahl.

Parameter:

  • text: Die Zeichenkette, die die Zahlendarstellung enthält.

Rückgabe:

  • Ein numerischer Wert, entweder Ganzzahl oder Gleitkommazahl, je nach Eingabeformat.

Beispiel:

// Fall 1: Eine Ganzzahl parsen (z. B. Helligkeitsstufe)
brightness = str::number("80") // Gibt Ganzzahl 80 zurück

// Fall 2: Eine Gleitkommazahl parsen (z. B. Temperatur)
temp_str = "21.5"
threshold = str::number(temp_str) // Gibt Gleitkommazahl 21.5 zurück
current_temp = 22

// Den umgewandelten Wert in der Logik verwenden
if (current_temp > threshold) {
    ...
}

# str::fmt

Erstellt eine formatierte Zeichenkette, indem Platzhalter {} innerhalb einer Vorlagenzeichenkette durch die Zeichenkettendarstellung der bereitgestellten Argumente ersetzt werden. Sie akzeptiert eine variable Anzahl von Argumenten unterschiedlicher Typen (Zeichenketten, numerische und boolesche Werte) und wandelt sie vor dem Einfügen automatisch in Text um. Die Ersetzung erfolgt positionsabhängig: Das erste {} wird durch das erste Argument ersetzt, das zweite {} durch das zweite und so weiter.

Parameter:

  • template: Die Formatzeichenkette, die geschweifte Klammern als Platzhalter {} enthält.
  • ...args: Eine Folge von Werten, die in die Platzhalter eingesetzt werden. Unterstützte Typen sind Zahlen, Zeichenketten und boolesche Literale (true/false).

Rückgabe:

  • Eine neue Zeichenkette, in der alle Platzhalter durch die entsprechenden Werte ersetzt sind.

Beispiel:

sensorName = "Kitchen_Main"
temp = 22.5
isActive = true

// Eine komplexe Protokollnachricht ohne manuelle Verkettung formatieren
log = str::fmt("Sensor {} status: Active={}, Value={}°C", sensorName, isActive, temp)

// Ergebnis: "Sensor Kitchen_Main status: Active=true, Value=22.5°C"

# str::split

Initialisiert eine Zeichenketten-Aufteilungsoperation und erstellt einen Iteratorzustand. Diese Funktion führt die eigentliche Aufteilung nicht sofort durch. Stattdessen gibt sie ein undurchsichtiges handle-Objekt zurück, das die aktuelle Position und die Logik kapselt, die zum Durchlaufen der Zeichenkette erforderlich sind. Dieses Objekt muss an str::split_next oder str::split_has_next übergeben werden, um die tatsächlichen Teilzeichenketten nacheinander abzurufen.

Parameter:

  • text: Die aufzuteilende Quellzeichenkette.
  • separator: Die Trennzeichenkette, die die Grenzen zwischen den Abschnitten markiert.

Rückgabe:

  • Ein undurchsichtiges Handle, das die aktive Aufteilungssitzung darstellt. Sie sollten dieses Objekt nicht direkt verändern.

Beispiel:

rawData = "sensor1;25.5;active"

// Den Splitter initialisieren. 'iterator' hält jetzt den Zustand.
iterator = str::split(rawData, ";")

// Der Iterator ist jetzt bereit, von split_next verarbeitet zu werden...

# str::split_has_next

Prüft, ob weitere Teilzeichenketten darauf warten, aus der aktuellen Aufteilungssitzung abgerufen zu werden. Diese Funktion untersucht das von str::split erstellte undurchsichtige state-Objekt. Sie verändert den Zustand nicht und rückt die Iteratorposition nicht vor, sondern prüft nur die Verfügbarkeit. Sie wird häufig als Bedingung in einer while-Schleife verwendet, um alle Teile einer Zeichenkette zu durchlaufen.

Parameter:

  • state: Das von str::split zurückgegebene undurchsichtige Handle.

Rückgabe:

  • true, wenn mindestens eine weitere Teilzeichenkette verfügbar ist; andernfalls false.

Beispiel:

data = "RED,GREEN,BLUE"
iterator = str::split(data, ",")

// Schleife durchlaufen, solange noch Tokens übrig sind
while (str::split_has_next(iterator)) {
    ...
    // Hier kann split_next() sicher aufgerufen werden
    // color = str::split_next(iterator) 
}

# str::split_next

Extrahiert die nächste Teilzeichenkette aus der Aufteilungssequenz, gibt sie zurück und rückt den Iterator auf die nächste Position vor. Diese Funktion verbraucht das aktuelle durch das undurchsichtige state identifizierte Segment der Zeichenkette. Sie ist dafür ausgelegt, nacheinander aufgerufen zu werden, bis alle Teile der Zeichenkette verarbeitet wurden.

Parameter:

  • state: Das von str::split zurückgegebene undurchsichtige Handle.

Rückgabe:

  • Das nächste Segment des ursprünglichen Textes.

Hinweis: Es wird empfohlen, die Verfügbarkeit mit str::split_has_next(state) zu prüfen, bevor Sie diese Funktion aufrufen, um eine sichere Iteration zu gewährleisten.

Beispiel:

// Szenario: Parsen einer Befehlszeichenkette "SET_COLOR;255;0;0"
commandRaw = "SET_COLOR;255;0;0"
iter = str::split(commandRaw, ";")

// Wir kennen das Format und können die Teile manuell extrahieren
if (str::split_has_next(iter)) {
    cmd = str::split_next(iter)   // "SET_COLOR"
    r = str::split_next(iter)     // "255"
    g = str::split_next(iter)     // "0"
    b = str::split_next(iter)     // "0"
    ...
}

# Array-Operationen

Dieser Abschnitt beschreibt Funktionen zum Erstellen und Bearbeiten von Arrays.

# array::new

Erstellt ein neues Array, das mit den bereitgestellten Werten initialisiert wird. Diese Funktion ist variadisch, das heißt, sie akzeptiert eine variable Anzahl von Argumenten beliebigen Typs. Wird sie ohne Argumente aufgerufen, erstellt sie ein leeres Array. Arrays können gemischte Typen aufnehmen und ihre Größe kann mit anderen Array-Funktionen dynamisch geändert werden.

Parameter:

  • ...values (optional): Eine Folge von Werten, mit denen das Array initialisiert wird. Sie können null oder mehr Argumente beliebigen Typs übergeben (Zahlen, Zeichenketten, boolesche Werte oder sogar andere Arrays). Werden keine Argumente angegeben, wird ein leeres Array erstellt.

Rückgabe:

  • Ein undurchsichtiges Handle, das das erstellte Array darstellt. Dieses Handle sollte an andere Array-Funktionen (etwa array::put_at, array::get_at, array::len) übergeben werden, um den Inhalt des Arrays zu bearbeiten.

Beispiel:

// Ein leeres Array erstellen
empty = array::new()

// Ein Array mit numerischen Anfangswerten erstellen
temperatures = array::new(21.5, 22.0, 19.8, 23.1)

// Ein Array mit gemischten Typen erstellen
config = array::new("sensor1", 100, true)

// Ein Array mit Zeichenkettenwerten für Raumnamen erstellen
rooms = array::new("Living Room", "Kitchen", "Bedroom", "Bathroom")

// Arrays können verwendet werden, um Sensormesswerte über die Zeit zu sammeln
readings = array::new()
// Später: array::push(readings, current_value)

# array::len

Gibt die Anzahl der aktuell im Array gespeicherten Elemente zurück. Diese Funktion ist nützlich, um zu prüfen, ob ein Array leer ist, über alle Elemente zu iterieren oder die Array-Größe vor dem Zugriff auf bestimmte Indizes zu validieren.

Parameter:

  • arr: Das von array::new zurückgegebene undurchsichtige Array-Handle.

Rückgabe:

  • Ein Ganzzahlwert, der die Anzahl der Elemente im Array angibt.

Beispiel:

// Die Größe eines Arrays prüfen
temps = array::new(21.5, 22.0, 19.8)
count = array::len(temps) // Gibt 3 zurück

// Prüfen, ob ein Array leer ist
data = array::new()
if (array::len(data) == 0) {
    std::print("No data collected yet")
}

// Länge für Iterationsgrenzen verwenden
sensors = array::new("temp1", "temp2", "humidity")
i = 0
while (i < array::len(sensors)) {
    // Jeden Sensor verarbeiten...
    i = i + 1
}

# array::get_at

Ruft den am angegebenen Index im Array gespeicherten Wert ab. Array-Indizes sind nullbasiert, das heißt, das erste Element befindet sich an Index 0, das zweite an Index 1 und so weiter.

Parameter:

  • arr: Das von array::new zurückgegebene undurchsichtige Array-Handle.
  • index: Die nullbasierte Position des abzurufenden Elements.

Rückgabe:

  • Der am angegebenen Index gespeicherte Wert. Der Rückgabetyp hängt davon ab, was an dieser Position gespeichert wurde.

Warnung: Sie müssen sicherstellen, dass der Index innerhalb der gültigen Grenzen liegt (d. h. 0 <= index < array::len(arr)), bevor Sie diese Funktion aufrufen. Der Versuch, auf einen nicht vorhandenen Index zuzugreifen, führt zu einem Programmausführungsfehler, der zu undefiniertem Verhalten führen kann. Validieren Sie den Index immer zuerst mit array::len().

Beispiel:

temps = array::new(21.5, 22.0, 19.8, 23.1)

// Sicherer Zugriff: zuerst die Grenzen prüfen
index = 2
if (index < array::len(temps)) {
    value = array::get_at(temps, index) // Gibt 19.8 zurück
    std::print(str::fmt("Temperature at index {}: {}°C", index, value))
}

// Sicher über alle Elemente iterieren
i = 0
while (i < array::len(temps)) {
    temp = array::get_at(temps, i)
    if (temp > 22.0) {
        std::print(str::fmt("High temperature detected: {}°C", temp))
    }
    i = i + 1
}

// GEFÄHRLICH: Tun Sie dies niemals ohne Grenzenprüfung!
// value = array::get_at(temps, 10) // Undefiniertes Verhalten - kann abstürzen!

# array::put_at

Speichert einen Wert am angegebenen Index im Array und ersetzt dabei jeden vorhandenen Wert an dieser Position. Array-Indizes sind nullbasiert, das heißt, das erste Element befindet sich an Index 0, das zweite an Index 1 und so weiter. Diese Funktion verändert das Array direkt und gibt keinen Wert zurück.

Parameter:

  • arr: Das von array::new zurückgegebene undurchsichtige Array-Handle.
  • index: Die nullbasierte Position, an der der Wert gespeichert werden soll.
  • value: Der am angegebenen Index zu speichernde Wert. Der Typ des Werts muss dem Typ des bereits an dieser Position im Array gespeicherten Elements entsprechen.

Rückgabe:

  • Keine.

Warnung: Sie müssen sicherstellen, dass der Index innerhalb der gültigen Grenzen liegt (d. h. 0 <= index < array::len(arr)), bevor Sie diese Funktion aufrufen. Der Versuch, auf einen nicht vorhandenen Index zu schreiben, führt zu einem Programmausführungsfehler, der zu undefiniertem Verhalten führen kann. Validieren Sie den Index immer zuerst mit array::len().

Beispiel:

// Ein Array mit Anfangswerten erstellen
temps = array::new(21.5, 22.0, 19.8, 23.1)

// Sichere Aktualisierung: zuerst die Grenzen prüfen
index = 1
if (index < array::len(temps)) {
    array::put_at(temps, index, 25.0) // Ersetzt 22.0 durch 25.0
}

// Alle Werte in einer Schleife aktualisieren
i = 0
while (i < array::len(temps)) {
    current = array::get_at(temps, i)
    // Einen Korrekturfaktor anwenden
    array::put_at(temps, i, current + 0.5)
    i = i + 1
}

// Bestimmte Elemente in einem Array von Zeichenketten aktualisieren
sensors = array::new("sensor1", "sensor2", "sensor3")
array::put_at(sensors, 0, "temp1")
array::put_at(sensors, 1, "temp2")
array::put_at(sensors, 2, "humidity")

// GEFÄHRLICH: Tun Sie dies niemals ohne Grenzenprüfung!
// array::put_at(temps, 10, 99.9) // Undefiniertes Verhalten - kann abstürzen!

# array::append

Fügt einen Wert am Ende des Arrays hinzu und vergrößert seine Größe um eins. Diese Funktion ist nützlich, um Arrays dynamisch aufzubauen, wenn die endgültige Größe im Voraus nicht bekannt ist.

Parameter:

  • arr: Das von array::new zurückgegebene undurchsichtige Array-Handle.
  • value: Der am Ende des Arrays hinzuzufügende Wert.

Rückgabe:

  • Keine.

Beispiel:

// Ein Array dynamisch durch Anhängen von Werten aufbauen
temps = array::new(21.5)
array::append(temps, 22.0)
array::append(temps, 19.8)
array::append(temps, 23.1)
// temps enthält jetzt: [21.5, 22.0, 19.8, 23.1]

// Sensormesswerte über die Zeit sammeln
readings = array::new(0.0) // Mit dem ersten Messwert initialisieren
array::append(readings, 0.5)
array::append(readings, 1.2)

// Die neue Größe prüfen
count = array::len(readings) // Gibt 3 zurück

// In einer Schleife anhängen (z. B. 5 Messwerte sammeln)
data = array::new(100)
i = 0
while (i < 4) {
    array::append(data, 100 + i)
    i = i + 1
}
// data enthält jetzt: [100, 100, 101, 102, 103]

# array::clear

Entfernt alle Elemente aus dem Array und lässt es leer zurück. Nach dem Aufruf dieser Funktion gibt array::len(arr) den Wert 0 zurück. Diese Funktion ist nützlich, um ein Array wiederzuverwenden, ohne ein neues zu erstellen.

Parameter:

  • arr: Das von array::new zurückgegebene undurchsichtige Array-Handle.

Rückgabe:

  • Keine.

Beispiel:

// Ein Array erstellen und befüllen
temps = array::new(21.5, 22.0, 19.8, 23.1)
std::print(str::fmt("Length before clear: {}", array::len(temps))) // 4

// Alle Elemente löschen
array::clear(temps)
std::print(str::fmt("Length after clear: {}", array::len(temps))) // 0

// Das Array kann wiederverwendet werden
array::append(temps, 25.0)
array::append(temps, 26.5)
// temps enthält jetzt: [25.0, 26.5]

// Nützlich für periodische Datensammlung - alte Messwerte löschen
readings = array::new(0.0)
// ... Messwerte sammeln ...
array::append(readings, 1.5)
array::append(readings, 2.3)
// ... Messwerte verarbeiten ...
// Für den nächsten Sammelzyklus zurücksetzen
array::clear(readings)

# Map-Operationen

Dieser Abschnitt beschreibt Funktionen zum Erstellen und Bearbeiten von Maps (Schlüssel-Wert-Wörterbüchern). Maps in Volang verwenden Zeichenketten als Schlüssel und können Werte beliebigen Typs speichern.

# map::new

Erstellt eine neue leere Map. Eine Map ist eine Sammlung von Schlüssel-Wert-Paaren, bei der die Schlüssel immer Zeichenketten sind. Werte können von beliebigem Typ sein (Zahlen, Zeichenketten, boolesche Werte, Arrays oder andere Maps). Maps sind nützlich, um strukturierte Daten oder Konfigurationseinstellungen zu speichern oder JSON-ähnliche Objekte darzustellen.

Parameter:

  • Keine.

Rückgabe:

  • Ein undurchsichtiges Handle, das die erstellte Map darstellt. Dieses Handle sollte an andere Map-Funktionen (etwa map::set, map::get, map::contains) übergeben werden, um den Inhalt der Map zu bearbeiten.

Beispiel:

// Eine leere Map erstellen
config = map::new()

// Die Map ist jetzt bereit, Schlüssel-Wert-Paare zu speichern
// map::set(config, "temperature", 22.5)
// map::set(config, "location", "Living Room")

// Maps werden auch von einigen Funktionen zurückgegeben, z. B. HTTP-Antwort-Header
// Im http::on_response-Callback ist der Parameter 'headers' eine Map

# map::len

Gibt die Anzahl der aktuell in der Map gespeicherten Schlüssel-Wert-Paare zurück. Diese Funktion ist nützlich, um zu prüfen, ob eine Map leer ist, oder um festzustellen, wie viele Einträge sie enthält.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.

Rückgabe:

  • Ein Ganzzahlwert, der die Anzahl der Schlüssel-Wert-Paare in der Map angibt.

Beispiel:

config = map::new()

// Die Größe einer leeren Map prüfen
count = map::len(config) // Gibt 0 zurück

// Nach dem Hinzufügen von Elementen erhöht sich die Anzahl
// map::set(config, "temperature", 22.5)
// map::set(config, "humidity", 45)
// count = map::len(config) // Gibt 2 zurück

// Prüfen, ob eine Map leer ist
if (map::len(config) == 0) {
    std::print("Map is empty")
}

# map::set

Fügt einen Wert für den angegebenen Schlüssel in der Map hinzu oder aktualisiert ihn. Existiert der Schlüssel nicht, wird ein neues Schlüssel-Wert-Paar erstellt. Existiert der Schlüssel bereits, wird der Wert durch den neuen ersetzt, wobei der neue Wert vom selben Typ wie der vorhandene Wert sein muss.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.
  • key: Eine Zeichenkette, die den Schlüsselnamen angibt.
  • value: Der zu speichernde Wert. Kann von beliebigem Typ sein (Zahl, Zeichenkette, boolescher Wert, Array oder eine andere Map).

Rückgabe:

  • Keine.

Beispiel:

config = map::new()

// Neue Schlüssel-Wert-Paare hinzufügen
map::set(config, "temperature", 22.5)
map::set(config, "location", "Living Room")
map::set(config, "active", true)

// Vorhandenen Wert aktualisieren (gleicher Typ erforderlich)
map::set(config, "temperature", 23.0) // OK - Gleitkomma zu Gleitkomma

// Unterschiedliche Typen unter unterschiedlichen Schlüsseln speichern
map::set(config, "sensor_count", 5)      // Ganzzahl
map::set(config, "sensor_name", "temp1") // Zeichenkette
map::set(config, "enabled", true)        // boolescher Wert

# map::get

Ruft den mit dem angegebenen Schlüssel verknüpften Wert aus der Map ab. Der Rückgabetyp hängt davon ab, was unter diesem Schlüssel gespeichert wurde.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.
  • key: Eine Zeichenkette, die den abzurufenden Schlüsselnamen angibt.

Rückgabe:

  • Der unter dem angegebenen Schlüssel gespeicherte Wert. Der Rückgabetyp entspricht dem Typ des gespeicherten Werts.

Warnung: Der angegebene Schlüssel muss in der Map existieren. Der Versuch, einen Wert für einen nicht vorhandenen Schlüssel abzurufen, führt zu einem Laufzeitfehler. Verwenden Sie immer map::contains, um zu prüfen, ob der Schlüssel existiert, bevor Sie diese Funktion aufrufen.

Beispiel:

config = map::new()
map::set(config, "temperature", 22.5)
map::set(config, "location", "Living Room")

// Sicherer Zugriff: zuerst prüfen, ob der Schlüssel existiert
if (map::contains(config, "temperature")) {
    temp = map::get(config, "temperature")
    std::print(str::fmt("Temperature: {}°C", temp))
}

// Auf den Wert zugreifen, wenn Sie wissen, dass der Schlüssel existiert
location = map::get(config, "location") // Gibt "Living Room" zurück

// GEFÄHRLICH: Tun Sie dies niemals ohne vorherige Prüfung!
// value = map::get(config, "nonexistent") // Laufzeitfehler!

# map::clear

Entfernt alle Schlüssel-Wert-Paare aus der Map und lässt sie leer zurück. Nach dem Aufruf dieser Funktion gibt map::len(map) den Wert 0 zurück. Diese Funktion ist nützlich, um eine Map wiederzuverwenden, ohne eine neue zu erstellen.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.

Rückgabe:

  • Keine.

Beispiel:

config = map::new()
map::set(config, "temperature", 22.5)
map::set(config, "humidity", 45)
std::print(str::fmt("Size before clear: {}", map::len(config))) // 2

// Alle Einträge löschen
map::clear(config)
std::print(str::fmt("Size after clear: {}", map::len(config))) // 0

// Die Map kann wiederverwendet werden
map::set(config, "new_key", "new_value")

# map::contains

Prüft, ob der angegebene Schlüssel in der Map existiert. Diese Funktion sollte vor dem Aufruf von map::get verwendet werden, um Laufzeitfehler beim Zugriff auf nicht vorhandene Schlüssel zu vermeiden.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.
  • key: Eine Zeichenkette, die den zu prüfenden Schlüsselnamen angibt.

Rückgabe:

  • true, wenn der Schlüssel in der Map existiert; andernfalls false.

Beispiel:

config = map::new()
map::set(config, "temperature", 22.5)
map::set(config, "location", "Living Room")

// Prüfen, ob ein Schlüssel existiert
if (map::contains(config, "temperature")) {
    std::print("Temperature key exists")
    temp = map::get(config, "temperature")
}

// Auf einen nicht vorhandenen Schlüssel prüfen
if (map::contains(config, "humidity")) {
    humidity = map::get(config, "humidity")
} else {
    std::print("Humidity not set")
}

// In bedingter Logik verwenden
key = "location"
if (map::contains(config, key)) {
    value = map::get(config, key)
    std::print(str::fmt("Found {}: {}", key, value))
}

# map::keys

Gibt ein Array zurück, das alle aktuell in der Map gespeicherten Schlüssel enthält. Über das zurückgegebene Array kann mit array::len und array::get_at iteriert werden, um jeden Schlüssel zu verarbeiten. Die Reihenfolge der Schlüssel ist nicht garantiert.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.

Rückgabe:

  • Ein Array von Zeichenketten, wobei jedes Element ein Schlüssel aus der Map ist.

Beispiel:

settings = map::new()
map::set(settings, "brightness", 80)
map::set(settings, "color", "warm")
map::set(settings, "enabled", true)

keys = map::keys(settings)
i = 0
while (i < array::len(keys)) {
    key = array::get_at(keys, i)
    value = map::get(settings, key)
    std::print(str::fmt("{} = {}", key, value))
    i = i + 1
}

# map::values

Gibt ein Array zurück, das alle aktuell in der Map gespeicherten Werte enthält. Über das zurückgegebene Array kann mit array::len und array::get_at iteriert werden. Die Reihenfolge der Werte entspricht der Reihenfolge der von map::keys zurückgegebenen Schlüssel.

Parameter:

  • map: Das von map::new zurückgegebene undurchsichtige Map-Handle.

Rückgabe:

  • Ein Array von Werten, wobei jedes Element ein Wert aus der Map ist. Die Elemente können von beliebigem Typ sein.

Beispiel:

sensors = map::new()
map::set(sensors, "temp", 22.5)
map::set(sensors, "humidity", 65)

values = map::values(sensors)
i = 0
while (i < array::len(values)) {
    std::print(array::get_at(values, i))
    i = i + 1
}

# JSON-Operationen

Dieser Abschnitt beschreibt Funktionen für die Arbeit mit JSON-Daten. JSON (JavaScript Object Notation) ist ein gängiges Format für den Datenaustausch, insbesondere bei der Kommunikation mit Web-APIs.

# json::get

Extrahiert einen Wert aus einer JSON-Zeichenkette mithilfe eines Pfads in Punktnotation. Diese Funktion parst das JSON und navigiert durch verschachtelte Objekte, um den Wert an der angegebenen Position abzurufen.

Parameter:

  • json: Eine Zeichenkette mit gültigen JSON-Daten.
  • path: Eine Zeichenkette, die den Pfad zum gewünschten Feld in Punktnotation angibt (z. B. "a.b.c.d").

Rückgabe:

  • Der Wert am angegebenen Pfad. Der Rückgabetyp hängt vom JSON-Werttyp ab: string, number, bool oder array (derselbe Array-Typ wie in den Array-Operationen beschrieben, verwendbar mit den array::*-Funktionen).

Beispiel:

// Einfaches JSON-Objekt
json_data = """{"temperature": 22.5, "location": "Living Room", "active": true}"""
temp = json::get(json_data, "temperature") // Gibt 22.5 zurück
location = json::get(json_data, "location") // Gibt "Living Room" zurück
active = json::get(json_data, "active") // Gibt true zurück

// Verschachteltes JSON-Objekt
nested = """{"sensor": {"id": "temp1", "value": 23.5, "enabled": false}}"""
sensor_id = json::get(nested, "sensor.id") // Gibt "temp1" zurück
sensor_value = json::get(nested, "sensor.value") // Gibt 23.5 zurück
sensor_enabled = json::get(nested, "sensor.enabled") // Gibt false zurück

// Tief verschachtelte Struktur
deep = """{"building": {"floor": {"room": {"temperature": 22.0}}}}"""
room_temp = json::get(deep, "building.floor.room.temperature") // Gibt 22.0 zurück

// Einen Array-Wert abrufen
json_with_array = """{"readings": [21.5, 22.0, 22.5]}"""
readings = json::get(json_with_array, "readings") // Gibt Array [21.5, 22.0, 22.5] zurück

# HTTP-Operationen

Dieser Abschnitt beschreibt Funktionen zum Senden von HTTP-Anfragen an externe Dienste. Diese Funktionen ermöglichen es Ihren Volang-Skripten, mit Web-APIs zu kommunizieren, Benachrichtigungen zu senden oder Dienste von Drittanbietern zu integrieren.

# http::client

Erstellt eine neue HTTP-Client-Instanz, die zum Senden von HTTP-Anfragen erforderlich ist. Der Client verwaltet die Verbindungseinstellungen, kümmert sich um die Ausführung der Anfrage und muss erstellt werden, bevor andere HTTP-Funktionen aufgerufen werden.

Parameter:

  • Keine.

Rückgabe:

  • Ein undurchsichtiges Handle, das den HTTP-Client darstellt. Dieses Handle sollte an andere HTTP-Funktionen (etwa http::call) übergeben werden, um Anfragen auszuführen.

Beispiel:

// Einen HTTP-Client erstellen
client = http::client()

// Der Client ist jetzt bereit, Anfragen zu senden

# http::set_method

Setzt die HTTP-Methode für die Anfrage. Diese Funktion muss aufgerufen werden, bevor die Anfrage mit http::call ausgeführt wird. Wird sie nicht gesetzt, ist die Standardmethode GET.

Parameter:

  • client: Das von http::client zurückgegebene undurchsichtige HTTP-Client-Handle.
  • method: Eine Zeichenkette, die die HTTP-Methode angibt. Unterstützte Werte: "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS".

Rückgabe:

  • Keine.

Beispiel:

client = http::client()

// Methode auf POST setzen, um Daten zu senden
http::set_method(client, "POST")

// Methode auf GET setzen, um Daten abzurufen (dies ist der Standard)
http::set_method(client, "GET")

// Methode auf PUT setzen, um Ressourcen zu aktualisieren
http::set_method(client, "PUT")

// Methode auf DELETE setzen, um Ressourcen zu entfernen
http::set_method(client, "DELETE")

# http::set_header

Fügt der Anfrage einen benutzerdefinierten HTTP-Header hinzu. Diese Funktion kann mehrfach aufgerufen werden, um mehrere Header hinzuzufügen. Header werden verwendet, um zusätzliche Informationen mit der Anfrage zu übergeben, etwa Authentifizierungstoken, Angaben zum Inhaltstyp oder benutzerdefinierte Metadaten.

Parameter:

  • client: Das von http::client zurückgegebene undurchsichtige HTTP-Client-Handle.
  • key: Eine Zeichenkette, die den Header-Namen angibt (z. B. "Content-Type", "Authorization").
  • value: Eine Zeichenkette, die den Header-Wert angibt.

Rückgabe:

  • Keine.

Beispiel:

client = http::client()
http::set_method(client, "POST")

// Inhaltstyp für JSON-Daten setzen
http::set_header(client, "Content-Type", "application/json")

// Authorization-Header mit API-Schlüssel hinzufügen
http::set_header(client, "Authorization", "Bearer my-api-token-123")

// Benutzerdefinierte Header hinzufügen
http::set_header(client, "X-Custom-Header", "custom-value")
http::set_header(client, "Accept", "application/json")

# http::set_body

Setzt den Inhalt des Anfragekörpers. Diese Funktion wird typischerweise mit POST-, PUT- oder PATCH-Anfragen verwendet, um Daten an den Server zu senden. Der Körper kann JSON, Formulardaten oder beliebige andere textbasierte Inhalte enthalten. Denken Sie daran, mit http::set_header den passenden Content-Type-Header zu setzen, damit er zum Körperformat passt.

Parameter:

  • client: Das von http::client zurückgegebene undurchsichtige HTTP-Client-Handle.
  • body: Eine Zeichenkette, die den Inhalt des Anfragekörpers enthält.

Rückgabe:

  • Keine.

Beispiel:

client = http::client()
http::set_method(client, "POST")
http::set_header(client, "Content-Type", "application/json")

// JSON-Körper setzen
http::set_body(client, """{"temperature": 22.5, "humidity": 45}""")

// Oder den Körper dynamisch mit str::fmt aufbauen
temp = 22.5
humidity = 45
body = str::fmt("""{"temperature": {}, "humidity": {}}""", temp, humidity)
http::set_body(client, body)

# http::call

Führt die HTTP-Anfrage an die angegebene URL mit den konfigurierten Client-Einstellungen (Methode, Header, Körper) aus. Diese Funktion ist asynchron: Sie sendet die Anfrage und kehrt sofort zurück. Die Antwort wird über die Callback-Funktion http::on_response zugestellt, die in Ihrem Skript definiert sein muss. Unterstützte Protokolle sind http:// und https://.

Parameter:

  • client: Das von http::client zurückgegebene undurchsichtige HTTP-Client-Handle.
  • url: Eine Zeichenkette mit der vollständigen URL, an die die Anfrage gesendet werden soll.

Rückgabe:

  • Keine. Die Antwort wird asynchron über den http::on_response-Callback zugestellt.

Callback: http::on_response(status, body, headers)

Um die HTTP-Antwort zu empfangen, müssen Sie eine externe Callback-Funktion mit der folgenden Signatur definieren:

extern fn http::on_response(status, body, headers) {
    // Die Antwort hier behandeln
}

Callback-Parameter:

  • status: Eine Ganzzahl, die den HTTP-Statuscode darstellt (z. B. 200 für Erfolg, 404 für nicht gefunden, 500 für Serverfehler).
  • body: Eine Zeichenkette, die den Inhalt des Antwortkörpers enthält.
  • headers: Ein Map-Objekt (siehe Map-Operationen), das die Antwort-Header als Schlüssel-Wert-Paare enthält.

Beispiel:

// Den Antwort-Callback definieren - dieser wird aufgerufen, wenn die Antwort eintrifft
extern fn http::on_response(status, body, headers) {
    if (status == 200) {
        std::print(str::fmt("Success! Response: {}", body))
    } else {
        std::print(str::fmt("Error: HTTP {}", status))
    }
}

// Die Anfrage vorbereiten und senden
client = http::client()
http::set_method(client, "GET")
http::set_header(client, "Accept", "application/json")
http::call(client, "http://192.168.1.100/api/status")

// Für eine POST-Anfrage mit Daten
client2 = http::client()
http::set_method(client2, "POST")
http::set_header(client2, "Content-Type", "application/json")
http::set_body(client2, """{"command": "turn_on"}""")
http::call(client2, "http://192.168.1.100/api/device/relay1")

# TCP-Operationen

Dieser Abschnitt beschreibt Funktionen für die reine TCP-Kommunikation. Sie ermöglichen es einem Volang-Skript, mit Geräten und Diensten zu kommunizieren, die ein eigenes binäres oder textbasiertes Protokoll über TCP sprechen, etwa SPS, Media-Controller oder Industrie-Gateways, bei denen kein HTTP verfügbar ist.

# tcp::oneshot

Führt einen vollständigen TCP-Austausch in einem einzigen Aufruf durch: Es öffnet eine Verbindung zur angegebenen Adresse, sendet die Anfrage-Bytes, liest die Antwort und schließt anschließend die Verbindung. Diese Funktion ist asynchron: Sie startet den Austausch und kehrt sofort zurück. Das Ergebnis wird an den on_result-Callback zugestellt, sobald die Antwort empfangen wurde, die erwartete Anzahl Bytes eingetroffen ist oder die Operation fehlschlägt.

Verwenden Sie diese Funktion für kurze Anfrage-Antwort-Protokolle, bei denen pro Verbindung eine Nachricht gesendet und eine Antwort erwartet wird.

Parameter:

  • sa (string): Die Socket-Adresse des entfernten Hosts in der Form "host:port" (zum Beispiel "192.168.1.50:9100").
  • din: Ein Byte-Array (mit array::new erstellt), das die zu sendenden Anfragedaten enthält. Jedes Element ist ein Byte-Wert im Bereich 0255.
  • exrs (integer): Die erwartete Antwortgröße in Bytes. Die Funktion liest bis zu dieser Anzahl Bytes, bevor sie den Austausch abschließt.
  • on_result (string): Der Name des extern fn-Callbacks, der mit dem Ergebnis aufgerufen wird. Die Funktion muss im selben Skript definiert sein.

Rückgabe:

  • Keine. Das Ergebnis wird asynchron über den on_result-Callback zugestellt.

Callback: on_result(result, dout)

Der in on_result benannte Callback muss im selben Skript mit der Syntax extern fn deklariert sein:

extern fn on_result(result, dout) {
    // Die Antwort hier behandeln
}

Callback-Parameter:

  • result (integer): 0, wenn der Austausch erfolgreich war, oder -1, wenn er fehlgeschlagen ist (zum Beispiel wenn die Verbindung nicht hergestellt werden konnte, eine Zeitüberschreitung auftrat oder sie geschlossen wurde, bevor die erwarteten Daten eintrafen).
  • dout: Ein Byte-Array mit den Antwort-Bytes. Bei einem Fehler kann das Array leer sein.

Beispiel:

// Die Antwort behandeln, sobald der Austausch abgeschlossen ist
extern fn on_result(result, dout) {
    if (result != 0) {
        // Das Gerät als nicht erreichbar markieren
        output::set("online", false)
        return
    }

    // Das erste Byte der Antwort lesen und seinen Zustand ausgeben
    if (array::len(dout) > 0) {
        status = array::get_at(dout, 0)
        output::set("online", true)
        output::set("status", status)
    }
}

// Die Anfrage-Nutzlast als Byte-Array aufbauen
request = array::new(0x01, 0x03, 0x00, 0x00)

// 4 Bytes senden und eine 8-Byte-Antwort erwarten
tcp::oneshot("192.168.1.50:9100", request, 8, "on_result")

# Zeitoperationen

# time::now

Ruft die aktuelle Systemzeit als Unix-Zeitstempel ab. Der Wert stellt die Anzahl der Sekunden dar, die seit 00:00:00 UTC am 1. Januar 1970 (der Unix-Epoche) vergangen sind.

Diese Funktion ist unerlässlich, um zu verfolgen, wann Ereignisse aufgetreten sind, die zwischen Aktionen vergangene Zeit zu berechnen oder sich mit externen Servern zu synchronisieren.

Parameter:

  • Keine.

Rückgabe:

  • Ein Ganzzahlwert, der den aktuellen Unix-Zeitstempel (in Sekunden) darstellt.

Beispiel:

// Die Zeit speichern, zu der zuletzt Bewegung erkannt wurde
last_motion_time = time::now()

// ... später im Code ...

// Prüfen, ob seit der letzten Bewegung mehr als 60 Sekunden vergangen sind
if (time::now() > last_motion_time + 60) {
   ...
}

# time::uptime

Gibt die Anzahl der Sekunden zurück, die seit dem Einschalten oder dem letzten Neustart des Moduls vergangen sind. Dieser Wert ist nützlich, um den Systemzustand zu überwachen, unerwartete Neustarts zu erkennen oder zeitbasierte Logik umzusetzen, die nach einem Stromzyklus zurückgesetzt werden soll.

Anders als time::now(), das einen absoluten Zeitstempel liefert, liefert time::uptime() eine relative Messung, die bei jedem Start des Moduls bei null beginnt.

Parameter:

  • Keine.

Rückgabe:

  • Ein Ganzzahlwert, der die Anzahl der Sekunden seit dem Start des Moduls darstellt.

Beispiel:

// Eine Warnung protokollieren, wenn das Modul länger als 24 Stunden läuft
// (könnte darauf hindeuten, dass es nicht zur Wartung neu gestartet wurde)
if (time::uptime() > 86400) {
    std::print("Module running for over 24 hours")
}

// Die Initialisierungslogik verzögern, bis das Modul 10 Sekunden lang stabil war
if (time::uptime() > 10) {
    // Man kann davon ausgehen, dass alle Sensoren initialisiert sind
    ...
}

// Erkennen, ob das Modul kürzlich neu gestartet wurde
if (time::uptime() < 60) {
    std::print("Module just started, initializing...")
}

# Mathematische Operationen

# math::abs

Berechnet den Absolutwert einer Zahl. Ist die Eingabe negativ, gibt sie das positive Äquivalent zurück; ist die Eingabe positiv, gibt sie den Wert unverändert zurück. Diese Funktion unterstützt sowohl Ganzzahl- als auch Gleitkommatypen.

Sie ist besonders nützlich, um die Differenz (Delta) zwischen zwei Sensormesswerten zu berechnen, ohne sich darum zu kümmern, welcher Wert größer ist (z. B. um zu prüfen, ob sich die Temperatur in eine beliebige Richtung um mehr als 1 Grad geändert hat).

Parameter:

  • value: Die zu verarbeitende Zahl.

Rückgabe:

  • Ein numerischer Wert, der den nicht negativen Wert der Eingabe darstellt. Der Rückgabetyp entspricht dem Eingabetyp.

Beispiel:

target_temp = 21.0
current_temp = 19.5

// Die Differenz unabhängig von der Richtung berechnen
delta = math::abs(target_temp - current_temp)

// Wenn die Differenz erheblich ist (mehr als 0,5 Grad), Aktion ausführen
if (delta > 0.5) {
    ....
}

# math::round

Rundet die gegebene Gleitkommazahl auf den nächsten Ganzzahlwert. Grenzfälle (bei denen der Nachkommaanteil genau 0.5 beträgt) werden von null weg gerundet.

Parameter:

  • value: Die zu rundende Zahl.

Rückgabe:

  • Eine Ganzzahl, die die nächste ganze Zahl darstellt.

Beispiel:

// Beispiel 1: Sensordaten für die Anzeige runden
rawTemp = 21.7
displayTemp = math::round(rawTemp) // Gibt 22 zurück

// Beispiel 2: Grenzfälle (Runden von null weg)
val1 = math::round(2.5)  // Gibt 3 zurück
val2 = math::round(-2.5) // Gibt -3 zurück

// Eine Dimmerstufe setzen (muss eine Ganzzahl 0-100 sein)
calculatedLevel = 55.4
dimmerLevel = math::round(calculatedLevel) // Gibt 55 zurück

# math::random

Gibt eine pseudozufällige Gleitkommazahl im Bereich [0.0, 1.0) zurück. Jeder Aufruf erzeugt einen anderen Wert. Das Ergebnis kann skaliert und mit math::round kombiniert werden, um zufällige Ganzzahlen innerhalb eines gewünschten Bereichs zu erzeugen.

Parameter:

Keine.

Rückgabe:

  • Ein Gleitkommawert, der größer oder gleich 0.0 und kleiner als 1.0 ist.

Beispiel:

// Einen zufälligen Wert zwischen 0.0 und 1.0 erhalten
r = math::random()

// Eine zufällige Ganzzahl zwischen 1 und 100 erzeugen
n = math::round(math::random() * 100) + 1

// Zufällige boolesche Entscheidung (50/50)
if (math::random() < 0.5) {
    output::set("led", true)
} else {
    output::set("led", false)
}

# Base64-Operationen

Dieser Abschnitt beschreibt Funktionen zum Kodieren von Daten mit Base64-Kodierungsschemata.

# base64::encode

Kodiert eine Zeichenkette in ihre Base64-Darstellung unter Verwendung des Standardalphabets (RFC 4648 Tabelle 1). Die Ausgabe verwendet die Zeichen A-Z, a-z, 0-9, +, / und wird mit =-Zeichen aufgefüllt, um sicherzustellen, dass die Ausgabelänge ein Vielfaches von 4 ist.

Parameter:

  • data (string): Die zu kodierende Eingabezeichenkette.

Rückgabe:

  • Eine Zeichenkette, die die Base64-kodierte Darstellung der Eingabe enthält.

Beispiel:

// Eine einfache Zeichenkette kodieren
encoded = base64::encode("Hello, World!") // Gibt "SGVsbG8sIFdvcmxkIQ==" zurück

// Anmeldedaten für HTTP Basic Auth kodieren
credentials = str::concat("user", ":", "password")
auth = str::concat("Basic ", base64::encode(credentials))
http::set_header(client, "Authorization", auth)

// Eine leere Zeichenkette wird zu einer leeren Zeichenkette kodiert
encoded = base64::encode("") // Gibt "" zurück

# base64::url_encode

Kodiert eine Zeichenkette in ihre Base64url-Darstellung unter Verwendung des URL-sicheren Alphabets (RFC 4648 Tabelle 2). Die Ausgabe verwendet die Zeichen A-Z, a-z, 0-9, -, _ und enthält keine Auffüllzeichen. Diese Kodierung eignet sich für die Verwendung in URLs, Query-Parametern und JWT-Segmenten.

Parameter:

  • data (string): Die zu kodierende Eingabezeichenkette.

Rückgabe:

  • Eine Zeichenkette, die die Base64url-kodierte Darstellung der Eingabe ohne Auffüllung enthält.

Beispiel:

// Für URL-sichere Verwendung kodieren
encoded = base64::url_encode("Hello, World!") // Gibt "SGVsbG8sIFdvcmxkIQ" zurück

// Einen JWT-Header und eine JWT-Nutzlast aufbauen
header = base64::url_encode("""{"alg":"RS256","typ":"JWT"}""")
payload = base64::url_encode("""{"sub":"1234567890","name":"John"}""")
signing_input = str::concat(header, ".", payload)

// Beachten Sie den Unterschied zum Standard-Base64:
// base64::encode("subjects?_d")     gibt "c3ViamVjdHM/X2Q=" zurück
// base64::url_encode("subjects?_d") gibt "c3ViamVjdHM_X2Q" zurück

# Kryptografische Operationen

Dieser Abschnitt beschreibt Funktionen zum Durchführen kryptografischer Operationen.

# crypto::rs256_sign

Signiert Daten mit einem privaten RSA-Schlüssel unter Verwendung des RS256-Algorithmus (RSASSA-PKCS1-v1_5 mit SHA-256). Diese Funktion wird typischerweise verwendet, um JWT-Signaturen oder andere authentifizierte Nachrichten zu erstellen.

Parameter:

  • data (string): Die zu signierenden Daten.
  • private_key_pem (string): Der private RSA-Schlüssel im PEM-Format.

Rückgabe:

  • Eine Zeichenkette, die die Base64url-kodierte Signatur enthält.

Beispiel:

// Eine JWT-Signatur erstellen
header = base64::url_encode("""{"alg":"RS256","typ":"JWT"}""")
payload = base64::url_encode("""{"sub":"device-001","iat":1700000000}""")
signing_input = str::concat(header, ".", payload)

// Mit dem privaten Schlüssel signieren
signature = crypto::rs256_sign(signing_input, private_key)

// Das vollständige JWT zusammensetzen
jwt = str::concat(signing_input, ".", signature)

# Asynchrone Operationen

Dieser Abschnitt beschreibt Callback-Funktionen, die definiert werden können, um asynchrone Ereignisse und Antworten zu behandeln.

Referenzdokumentation für die Funktionen und Module der Volang-Standardbibliothek.