# Inhalt - [Beschreibung](#beschreibung) - [Getting started](#getting-started) - [Beispiel 1](#beispiel-1) - [Beispiel 2](#beispiel-2) - [Beispiel 3](#beispiel-3) - [Blöcke](#blocks) - [Systemblöcke](#systemblöcke) - [Debug Ausgabe](#debug-ausgabe) - [Kommentar](#kommentar) - [Steuere State](#steuere-state) - [Aktualisiere State](#aktualisiere-state) - [Bind states](#bind-states) - [Write states](#write-states) - [Create state](#create-state) - [Get value of state](#get-value-of-state) - [Get Object ID](#get-object-id) - [Aktionsblöcke](#aktionsblöcke) - [Exec - Kommando](#exec---kommando) - [request URL](#request-url) - [SendTo Blöcke](#sendTo-blöcke) - [Send to telegram](#send-to-telegram) - [Send to SayIt](#send-to-sayit) - [Send to pushover](#send-to-pushover) - [Send email](#send-email) - [Custom sendTo block](#custom-sendto-block) - [Datum und Zeit Blöcke](#datum-und-zeit-blöcke) - [Time comparision](#time-comparision) - [Actual time comparision](#actual-time-comparision) - [Get actual time im specific format](#get-actual-time-im-specific-format) - [Get time of astro events for today](#get-time-of-astro-events-for-today) - [Convert blocks](#convert-blocks) - [Convert to number](#convert-to-number) - [Convert to boolean](#convert-to-boolean) - [Get type of variable](#get-type-of-variable) - [Convert to date/time object](#convert-to-datetime-object) - [Convert date/time object to string](#convert-datetime-object-to-string) - [Convert JSON to object](#convert-json-to-object) - [Convert object to JSON](#convert-object-to-json) - [Convert by JSONata Expression](#convert-by-jsonata-expression) - [Trigger](#trigger) - [Trigger on states change](#trigger-on-states-change) - [Trigger on state change](#trigger-on-state-change) - [Trigger info](#trigger-info) - [Schedule](#schedule) - [Trigger on astro event](#trigger-on-astro-event) - [Named schedule](#named-schedule) - [Clear schedule](#clear-schedule) - [CRON dialog](#cron-dialog) - [CRON rule](#cron-rule) - [Trigger auf Dateiaktualisierung](#trigger-auf-dateiaktualisierung) - [Ereignis bei Dateiaktualisierung abbrechen](#ereignis-bei-dateiaktualisierung-abbrechen) - [Timeouts](#timeouts) - [Delayed execution](#delayed-execution) - [Clear delayed execution](#clear-delayed-execution) - [Execution by interval](#execution-by-interval) - [Stop execution by interval](#stop-execution-by-interval) - [Logic](#logic) - [If else block](#if-else-block) - [Comparision block](#comparision-block) - [Logical AND/OR block](#logical-and-or-block) - [Negation block](#negation-block) - [Logical value TRUE/FALSE](#logical-value-true-false) - [null block](#null-block) - [Test block](#test-block) - [Loops](#loops) - [Repeat N times](#repeat-n-times) - [Repeat while](#repeat-while) - [Count](#count) - [For each](#for-each) - [Break out of loop](#break-out-of-loop) - [Math](#math) - [Number value](#number-value) - [Arithmetical operations +-\*/^](#arithmetical-operations--) - [Square root, Abs, -, ln, log10, e^, 10^](#square-root-abs---ln-log10-e-10) - [sin, cos, tan, asin, acos, atan](#sin-cos-tan-asin-acos-atan) - [Math constants: pi, e, phi, sqrt(2), sqrt(1/2), infinity](#math-constants-pi-e-phi-sqrt2-sqrt12-infinity) - [Is even, odd, prime, whole, positive, negative, divisibly by](#is-even-odd-prime-whole-positive-negative-divisibly-by) - [Modify variably by value plus or minus](#modify-variably-by-value-plus-or-minus) - [Round, floor, ceil value](#round-floor-ceil-value) - [Operations on the list of values: sum, min, max, average, median, modes, deviation, random item](#operations-on-the-list-of-values-sum-min-max-average-median-modes-deviation-random-item) - [Modulus](#modulus) - [Limit some value by min and max](#limit-some-value-by-min-and-max) - [Random value from 0 to 1](#random-value-from-0-to-1) - [Random value between min and max](#random-value-between-min-and-max) - [Text](#text) - [String value](#string-value) - [Concatenate strings](#concatenate-strings) - [Append string to variable](#append-string-to-variable) - [Length of string](#length-of-string) - [Is string empty](#is-string-empty) - [Find position in string](#find-position-in-string) - [Get symbol in string on specific position](#get-symbol-in-string-on-specific-position) - [Get substring](#get-substring) - [Convert to upper case or to lower case](#Convert-to-upper-case-or-to-lower-case) - [Trim string](#trim-string) - [Lists](#lists) - [Create empty list](#create-empty-list) - [Create list with values](#create-list-with-values) - [Create list with same value N times](#create-list-with-same-value-n-times) - [Get length of list](#get-length-of-list) - [Is list empty](#is-list-empty) - [Find position of item in list](#Find-position-of-item-in-list) - [Get item in list](#get-item-in-list) - [Set item in list](#set-item-in-list) - [Get sublist of list](#get-sublist-of-list) - [Convert text to list and vice versa](#convert-text-to-list-and-vice-versa) - [Colour](#colour) - [Colour value](#colour-value) - [Random colour](#random-colour) - [RGB colour](#rgb-colour) - [Mix colours](#mix-colours) - [Variables](#variables) - [Set variable's value](#set-variables-value) - [Get variable's value](#get-variables-value) - [Functions](#functions) - [Create function from blocks with no return value](#create-function-from-blocks-with-no-return-value) - [Create function from blocks with return value](#create-function-from-blocks-with-return-value) - [Return value in function ](#return-value-in-function) - [Create custom function with no return value](#create-custom-function-with-no-return-value) - [Create custom function with return value](#create-custom-function-with-return-value) - [Call function](#call-function)   # Beschreibung Blockly ist ein grafischer Editor, der es Nutzern erlaubt Skripte durch zusammenfügen von Blöcken zu erzeugen. Er wurde für Nutzer entwickelt, die keine Erfahrung in Programmierung von Computern besitzen.   # Getting started ## Beispiel 1 **Zustand eines Datenpunkts bei Änderung eines anderen Datenpunkts ändern** ![Getting started 1](img/getting_started_1_de.png) Dies ist das klassische Beispiel bei Änderung eines Datenpunktes etwas anderes zu schalten. Hier wird das Licht an oder ausgeschaltet wenn Bewegung bzw. keine Bewegung erkannt wird. Zuerst den Block "Triggers=>Falls Objekt" einfügen. Die Objekt ID auswählen um den Zustand des Objekts als Trigger für dieses Skript zu benutzen. Einen anderen Block - "System=>Steuere" hinzufügen und im Dialog den anderen Zustand der durch den Trigger geändert werden soll auswählen. In diesen Steuerungsblock einen Block "System=>Wert von Objekt ID" einfügen und im Dialog das Objekt "Bewegung" auswählen, um dessen Zustand in "Licht": zu schreiben. **Es gibt bei den Trigger Blöcken eine spezielle Variable "Wert". Diese wird immer hier definiert und kann für verschiedene Zwecke verwendet werden. Sie enthält den aktuellen Wert des triggernden Objekts und man kann daher einfacherer Skripte erzeugen indem man den Block "Variable=>Objekt ID" benutzt und ihn in "Wert" umbenennt.** ![Getting started 1](img/getting_started_1_2_de.png)   Beispiel zum importieren: ```xml Switch light ON or OFF it motion detected or IDLE ne javascript.0.Motion javascript.0.Light FALSE val javascript.0.Motion ```   ## Beispiel 2 **Licht bei Bewegung anschalten und ausschalten wenn 10 Minuten keine Bewegung.** ![Getting started 2](img/getting_started_2_de.png) Wenn der Zustand "Bewegung" mit dem Wert "wahr" aktualisiert wird, mache: - schalte "Licht" an - starte die Verzögerung von 10 Minuten um "Licht" auszuschalten und lösche alle bisherigen Verzögerungen für diesen Datenpunkt. Wie man sieht wird der Flag "lösche Verzögerung" durch den letzten Befehl gelöscht. Dieses löscht alle Timer für diesen Datenpunkt und startet einen neuen Timer   Beispiel zum importieren: Switch light ON and OFF in 10 minutes of IDLE true true javascript.0.Motion javascript.0.Light FALSE TRUE javascript.0.Light TRUE 600000 TRUE FALSE ```   ## Beispiel 3 **Verschicke eine E-Mail, wenn die Außentemperatur höher als 25 Grad Celsius ist.** ![Getting started 3](img/getting_started_3_de.png) Erklärung: Zuerst müssen wir eine Variable definieren um zu speichern, dass die E-Mail für den aktuellen Temperaturalarm bereits gesendet wurde und diese Variable auf "falsch" setzen. Dann beobachten wir die Veränderungen der Temperatur. Wir könnten dieses Skript auch periodisch ausführen, aber das ist nicht so effektiv. Wenn sich die Temperatur ändert vergleichen wir den aktuellen Wert mit 25 und prüfen, ob die E-Mail bereits verschickt wurde oder nicht. Wenn die E-Mail noch nicht versendet war, speichern wir, dass wir sie jetzt senden und senden sie auch. Natürlich muss der E-Mail-Adapter vorher installiert und konfiguriert worden sein. Wenn die Temperatur unter 23 Grad fällt setzen wir die Variable "emailSent" zurück, damit beim nächsten Temperaturalarm wieder eine E-Mail gesendet wird. Dazu wird die aktuelle Temperatur mit 23 verglichen und es werden keine E-Mails geschickt, solange die Temperatur um 25 Grad schwankt. Um den "falls ... sonst falls ..." Block zu erstellen klickt man auf das Zahnrad und fügt die zusätzlich benötigten Elemente dem "falls" Block hinzu. ![Getting started 3](img/getting_started_3_1_de.png) Man kann zu jedem Block einen Kommentar hinterlegen, indem man "Kommentar hinzufügen" im Kontextmenü des Blocks anklickt. Diesen Kommentar kann man später durch anklicken des Fragezeichens ansehen. ![Getting started 3](img/getting_started_3_2_de.png) Man kann größere Blöcke einklappen, um eine bessere Übersicht zu erhalten, indem man im Kontextmenü den Punkt "Block einklappen" auswählt. ![Getting started 3](img/getting_started_3_3_de.png)   Beispiel zum importieren: ```xml Send email if outside temperature is more than 25 grad Celsius. emailSent FALSE ne true javascript.0.Outside_temperature AND EQ emailSent FALSE emailSent Remember, that email was sent FALSE FALSE log myaddress@domain.com Temperature is over 25°C Temperature alert LT value 23 emailSent FALSE ```     # Blöcke ## Systemblöcke ### Debug Ausgabe ![Debug output](img/system_debug_en.png) Dieser Block macht nichts, außer eine Zeile ins log zu schreiben. Man kann ihn zum debuggen des Scripts nutzen, wie diesen hier: ![Debug output](img/system_debug_1_en.png)   Beispiel zum Importieren: ```xml Print time into log every second interval 1000 log test hh:mm:ss ``` Man kann 4 verschiedene Schweregrade für die Nachrichten definieren: - debug (dazu muss der debug-Level der Javascript Instanz aktiviert sein.) - info (default, zumindest der info log level muss in der Javascript Instanz aktiviert sein.) - warning - error (wird immer angezeigt. Die anderen Level können ignoriert werden, wenn es entsprechend in der Javascript Instanz eingestellt ist.)   ### Kommentar ![Comment](img/system_comment_en.png) Einen Kommentar zum Skript hinzufügen um es später besser verstehen zu können. Der Block macht gar nichts, es ist nur ein Kommentar.   ### Steuere State ![Control state](img/system_control_en.png) Man kann einen Zustand auf zwei verschiedene Arten schreiben: - Um etwas zu steuern und den Wert an die Hardware zu schicken (Dieser Block) - Einen neuen Wert schreiben, der nur der Information dient, z.B. Temperaturänderung ([nächster Block](#update-state))   Typische Anwendung dieses Blocks: ![Control state](img/system_control_sample1_en.png) Die Object ID wird im Dialog ausgewählt der zu sendende Wert muss angegeben werden. Abhängig vom Typ des Datenpunkts kann der Wert vom Typ [string](#string-value), [number](#number-value) oder [boolean](#ogical-value-trueflase) sein. Weitere Erklärungen gibt es [hier](https://github.com/ioBroker/ioBroker/wiki/Adapter-Development-Documentation#commands-and-statuses). Dieser Block schreibt den Befehl in den Datenpunkt mit (ack=false). Zusätzlich kann eine Verzögerung angegeben werden. Wenn die Verzögerung nicht 0 ist, wird der Zustand nicht sofort, sondern erst nach der angegebenen Zeit in Millisekunden gesetzt. Man kann alle anderen Verzögerungen für diesen Datenpunkt löschen, indem man die Checkbox anhakt. So wird in dem folgenden Beispiel der Datenpunkt "Licht" nur einmal geschaltet (nach 2 Sekunden): ![Control state](img/system_control_1_en.png)   Beispiel zum Importieren: ```xml Will be executed only once javascript.0.Light TRUE 1000 FALSE TRUE javascript.0.Light TRUE 2000 TRUE TRUE ``` Im Gegensatz zu dem vorherigen Beispiel wird der Zustand von "Licht" in dem folgenden Beispiel zweimal geschaltet(nach 1 Sekunde und nach 2 Sekunden): ![Control state](img/system_control_2_en.png) ```xml Will be executed twice javascript.0.Light TRUE 1000 FALSE TRUE javascript.0.Light TRUE 2000 FALSE FALSE ```   ### State umschalten ![Toggle state](img/system_toggle_en.png) Dieser Block ähnelt dem [Steuere-State-Block](#steuere-state), schaltet den Wert aber jeweils um — von `true` auf `false` und umgekehrt.   ### Aktualisiere State ![Update state](img/system_update_en.png) Dieser Block ist ähnlich dem [Steuere Block](#steuere-state), aber er setzt nur den aktuellen Wert. Es wird kein Befehl zum Steuern der Hardware gesendet. Typische Anwendung dieses Blocks: ![Update state](img/system_update_sample_en.png)   ### Bind States ![Bind state](img/system_bind_en.png) Dieser Block bindet zwei Zustände aneinander. Man kann das Gleiche mit diesen Blöcken erreichen: ![Bind state](img/system_bind_1_en.png) Man kann auswählen, ob der Wert nur weitergeleitet wird, wenn sich die Quelle ändert, oder bei jeder Aktualisierung.   Beispiel zum Importieren: ```xml ne javascript.0.Motion javascript.0.Light FALSE value ```   ### Write states ![Write state](img/system_write_en.png) Universal write block that can do the same as ["Update state"](#update-state) and ["Control state"](#control-state) together. But in compare with them, you can define Object ID and delay with other blocks to make your script more universal. ### Create state ![Create state](img/system_create_en.png) There are two types of variables that can be created in scripts: - local [variables](#set-variables-value) - global variables or states. Global states are visible in all scripts, but local are visible only in this current script. Global states can be used in vis, mobile and all other logic or visualisation modules, can be logged into db or whatever. This block creates global state and if the state yet exist, the command will be ignored. You can safely call this block by every start of the script. Dieser Block erzeugt globale Zustände und wenn dieser bereits existiert wird der Befehl ignoriert. Daher kann dieser Block ohne Risiko zu jedem Skriptstart verwendet werden.   Typische Anwendung dieses Blocks: ![Create state](img/system_create_sample1_en.png) ```xml Create state and subscribe on it changes myState ne javascript.0.myState log test Value of my state is value ``` Man kann den neu erzeugten State bereits in dem Block selber nutzen. Der folgende Code gibt bei der ersten Ausführung einen Fehler aus, weil 'subscribe' für "myState" das Objekt nicht finden kann: ![Create state](img/system_create_sample2_en.png) Bei der zweiten Ausführung wird keine Fehler ausgegeben, weil der Datenpunkt jetzt existiert.   ### Wert von Objekt ID ![Get value of state](img/system_get_value_en.png) Dieser Block dient dazu den Wert eines Datenpunktes auszulesen. Folgende Attribute des Datenpunktes können ausgelesen werden: - Wert - Acknowledge - Befehl = falsch oder update = wahr - Timestamp in ms seit dem 01.01.1970 (Hat den Typ "Datumsobjekt") - Letzte Änderung des Wertes in ms seit dem 01.01.1970 (Hat den Typ "Datumsobjekt") - Qualität - Quelle - Name der Instanz, die den letzten Wert geschrieben hat, wie z.B. `system.adapter.javascript.0`   Beispiel um die Zeit der letzten Änderung des Wertes auszugeben: ![Get value of state](img/system_get_value_sample_en.png) ```xml Print time of last change for myState log test Last change of myState was at hh:mm:ss lc javascript.0.myState ```   ### Objekt ID ![Get Object ID](img/system_get_id_en.png) Dieses ist ein einfacher Hilfsblock um komfortabel die Objekt-ID zum triggern des Blocks auszuwählen. Der ID Auswahldialog wird durch Anklicken von "Objekt ID" geöffnet.   Typische Anwendung dieses Blocks: ![Get Object ID](img/system_get_id_sample_en.png) ```xml Typical usage of Object ID selector ne default javascript.0.myState log Changed ```     ### Datenpunkt vorhanden Dieser Block liefert einen Boolean (`true` / `false`) und gibt zurück, ob der angegebene Datenpunkt aktuell überhaupt einen Wertdatensatz in der State-DB besitzt. Die OID wird über einen Value-Input geliefert — sie kann aus dem OID-Auswahlblock (`Objekt ID`), einer String-Variable oder jedem anderen Block kommen, der eine State-ID liefert. **Wozu das Ganze?** ioBroker speichert **Objekte** (Metadaten) und **States** (Werte) getrennt. Ein Adapter kann das *Objekt* eines Datenpunkts anlegen — die ID erscheint dann im OID-Auswahldialog —, ohne jemals einen *Wert* zu schreiben. In diesem Fall führt `getState(...)` zu einer Warnung im Log: ``` warn getState "zigbee.0.187a3efffee9e4e8.load_power" not found (3) ``` Auch eine Prüfung wie `Wert von Objekt-ID … != null` löst diese Warnung aus, weil sie bereits *während* des `getState`-Aufrufs entsteht — also bevor der Vergleich überhaupt ausgewertet wird. Der Block **Datenpunkt vorhanden** verwendet intern `existsStateAsync(...)`. Diese Funktion prüft den Cache stillschweigend und schreibt nichts ins Log, falls der State fehlt. Das ist der saubere Weg, einen `getState`-Aufruf abzusichern, wenn ein Adapter Datenpunkte vorab anlegt, aber nicht sofort befüllt (z. B. Zigbee, Tuya). Typische Anwendung — einen Lese-Vorgang gegen fehlende State-Datensätze absichern: ``` wenn [Datenpunkt vorhanden [Objekt ID "zigbee.0.…load_power"]] setze [leistung] auf [Wert von Objekt-ID "zigbee.0.…load_power"] log [leistung] ``` Der erzeugte JavaScript-Code: ```javascript if ((await existsStateAsync('zigbee.0.187a3efffee9e4e8.load_power'))) { let leistung = getState('zigbee.0.187a3efffee9e4e8.load_power').val; console.log(leistung); } ``` **Hinweis:** Mit der Adapter-Einstellung *„Beim Start nicht alle Zustände abonnieren"* lässt sich `existsState` nicht synchron auswerten. Der Block erzeugt deshalb die asynchrone Form (`await existsStateAsync(...)`), die in beiden Modi korrekt funktioniert.   ## Aktionsblöcke ### Exec - Kommando ![Exec - execute](img/action_exec_en.png) Dieser Block führt das eingegebene Kommando im System aus, so als ob man es auf der Kommandozeile via SSH eingegeben hätte. Der Befehl wird mit den rechten des Users ausgeführt unter dem ioBroker gestartet wurde. Wenn keine Ausgabe gewünscht ist, kann diese unterdrückt werden: ![Exec - execute](img/action_exec_2_en.png) Wenn eine Ausgabe erfolgen soll: ![Exec - execute](img/action_exec_1_en.png)   ```xml Execute some system command TRUE ls /opt/ log result result ```   Zur Analyse der Ausgabe werden 3 besondere Variable erzeugt: - Ergebnis, enthält die reguläre Ausgabe auf die Konsole (z.B. für den Befehl "ls /opt" lautet die Ausgabe "iobroker nodejs") - Fehlerobjekt, wenn der Befehl vom JavaScript Modul nicht ausgeführt werden konnte - stderr, die Fehlerausgabe des ausgeführten Programms Zusätzlich wird die selbe Ausgabe auch im Log erscheinen, wenn der loglevel nicht auf 'none' steht.   ### request URL ![request URL](img/action_request_en.png) Ruft eine URL auf und gibt das Ergebnis zurück.   Beispiel: ![request URL](img/action_request_1_en.png) Zur Analyse der Ausgabe werden 3 besondere Variable erzeugt: - Ergebnis, enthält den body der angeforderten Seite - Fehler, enthält eine Fehlerbeschreibung - Antwort (nur für Fortgeschrittene), Spezialobjekt vom Typ [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) Wenn keine Ausgabe gewünscht ist, kann diese unterdrückt werden. Dazu die Option "mit Ergebnis" abhaken.     ## SendTo Blöcke ### Send to telegram ![Send to telegram](img/sendto_telegram_en.png) Dieser Block dient dazu eine Nachricht über telegram mit Hilfe des telegram-Adapters zu senden. Selbstverständlich muss dafür vorher der telegram-Adapter installiert und konfiguriert werden. Um die Nachricht über eine bestimmte Instanz zu senden, muss die gewünschte Instanz des Adapters (üblicherweise telegram.0) ausgewählt werden, ansonsten wird die Nachricht über alle verfügbaren Instanzen verschickt. Das Feld *Meldung* ist zwingend notwendig und der dort enthaltene Text wird exakt so an den Klienten gesendet. User name ID is optional and this is ID from [telegram](https://core.telegram.org/bots/api#user) (Unique identifier for user or bot). Additionally, if the log level is not "none", the same message will be sent to log.   ### Send to SayIt ![Send to SayIt](img/sendto_sayit_en.png) This block is used to send text to `sayit` instance to pronounce this text. Of course the `sayit` adapter must be installed and configured. To send message to some specific instance, you should select the installed adapter instance (Normally `sayit.0`), elsewise message will be sent to all existing instances. Property *message* is mandatory and exactly this text will be pronounced. You must check the language property. This will be used for text2speech engine. Volume is optional (normally from 0 to 100). Additionally, if the log level is not "none", the same message will be sent to log.   ### Send to pushover ![Send to pushover](img/sendto_pushover_en.png) This block is used to send text to pushover client. You can read about pushover driver [here](https://github.com/ioBroker/ioBroker.pushover). Of course the pushover adapter must be installed and configured. To send message to some specific instance, you should select the installed adapter instance (Normally pushover.0), elsewise message will be sent to all existing instances. Property *message* is mandatory and exactly this text will be sent to client. All other properties are optional, and you can read bout them [here](https://pushover.net/api): - *device ID* - your user's device name to send the message directly to that device, rather than all the user's devices (multiple devices may be separated by a comma) - *title* - your message's title, otherwise your app's name is used - *URL* - a supplementary URL to show with your message - *URL title* - a title for your supplementary URL, otherwise just the URL is shown - *priority* - send as -2 to generate no notification/alert, -1 to always send as a quiet notification, 1 to display as high-priority and bypass the user's quiet hours, or 2 to also require confirmation from the user - *time in ms* - a Unix timestamp of your message's date and time to display to the user, rather than the time your message is received by our API - *sound* - the name of one of the sounds supported by device clients to override the user's default sound choice Additionally, if the log level is not "none", the same message will be sent to log.   ### Send email ![Send to email](img/sendto_email_en.png) This block is used to send text as email. Of course the email adapter must be installed, configured and tested. To send message to some specific instance, you should select the installed adapter instance (Normally email.0), elsewise message will be sent to all existing instances. Property *text* is mandatory and exactly this text will be sent to client. Of course the destination (*to*) must be filled with valid email address. You can attach up to files (normally images) to email. To use images in the text, you must change format to HTML (check "Send as HTML" option) and text could look like: ```html

Embedded image 1:

Embedded image 2:

``` You can refer to files as ``````. "file1" and "file2" are reserved IDs and cannot be changed. "file name" must consist full path to image on disk. ![Send to email](img/sendto_email_1_en.png) ```xml FALSE user@myemail.com <p>Embedded image 1: <img src='cid:file1'/></p> From Sweet Home /opt/video/imageCam.png ``` Additionally, if the log level is not "none", the same message will be sent to log.   ### Custom sendTo block ![Custom sendTo block](img/sendto_custom_en.png) This is just a help block to send internal system message (sendTo) to any adapter. Of course, you can use custom function block to do anything crazy, and to send messages too. You can define your own parameters for sendTo command: ![Custom sendTo block](img/sendto_custom_1_en.png) Read more [here](https://github.com/ioBroker/ioBroker.javascript#sendto) about "sendTo". Example how to send SQL query to sql adapter: ![Custom sendTo block](img/sendto_custom_2_en.png) ```xml --> Send query to SQL adapter sql.0 query TRUE log SELECT * FROM datapoints log test result JSON.stringify cmV0dXJuIEpTT04uc3RyaW5naWZ5KG9iaik7 Describe this function... ``` If you use only one parameter with empty name, so no structure will be created, like here: ```javascript var obj, result; /** * Describe this function... */ function JSON_stringify(obj) { return JSON.stringify(obj); } // Send query to SQL adapter sendTo("sql.0", "query", 'SELECT * FROM datapoints', function (result) { console.log((JSON_stringify(result))); }); console.log("sql.0: " + ""); ``` Or how to request history from SQL adapter: ![Custom sendTo block](img/sendto_custom_3_en.png) ```XML Get history from SQL adapter end object sql.0 getHistory TRUE system.adapter.admin.0.memRss {start: end - 3600000, end: end, aggregate: "minmax"} log test result JSON.stringify cmV0dXJuIEpTT04uc3RyaW5naWZ5KG9iaik7 JSON.stringify object ``` Generated javascript code: ```javascript var obj, end, result; /** * JSON.stringify object */ function JSON_stringify(obj) { return JSON.stringify(obj); } // Get history from SQL adapter end = (new Date().getTime()); sendTo("sql.0", "getHistory", { "id": 'system.adapter.admin.0.memRss', "options": {start: end - 3600000, end: end, aggregate: "minmax"} }, function (result) { console.log((JSON_stringify(result))); }); ``` If you start value with "{" it will be interpreted as JSON string. Use double quotes in string.   ### An anderes Skript senden ![An anderes Skript senden](img/sendto_otherscript_1_en.png) Mit diesem Block kannst du eine Nachricht an ein anderes Skript senden. Die Nachricht kann dort durch den Block [Ereignis – Nachricht empfangen](#trigger-on-script-event) verarbeitet werden.   ## Date and Time blocks ### Time comparison ![Time comparision](img/datetime_compare_ex_en.png) If used operator "between" or "not between", the block looks like this: ![Time comparision](img/datetime_compare_ex_1_en.png) You can specify a time, which must be compared. Block expects the time as "Date object". ![Time comparision](img/datetime_compare_ex_2_en.png) There are following compare modes: - less than, check if actual time less than specified time. - equal to or less than - greater than - equal to or greater than - equal to - between, check if the time between some day times. - E.g. if time must be between 12:00 and 20:00. It will be checked if actual time grater or equal than 12:00 and less than 20:00. 20:00 will return false. - or for instance between 21:00 and 8:00. In the last case it will be checked if time greater or equal to 21:00 or less than 8:00. - not between, if the time is not in the given period of the daytime. If the time less than start and greater or equal to end. (if start time is greater than end time, it will be checked if the time greater or equal than end and smaller than start) Following time formats are valid: - YYYY-MM-DD hh:mm:ss - YYYY-MM-DD hh:mm - hh:mm:ss - hh:mm   ### Actual time comparision ![Actual time comparision](img/datetime_compare_en.png) This block is used to compare the day time with actual time. It has the same logic as [Time comparision](#time-comparision), but limits cannot be a blocks, and it compares only actual time. (for compatibility with old versions)   ### Get actual time im specific format ![Get actual time im specific format](img/datetime_actualtime_en.png) Returns the actual time in some specified format. Following formats are supported: - milliseconds - returns only milliseconds of current second from 0 to 999 (not epoch milliseconds). To get epoch milliseconds use "Date object"; - seconds - returns only seconds of current minute from 0 to 59, - seconds in day - returns number of seconds from start of the day (0 to 24 * 3600 - 1), - minutes - returns minutes of current hour from 0 to 59, - minutes in day - returns number of minutes from the day start (0 to 24 * 60 - 1), - hours - returns hours of current day from 0 to 23, - day of month - get day of month from 1 to 31, - month as number - get month as number from 1 to 12, - month as text - get month as text. Language must be specified. - month as short text - get month as text: Jan, Feb, Mar, Apr, May, June, July, Aug, Sept, Oct, Nov, Dec. Language must be specified. - short year - Year from 0 to 99, e.g. for 2016 the result will be 16. - full year - Full year: 2016 - week day text - Get day of week as text. - short week day - Get day of week as short text: Su, Mo, Tu, We, Th, Fr, Sa. - week day as number - Day of week as number from 1 (monday) to 7 (sunday). - custom format - You can specify your own [format](https://github.com/ioBroker/ioBroker.javascript#formatdate). - Date object - Returns date and time as number of milliseconds from start of epoch (1970.1.1 00:00:00.000Z GMT). This is always GMT. - yyyy.mm.dd - 2016.09.14 - yyyy/mm/dd - 2016/09/14 - yy.mm.dd - 16.09.14 - yy/mm/dd - 16/09/14 - dd.mm.yyyy - 14.09.2016 - dd/mm/yyyy - 14/09/2016 - dd.mm.yy - 14.09.16 - dd/mm/yy - 14/09/16 - mm/dd/yyyy - 09/14/2016 - mm/dd/yy - 09/14/16 - dd.mm. - 14.09. - dd/mm - 14/09 - mm.dd - 09.14 - mm/dd - 09/14 - hh:mm - 12:00 - hh:mm:ss - 12:00:00 - hh:mm:ss.sss - 12:00:00.000   ### Get time of astro events for today ![Get time of astro events for today](img/datetime_astro_en.png) Returns the time in current day of some specific astrological event. The attribute "offset" is the offset in minutes. It can be negative too, to define time before astro event. Following values can be used as attribute in astro-function: - sunrise: sunrise (top edge of the sun appears on the horizon) - sunriseEnd: sunrise ends (bottom edge of the sun touches the horizon) - goldenHourEnd: morning golden hour (soft light, best time for photography) ends - solarNoon: solar noon (sun is in the highest position) - goldenHour: evening golden hour starts - sunsetStart: sunset starts (bottom edge of the sun touches the horizon) - sunset: sunset (sun disappears below the horizon, evening civil twilight starts) - dusk: dusk (evening nautical twilight starts) - nauticalDusk: nautical dusk (evening astronomical twilight starts) - night: night starts (dark enough for astronomical observations) - nightEnd: night ends (morning astronomical twilight starts) - nauticalDawn: nautical dawn (morning nautical twilight starts) - dawn: dawn (morning nautical twilight ends, morning civil twilight starts) - nadir: nadir (the darkest moment of the night, sun is in the lowest position) The return value has type "Date Object", what is just the number of milliseconds from 1970.01.01. **Note:** to use "astro"-function the "latitude" and "longitude" must be defined in javascript adapter settings.     ## Convert blocks Sometimes it is required to convert value into other type. Following blocks allow converting value into specific types. ### Convert to number ![Convert to number](img/convert_tonumber_en.png) Convert value to number (float).   ### Convert to boolean ![Convert to boolean](img/convert_toboolean_en.png) Convert value to boolean (true or false).   ### Convert to string ![Convert to string](img/convert_tostring_en.png) Convert value to string.   ### Get type of variable ![Get type of variable](img/convert_typeof_en.png) Get type of value. Type can be: boolean, number, string, object.   ### Convert to date/time object ![Convert to date/time object](img/convert_todate_en.png) Convert value to "Date object". Read [here](#get-actual-time-im-specific-format), what the "Date object" is.   ### Convert date/time object to string ![Convert to boolean](img/convert_fromtime_en.png) Convert "Date object" into string. It has the same format options as [Get actual time im specific format](#get-actual-time-im-specific-format).   ### Convert JSON to object ![Convert JSON to object](img/convert_json2object_en.png) Convert JSON string into javascript object. If an error occurs, the empty object will be returned. (only for experts)   ### Convert object to JSON ![Convert object to JSON](img/convert_object2json_en.png) Convert Javascript object to JSON string. If prettify option is selected the result string looks like: ```json { "a": 1, "b": 2 } ``` if not: ``` {"a": 1, "b": 2} ``` ### Convert by JSONata Expression ![Convert by JSONata Expression](img/convert_by_jsonata_en.png) Convert Javascript object by JSONata expression. You can read more about it here: [https://jsonata.org/](https://jsonata.org/) Example payload: ``` {"example": [{"value": 4},{"value": 7},{"value": 13}]} ``` Result: ``` [{"value": 4},{"value": 7},{"value": 13}] 24 4 13 ``` ## Trigger ### Trigger on states change ![Trigger on states change](img/trigger_trigger_ex_en.png) This block executes some action if state of given objects changed or updated. This is the main block to build interactions between different states and accordingly systems. With this block you can bind different states together or send message or email on value change. Typical usage of block: ![Trigger on states change](img/trigger_trigger_ex_1_en.png) ```xml Switch light on if motion detected ne javascript.0.Motion javascript.0.Light FALSE TRUE ``` You can define as many ObjectIDs as you want via extension dialog: ![Trigger on states change](img/trigger_trigger_ex_2_en.png) If only one object ID is used so special variables are available in the statement block: - value - actual value of state - oldValue - old value of state ![Trigger on states change](img/trigger_trigger_ex_3_en.png) ```xml ne javascript.0.Motion log test Actual value is value Old value was oldValue ``` elsewise if more than one object ID is used for trigger, you can access value and old value via [Trigger info](#trigger-info).   ### Trigger on state change ![Trigger on state change](img/trigger_trigger_en.png) This is the same block as "Trigger on states change", but with no possibility to use multiple object IDs for triggering (for versions compatibility).   ### Trigger info ![Trigger info](img/trigger_object_id_en.png) Get information about value, timestamp or ID of the state, that triggered the trigger. This block can be used only inside of ["Trigger on states change"](#trigger-on-states-change) or ["Trigger on state change"](#trigger-on-state-change) blocks. Following information can be accessed: - object ID - ID of state, that fired the trigger - name - name of state from common.name - description - description of state from common.desc - channel ID - ID of channel to which belongs the state. If not channel there, it will be null - channel name - name of channel to which belongs the state. If not channel there, it will be null - device ID - ID of device to which belongs the state. If not channel there, it will be null - device name - name of device to which belongs the state. If not channel there, it will be null - state value - actual value of fired state - state timestamp - actual timestamp as Date object - state quality - actual quality code of value - origin of value - name of instance that cause the change - is command or update - is it command (ack=false) or update (ack=true) - last change of state - timestamp of last change of this value - previous value - previous value of this state, before the trigger fired - previous timestamp - previous timestamp of this state, before the trigger fired - previous quality - previous quality of this state, before the trigger fired - previous origin - previous origin of this state, before the trigger fired - previous command or update - previous type of this value, before the trigger fired - previous last change - previous "last changed value" of this state, before the trigger fired Typical usage: ![Trigger info](img/trigger_object_id_1_en.png) ```xml ne javascript.0.Motion log test Actual value is state.val Old value was oldState.val ```   ### Schedule ![Schedule](img/trigger_schedule_en.png) This is second main block for automation after ["Trigger on states change"](#trigger-on-states-change). This block lets execute some actions periodically. The definition of schedule rule will be done in very well documented CRON [format](https://en.wikipedia.org/wiki/Cron). With extension, that seconds can be defined too. If seconds should be used they must be defined as very first parameter of CRON rule and rule will have 6 parts. Generally CRON rule consist of 5 or 6 parts: - seconds rules (optional) - minutes rules - hours rules - day of month rules - month's rules - and day of week rules. For every part following formats are allowed: - \* - fire every (second, minute, hour, ...) - X (e.g. 5) - fire only in this second, minute, hour... - from-to (e.g 1-9) - fire only in this interval - \*/X (e.g. \*/5) - fire every X seconds, minutes... In case of "\*/5" for hours the trigger will fire on 0, 5, 10, 15 and on 20 hours. - numbers and intervals can be combined by comma (e.g 1,3,4-6). Do not make spaces between numbers, because space is delimiter for rule's parts. \*/10 \* \* \* 6,7 - fire every 10 minutes on saturday and sunday. \*/30 \* \* \* \* \* - fire every 30 seconds. ``` ┌───────────── min (0 - 59) │ ┌────────────── hour (0 - 23) │ │ ┌─────────────── day of month (1 - 31) │ │ │ ┌──────────────── month (1 - 12) │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to Saturday; 7 is also Sunday) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ * * * * * schedule ``` or if seconds used: ``` ┌───────────── seconds (0 - 59) │ ┌───────────── min (0 - 59) │ │ ┌────────────── hour (0 - 23) │ │ │ ┌─────────────── day of month (1 - 31) │ │ │ │ ┌──────────────── month (1 - 12) │ │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to Saturday; 7 is also Sunday) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ * * * * * * schedule ``` But there is a good help for you to build such a rules. By clicking on rule the CRON dialog will be opened and you can specify by mouse your rule. ![Schedule](img/trigger_schedule_1_en.png)   ### Trigger on astro event ![Schedule](img/trigger_astro_en.png) Execute some action on astrological event. Following events are possible: - sunrise: sunrise (top edge of the sun appears on the horizon) - sunriseEnd: sunrise ends (bottom edge of the sun touches the horizon) - goldenHourEnd: morning golden hour (soft light, best time for photography) ends - solarNoon: solar noon (sun is in the highest position) - goldenHour: evening golden hour starts - sunsetStart: sunset starts (bottom edge of the sun touches the horizon) - sunset: sunset (sun disappears below the horizon, evening civil twilight starts) - dusk: dusk (evening nautical twilight starts) - nauticalDusk: nautical dusk (evening astronomical twilight starts) - night: night starts (dark enough for astronomical observations) - nightEnd: night ends (morning astronomical twilight starts) - nauticalDawn: nautical dawn (morning nautical twilight starts) - dawn: dawn (morning nautical twilight ends, morning civil twilight starts) - nadir: nadir (the darkest moment of the night, sun is in the lowest position) **Note:** to use "astro"-function the "latitude" and "longitude" must be defined in javascript adapter settings. Additionally, you can set the offset in minutes to astrological event, e.g. to fire the trigger 1 hour before down: ![Schedule](img/trigger_astro_1_en.png) As you can see the offset can be negative too to specify time before astrological events.   ### Named schedule ![Schedule](img/trigger_schedule_ex_en.png) This block is the same as [Schedule](#schedule), but with possibility to set CRON rule by string and with possibility to stop the schedule. You can specify unique name of this schedule block and then later to clear it with [Clear schedule](#clear-schedule). Here is an example of configurable alarm clock: ![Schedule](img/trigger_schedule_ex_1_en.png) ```xml Configurable alarm. Set time as: hh:mm alarmTime ne javascript.0.alarmTime alarm alarm * * * * * state.val log Wake up! time to CRON dmFyIHBhcnRzID0gdGltZS5zcGxpdCgnOicpOwovLyBpZiBpdCBpcyBDUk9OCmlmIChwYXJ0cy5sZW5ndGggPT09IDEpIHJldHVybiB0aW1lOwpyZXR1cm4gcGFydHNbMV0gKyAnICcgKyBwYXJ0c1swXSArICcgKiAqIConOw== Describe this function... ```   ### Clear schedule ![Schedule](img/trigger_cron_clear_en.png) With this function block you can clear named schedule. If you define named one more time without clearing it, the old one will still active. See an example in [Named schedule](#named-schedule)   ### CRON dialog ![Schedule](img/trigger_cron_input_en.png) Create CRON rule from dialog. This block can be connected with [Named schedule](#named-schedule). ![Schedule](img/trigger_cron_input_1_en.png) ```xml Every 0th minute every hour schedule * * * * * 0 * * * * log It is exactly It is exactly h o'clock ```   ### CRON rule ![Schedule](img/trigger_cron_rule_en.png) Combine CRON rule from different parts. You can display rule as block or as line: ![Schedule](img/trigger_cron_rule_1_en.png) With additional parameter "with seconds" you can specify seconds for CRON rule too ![Schedule](img/trigger_cron_rule_2_en.png) This block can be used (like [CRON dialog](#cron-dialog)) only with [Named schedule](#named-schedule) block. ### Trigger auf Dateiaktualisierung ![onFile](img/trigger_onFile_de.png) Sie können Dateiaktualisierungen abonnieren und einige Aktionen ausführen. Z.B. hier wird der Inhalt von `vis´ bei jeder Projektaktualisierung ausgedruckt: ``` data TRUE vis.0 main/* log test data ``` **Wichtig**: Diese Funktionalität ist nur mit js-controller@4.1.x oder neuer verfügbar. ### Ereignis bei Dateiaktualisierung abbrechen ![onFile](img/trigger_offFile_de.png) Mit diesem Block können Sie Veranstaltungen per Dateiaktualisierung abbestellen. **Wichtig**: Diese Funktionalität ist nur mit js-controller@4.1.x oder neuer verfügbar. ### Trigger auf Skript-Ereignis ![Trigger auf Skript-Ereignis](img/trigger_onScript_en.png) Mit diesem Block kannst du dich auf skriptübergreifende Ereignisse abonnieren und beim Empfang eine Aktion ausführen. ## Timeouts ### Warten/Pause Mit diesem einfachen Block lässt sich die Ausführung von Blöcken pausieren. Achtung: Wird `pause` innerhalb einer Block-Kette verwendet, werden alle in diesem Skript darunter liegenden Blöcke ebenfalls verzögert: ![Beispiel 1](img/wait1.png) Generierter Code: ``` console.log('"Independent" block'); // Wird nicht verzögert console.log('Before pause'); await wait(5000); console.log('After pause'); ``` Log-Ausgabe: ``` 15:48:21.807 info javascript.0 (7304) script.js.Skript_1: "Independent" block 15:48:21.807 info javascript.0 (7304) script.js.Skript_1: Before pause 15:48:21.807 info javascript.0 (7304) script.js.Skript_1: registered 0 subscriptions and 0 schedules 15:48:26.810 info javascript.0 (7304) script.js.Skript_1: After pause ``` ![Beispiel 2](img/wait2.png) Generierter Code: ``` console.log('Before pause'); await wait(5000); console.log('After pause'); console.log('"Independent" block'); // Wird um 5 Sekunden verzögert ``` Ausgabe: ``` 15:52:03.289 info javascript.0 (7304) script.js.Skript_1: Before pause 15:52:03.290 info javascript.0 (7304) script.js.Skript_1: registered 0 subscriptions and 0 schedules 15:52:08.296 info javascript.0 (7304) script.js.Skript_1: After pause 15:52:08.297 info javascript.0 (7304) script.js.Skript_1: "Independent" block ``` ### Delayed execution ![Delayed execution](img/timeouts_timeout_en.png) With this block you can execute other blocks delayed by some time specified in milliseconds. if you know Javascript it is the same function as setTimeout. There is no "pause" in blockly, but you can use this block to simulate pause. If you place all blocks, that must be executed after the pause you will achieve the same effect as with pause. An additional feature is to set the interval by using a variable, just replace the "ms" with a predefined variable: ![Execution by interval variable](img/Timer_variable_en.PNG) Every delayed execution can have unique name. It can be canceled by other block. [Clear delayed execution](#clear-delayed-execution) ![Delayed execution](img/timeouts_timeout_1_en.png) ```xml log Make a pause 5 seconds timeout 5000 log After pause ```   ### Clear delayed execution ![Clear delayed execution](img/timeouts_timeout_clear_en.png) This block is used to cancel running delay by name. Typical usage is simulation of motion detection scenario. By first motion the light should go on and after the last motion after 30 seconds the light should go off. ![Clear delayed execution](img/timeouts_timeout_clear_1_en.png) ```xml ne node-red.0.javascript.0.Motion EQ value TRUE log Motion detected Switch light ON javascript.0.Light FALSE TRUE Stop timer, even if it not running lightOff lightOff 5000 log Light OFF javascript.0.Light FALSE FALSE ```   ### Execution by interval ![Execution by interval](img/timeouts_interval_en.png) This block allows you to execute some action periodically. Of course there is a CRON block, but CRON block has the smallest interval one second. This block can execute actions in milliseconds periods. If you set the interval too small (under 100ms) it can be, that intervals will be bigger. Similar to timeout block you can set unique interval name too.   ### Stop execution by interval ![Stop execution by interval](img/timeouts_interval_clear_en.png) With the help of this block you can cancel periodically execution of interval block by its name.     ## Logic ### If else block ### Comparision block ### Logical AND/OR block ### Negation block ### Logical value TRUE/FALSE ### null block ### Test block     ## Loops ### Repeat N times ### Repeat while ### Count ### For each ### Break out of loop     ## Math ### Number value ### Arithmetical operations +-*/^ ### Square root, Abs, -, ln, log10, e^, 10^ ### sin, cos, tan, asin, acos, atan ### Math constants: pi, e, phi, sqrt(2), sqrt(1/2), infinity ### Is even, odd, prime, whole, positive, negative, divisibly by ### Modify variably by value (plus or minus) ### Round, floor, ceil value ### Operations on the list of values: sum, min, max, average, median, modes, deviation, random item ### Modulus ### Limit some value by min and max ### Random value from 0 to 1 ### Random value between min and max     ## Text ### String value ### Concatenate strings ### Append string to variable ### Length of string ### Is string empty ### Find position in string ### Get symbol in string on specific position ### Get substring ### Convert to upper case or to lower case ### Trim string     ## Lists ### Create empty list ### Create list with values ### Create list with same value N times ### Get length of list ### Is list empty ### Find position of item in list ### Get item in list ### Set item in list ### Get sublist of list ### Convert text to list and vice versa     ## Colour ### Colour value ### Random colour ### RGB colour ### Mix colours     ## Variables ### Set variable's value ![Set variable's value](img/variables_set_en.png) To use this block you should understand basic programming rules: how to use variables. With this block you can write into global (visible everywhere in this script) variable and use it to store some values. If variable does not exist, it will be declared automatically. This block can create new variable or use existing one. ![Set variable's value](img/variables_set_1_en.png) This code: ![Set variable's value](img/variables_set_2_en.png) ```xml item 0 ``` does only this: ```javascript var item; item = 0; ```   ### Get variable's value ![Get variable's value](img/variables_get_en.png) This block gets the value of variable. You can create a new one or use existing one. ![Get variable's value](img/variables_get_1_en.png) There is one exception with trigger blocks [Trigger on states change](#trigger-on-states-change) and [Trigger on state change](#trigger-on-state-change). Inside these blocks variable "value" yet exist, but anyway to read their values you must rename variable into value and then use it. ![Get variable's value](img/variables_get_2_en.png)     ## Funktionen ### Funktion aus Blöcken erstellen (ohne Rückgabewert) ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_en.png) Mit diesem Block kannst du wiederkehrende Block-Sequenzen zu einer Funktion zusammenfassen und diese Funktion anschließend an beliebigen Stellen im aktuellen Blockly-Skript verwenden. Hier ein Beispiel für eine Funktion, die nur die aktuelle Uhrzeit ins Log schreibt: ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_2_en.png) ```xml Print current time printTime Describe this function... log test hh:mm:ss.sss ``` Nachdem die Funktion erstellt wurde, kann sie folgendermaßen verwendet werden: ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_3_en.png) ```xml interval 1000 ``` Die neu erstellte Funktion erscheint im Block-Menü: ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_4_en.png) Zusätzlich lassen sich über den Konfigurationsdialog Argumente für die Funktion festlegen. Im selben Dialog können auch die Namen der Argumente bearbeitet werden. ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_1_en.png) Hier ein Beispiel für eine Funktion, die die Summe des ersten und des zweiten Arguments ausgibt: ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_5_en.png) ```xml Print sum of a and b printSum Describe this function... log test ADD 1 a 1 b ``` Die Argumente erscheinen im Variablen-Menü: ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_6_en.png) Die Funktion lässt sich dann so verwenden: ![Funktion aus Blöcken erstellen ohne Rückgabewert](img/functions_function_7_en.png) ```xml 5 6 ``` ### Funktion aus Blöcken erstellen (mit Rückgabewert) ![Funktion aus Blöcken erstellen mit Rückgabewert](img/functions_function_ret_en.png) Dieser Block funktioniert wie der vorherige, kann aber zusätzlich ein Ergebnis zurückgeben, das anschließend in anderen Blöcken weiterverwendet werden kann. ![Funktion aus Blöcken erstellen mit Rückgabewert](img/functions_function_ret_2_en.png) ```xml do something Return sum of a and b ADD 1 a 1 b ``` Die Verwendung ist analog zu den anderen Funktionsblöcken: ![Funktion aus Blöcken erstellen mit Rückgabewert](img/functions_function_ret_3_en.png) ```xml log test 5 6 sum Return sum of a and b ADD 1 a 1 b ``` Für jede Funktion lässt sich ein Kommentar bzw. eine Beschreibung hinzufügen. ![Funktion aus Blöcken erstellen mit Rückgabewert](img/functions_function_ret_1_en.png) Im Funktionsblock kann zusätzlich ein spezielles Return-Element verwendet werden: ![Funktion aus Blöcken erstellen mit Rückgabewert](img/functions_function_ret_4_en.png) ![Funktion aus Blöcken erstellen mit Rückgabewert](img/functions_function_ret_5_en.png) ```xml log test 5 log test wd numberToDay Return sum of a and b EQ day 0 Sunday EQ day 1 Monday EQ day 2 Tuesday EQ day 3 Wednesday EQ day 4 Thursday EQ day 5 Friday EQ day 6 Saturday EQ day 7 Sunday Invalid day ``` ### Wert in Funktion zurückgeben ![Wert in Funktion zurückgeben](img/functions_return_en.png) Siehe Verwendung dieses Blocks unter [Funktion aus Blöcken erstellen (mit Rückgabewert)](#funktion-aus-blöcken-erstellen-mit-rückgabewert). Dieser Block ist nur dort verwendbar und dient dazu, mitten in der Funktion einen Wert zurückzugeben. ### Eigene Funktion erstellen (ohne Rückgabewert) ![Eigene Funktion erstellen ohne Rückgabewert](img/functions_function_ex_en.png) Manchmal reichen die vorhandenen Blöcke nicht aus, um eine bestimmte Aufgabe zu lösen. Mit diesem Block kannst du einen eigenen Block als Funktion definieren, der Parameter entgegennimmt und beliebige Aktionen ausführt. Um eine solche Funktion zu schreiben, sind JavaScript-Kenntnisse nötig. Innerhalb der Funktion stehen alle Funktionen zur Verfügung, die auch im normalen JavaScript-Skript verfügbar sind. Um den Code zu schreiben, klickst du auf das `...` am Ende des Blocks, woraufhin sich der Editor-Dialog öffnet. ![Eigene Funktion erstellen ohne Rückgabewert](img/functions_function_ex_1_en.png) Ansonsten ist die Verwendung dieses Blocks analog zu den Standard-Funktionsblöcken, etwa [Funktion aus Blöcken erstellen (mit Rückgabewert)](#funktion-aus-blöcken-erstellen-mit-rückgabewert) oder [Funktion aus Blöcken erstellen (ohne Rückgabewert)](#funktion-aus-blöcken-erstellen-ohne-rückgabewert). ### Eigene Funktion erstellen (mit Rückgabewert) ![Eigene Funktion erstellen mit Rückgabewert](img/functions_function_ex_ret_en.png) Dieser eigene Funktionsblock kann Werte zurückgeben. Um ein Ergebnis aus der Funktion zurückzugeben, schreibst du: ``` return 'dein Ergebnis'; ``` Wie hier: ![Eigene Funktion erstellen mit Rückgabewert](img/functions_function_ex_ret_1_en.png) ```xml sum cmV0dXJuIGEgKyBiOw== Summarise a and b log test 5 6 ``` ### Funktion aufrufen ![Funktion aufrufen](img/functions_call_ex_en.png) ![Funktion aufrufen](img/functions_call_ex_ret_en.png) Für jede angelegte Funktion erscheint im Menü ein zusätzlicher Block mit dem Namen dieser Funktion. Du kannst ihn wie jeden anderen Block in deinen Skripten verwenden. ## AI Chat für Blockly Das AI-Chat-Panel ist jetzt auch für Blockly-Scripts verfügbar. Klicke auf den AI-Button (Zauberstab-Symbol) in der Toolbar, um das Chat-Panel neben dem Blockly-Editor zu öffnen. ### Funktionsumfang - **Chat-Modus**: Stelle Fragen zu deinem Blockly-Script. Die KI sieht den generierten JavaScript-Code als Kontext. - **Code-Modus**: Beschreibe eine Automatisierungsaufgabe und die KI generiert Blockly-XML-Blöcke in einem Zwei-Schritt-Prozess (Plan, dann Blöcke). - **Visuelle Vorschau**: KI-generierte Blöcke werden als grafische Blockly-Vorschau direkt im Chat dargestellt statt als rohes XML. - **Blöcke einfügen**: Klicke auf "Blöcke einfügen", um die KI-generierten Blöcke in deinen Blockly-Workspace einzufügen. - **Diff-Ansicht**: Klicke auf "Als Diff anzeigen" für einen Side-by-Side-Vergleich deiner aktuellen Blöcke mit den KI-vorgeschlagenen Blöcken, mit Akzeptieren/Ablehnen-Buttons. ### Unterstützte Block-Typen Die KI kann folgende ioBroker-Blockly-Blocktypen generieren: - **on_ext** – Trigger (auf Zustandsänderungen reagieren) - **schedule** – Cron-basierte Zeitpläne - **control** – Zustand setzen (setState) - **get_value** – Zustandswert lesen (getState) - **debug** – Log-Ausgabe - **sendto_custom** – Nachrichten senden (z.B. Telegram) - **timeouts_settimeout** – Verzögerte Aktionen - **controls_if** – Wenn/Dann-Bedingungen - **logic_compare** – Vergleiche (EQ, NEQ, LT, GT, etc.) - **math_number**, **text**, **logic_boolean** – Wert-Blöcke ### Tipps - Verwende den **Code-Modus** zum Generieren neuer Blöcke aus einer Aufgabenbeschreibung. - Verwende den **Chat-Modus** (oder Agent-Modus) für Fragen zu bestehenden Blöcken. - Die KI funktioniert am besten, wenn du deine Automatisierung in einfacher Sprache beschreibst, z.B. "Schalte das Wohnzimmerlicht ein, wenn der Bewegungssensor auslöst". - Du kannst `@geräte` verwenden, um deine Smart-Home-Geräte in den Kontext einzubeziehen.