# Contents - [Description](#description) - [Getting started](#getting-started) - [Sample 1](#sample-1) - [Sample 2](#sample-2) - [Sample 3](#sample-3) - [Blocks](#blocks) - [System blocks](#system-blocks) - [Debug output](#debug-output) - [Comment](#comment) - [Control state](#control-state) - [Update state](#update-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) - [Actions Blocks](#actions-blocks) - [Exec - execute](#exec---execute) - [request URL](#request-url) - [Send to Blocks](#send-to-blocks) - [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) - [Date and Time blocks](#date-and-time-blocks) - [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) - [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) - [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) # Description Blockly is a visual editor that allows users to write programs by adding blocks together. It is designed for people with no prior experience with computer programming. # Getting started ## Sample 1 **Control state on change of some other state** ![Getting started 1](img/getting_started_1_en.png) This is the classical rule to switch something ON or OFF on other event. Here the light will be switched on or off if the motion was detected or motion detector sends IDLE state. First of all insert block "Triggers=>Event: if object". Select object ID to use this state as trigger for rule. Add to trigger other block - "System=>Control" and select in dialog other state that must be controlled by event. Insert into control block the "System=>Get value of state" block and select in dialog the "Motion" object to write the value of this state into "Light"*[]: There is a special variable **value"" in trigger block. It is always defined there and you can use this variable for your need. It consist actual value of triggered state and you can create simpler rule by using "Variable=>item" block and renaming it into "value". ![Getting started 1](img/getting_started_1_2_en.png) ```xml Switch light ON or OFF it motion detected or IDLE ne javascript.0.Motion javascript.0.Light FALSE val javascript.0.Motion ``` ## Sample 2 **Switch light on by motion and switch off in 10 minutes if no motion detected.** ![Getting started 2](img/getting_started_2_en.png) If state "Motion" was updated with value true do: - switch "Light" on - start the delayed set in 10 minutes to switch "Light" off and clear all the delayed sets for this state You can notice, that the flag "clear running" is set by last command. This clears any running timers for this state and the timer will be started anew. ```xml 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 ``` ## Sample 3 **Send email if outside temperature is more than 25 grad Celsius.** ![Getting started 3](img/getting_started_3_en.png) Explanation: First we must to define the variable to remember if the email yet sent for actual temperature alert or not and fill it with "false". Then we subscribe on changes of temperature. We can execute our rule periodically, but is is not so effective. If temperature was changed we compare its value with 25 and check if the email yet sent or not. If email is not sent, we remember, that email sent and send the email. Of course email adapter must be installed and configured before. If the temperature less than 23 grad, reset "emailSent" flag to send email by next temperature alert. We compare temperature with 23 to do not sent emails every time if temperature fluctuate about 25 grad. To create the "if ... else if ..." block you must click on the gear icon and add required parts to "IF" block. ![Getting started 3](img/getting_started_3_1_en.png) You can specify comment for every block by selecting "Add comment" in context menu. You can later open the comments by clicking on the question mark icon. ![Getting started 3](img/getting_started_3_2_en.png) You can collapse some big blocks for better code presentation by selection in context menu "Collapse Block". ![Getting started 3](img/getting_started_3_3_en.png) Sample to import: ```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 ``` # Blocks ## System blocks ### Debug output ![Debug output](img/system_debug_en.png) This block does nothing except prints line into the log. You can use it for debugging of your script. Like this one: ![Debug output](img/system_debug_1_en.png) ```xml Print time into log every second interval 1000 log test hh:mm:ss ``` You can define 4 different levels of severity for message: - debug (the debug level of javascript adapter must be enabled) - info (default, at least info log level must be set in javascript instance settings) - warning - error - will be always displayed. Other severity levels can be ignored if severity of logging in javascirpt adapter is higher. ### Comment ![Comment](img/system_comment_en.png) Comment your code to understand it later better. It does nothing, just a comment. ### Control state ![Control state](img/system_control_en.png) You can write the state with two different meanings: - to control something and send command to end hardware (this block) - to update some state to just inform about e.g. new temperature ([next block](#update-state)) Typical usage of block: ![Control state](img/system_control_sample1_en.png) The object ID must be selected from dialog and the value must be defined too. Depends on the type of state the value can be [string](#string-value), [number](#number-value) or [boolean](#ogical-value-trueflase). You can read the explanation [here](https://git.spacen.net/yunkong2/yunkong2/wiki/Adapter-Development-Documentation#commands-and-statuses). This block writes command into state (ack=false). Additionally the delay can be specified. If delay is not 0, the state will be set not immediately but after defined in milliseconds period of time. You can stop all running delayed sets by issuing of control command. E.g in following schema the state "Light" will be controlled only once (in 2 seconds): ![Control state](img/system_control_1_en.png) ```xml Will be executed only once javascript.0.Light TRUE 1000 FALSE TRUE javascript.0.Light TRUE 2000 TRUE TRUE ``` But in this schema the state "Light" will be controlled twice (in 1 second and in 2 seconds): ![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 ``` ### Toggle state ![Toggle state](img/system_toggle_en.png) This block is similar to [control block](#control-state), but it toggles the value. From true to false and vice versa. ### Update state ![Update state](img/system_update_en.png) This block is similar to [control block](#control-state), but it is only updates the value. No command to control the hardware will be sent. Typical usage example: ![Update state](img/system_update_sample_en.png) ### Bind states ![Bind state](img/system_bind_en.png) This block simply binds two states with each other. You can achieve the same with this blocks: ![Bind state](img/system_bind_1_en.png) You can select if the value will be forwarded only if source state was changed or always when the state is just updated. ```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. Typical usage example: ![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 ``` You can start to use the new created state first in the block itself. Following code will report an error by the first execution, because subscribe for "myState" cannot find object: ![Create state](img/system_create_sample2_en.png) Although no warning will be printed by the second execution, because the state yet exists. ### Get value of state ![Get value of state](img/system_get_value_en.png) You can use this block to get the value of state. Additionally to value you can get following attributes: - Value - Acknowledge - command = false or update = true - Timestamp in ms from 1970.1.1 (It has type "Date object") - Last change of value in ms from 1970.1.1 (It has type "Date object") - Quality - Source - instance name, that wrote last value, like "system.adapter.javascript.0" Example to print time of the last value change: ![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 ``` ### Get Object ID ![Get Object ID](img/system_get_id_en.png) It is just a help block to comfortable select the object ID for trigger block. By clicking on Object ID value the select ID dialog will be opened. Typical usage: ![Get Object ID](img/system_get_id_sample_en.png) ```xml Typical usage of Object ID selector ne default javascript.0.myState log Changed ``` ## Actions Blocks ### Exec - execute ![Exec - execute](img/action_exec_en.png) Executes defined command on system. Like someone has written this command in SSH console. The command will be executed with permissions of user under which the yunkong2 was started. If no outputs are required, they can be ignored: ![Exec - execute](img/action_exec_2_en.png) If parsing of outputs must be done: ![Exec - execute](img/action_exec_1_en.png) ```xml Execute some system command TRUE ls /opt/ log result result ``` By analysing of outputs 3 special variables will be created: - result, consists normal output to the console (e.g. for "ls /opt" it consist "yunkong2 nodejs") - error object if command cannot be executed by javascript module - stderr, error output of executed program Additionally if the log level is not "none", the same command will be sent to log. ### request URL ![request URL](img/action_request_en.png) Calls URL and give back the result. Example: ![request URL](img/action_request_1_en.png) By analysing of outputs 3 special variables will be created: - result, consists body of the requested page - error, error description - response (only for experts), special object and has type of [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) If no outputs are required, they can be ignored. Just unset "with results" option. ## Send to Blocks ### Send to telegram ![Send to telegram](img/sendto_telegram_en.png) This block is used to send message to telegram client via telegram adapter. Of course the telegram adapter must be installed and configured. To send message to some specific instance, you should select the installed adapter instance (Normally telegram.0), elsewise message will be sent to all existing instances. Property *message* is mandatory and exactly this text will be sent to client. 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://git.spacen.net/yunkong2/yunkong2.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 of 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: ```

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://git.spacen.net/yunkong2/yunkong2.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 will use only one parameter with empty name, so no structure will 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 will start value with "{" it will be interpreted as JSON string. Use double quotes in string. ## Date and Time blocks ### Time comparision ![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 day time. 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://git.spacen.net/yunkong2/yunkong2.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 (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 to convert 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: ``` { "a": 1, "b": 2 } ``` if not: ``` {"a": 1, "b": 2} ``` ## 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 (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. ## Timeouts ### 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. 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 a 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. An additional feature is to set the interval by using a variable, just replace the "ms" with an predefined variable: ![Execution by interval variable](img/Timer_variable_en.PNG) ### 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) ## Functions ### Create function from blocks with no return value ![Create function from blocks with no return value](img/functions_function_en.png) With this block you can combine some repeat sequences into function and than use this function everywhere in current blockly. Here is an example of function that just prints into log current time. ![Create function from blocks with no return value](img/functions_function_2_en.png) ```xml Print current time printTime Describe this function... log test hh:mm:ss.sss ``` After the function created, you can use this function like this: ![Create function from blocks with no return value](img/functions_function_3_en.png) ```xml interval 1000 ``` You can find this new function in the blocks menu: ![Create function from blocks with no return value](img/functions_function_4_en.png) Additionally you can specify arguments for the function too via configuration dialog. You can edit the names of arguments in hte same dialog. ![Create function from blocks with no return value](img/functions_function_1_en.png) Here is an example of function that prints the sum of first argument and the second one: ![Create function from blocks with no return value](img/functions_function_5_en.png) ```xml Print sum of a and b printSum Describe this function... log test ADD 1 a 1 b ``` You can find the arguments in the variables menu: ![Create function from blocks with no return value](img/functions_function_6_en.png) And use this function like this: ![Create function from blocks with no return value](img/functions_function_7_en.png) ```xml 5 6 ``` ### Create function from blocks with return value ![Create function from blocks with return value](img/functions_function_ret_en.png) This block is the same, but it can return result of the function, that can be used later in blocks. ![Create function from blocks with return value](img/functions_function_ret_2_en.png) ```xml do something Return sum of a and b ADD 1 a 1 b ``` Usage is similar with other function blocks: ![Create function from blocks with return value](img/functions_function_ret_3_en.png) ```xml log test 5 6 sum Return sum of a and b ADD 1 a 1 b ``` For all functions you can add comment or description. ![Create function from blocks with return value](img/functions_function_ret_1_en.png) In the return block you can use special return element: ![Create function from blocks with return value](img/functions_function_ret_4_en.png) ![Create function from blocks with return value](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 ``` ### Return value in function ![Return value in function](img/functions_return_en.png) See usage of this block in [Create function from blocks with return value](#create-function-from-blocks-with-return-value]). This block can be used only there and serves to return value in the middle of the function. ### Create custom function with no return value ![Create custom function with no return value](img/functions_function_ex_en.png) Sometimes existing blocks are not suitable to solve specific problem. With this block you can create your own block as a function, that can accept parameters and do some action. To write such a function you must know javascript. You can use inside all functions, that were created for pure scripting. To write the code you must click the '...' at the ond the block and the editor dialog will be opened. ![Create custom function with no return value](img/functions_function_ex_1_en.png) Otherwise the usage of this block is similar with standard function blocks, like [Create function from blocks with return value](#create-function-from-blocks-with-return-value]) or [Create function from blocks with no return value](#create-function-from-blocks-with-no-return-value]). ### Create custom function with return value ![Create custom function with return value](img/functions_function_ex_ret_en.png) This custom function block can return values. To return result from function write ``` return 'your result'; ``` Like here: ![Create custom function with return value](img/functions_function_ex_ret_1_en.png) ```xml sum cmV0dXJuIGEgKyBiOw== Summarise a and b log test 5 6 ``` ### Call function ![Call function](img/functions_call_ex_en.png) ![Call function](img/functions_call_ex_ret_en.png) For every created function in the menu appears additional block with the name of this function. You can use it like normal blocks in you scripts.