├── CNAME ├── .gitignore ├── _config.yml ├── _includes ├── indexes │ ├── functions.md │ ├── mqtt.md │ ├── http.md │ └── basic.md ├── toc-recipe.html ├── breadcrumbs.html ├── header.html ├── toc-footer.html └── footer.html ├── favicon.ico ├── node-red.png ├── images ├── node-red.png ├── basic │ ├── convert-xml.png │ ├── parse-csv.png │ ├── split-text.png │ ├── convert-json.png │ ├── convert-yaml.png │ ├── generate-csv.png │ ├── join-streams.png │ ├── operate-on-array.png │ ├── retry-on-error.png │ ├── route-on-context.png │ ├── trigger-at-time.png │ ├── trigger-on-error.png │ ├── trigger-on-start.png │ ├── trigger-timeout.png │ ├── route-on-property.png │ ├── copy-message-property.png │ ├── move-message-property.png │ ├── rate-limit-messages.png │ ├── report-by-exception.png │ ├── trigger-at-interval.png │ ├── trigger-placeholder.png │ ├── delete-message-property.png │ ├── rate-limit-message-stream.png │ ├── set-message-property-fixed.png │ └── map-between-different-number-ranges.png ├── mqtt │ ├── receive-json.png │ ├── connect-to-broker.png │ ├── publish-to-topic.png │ ├── set-publish-topic.png │ ├── subscribe-to-topic.png │ ├── publish-retained-message.png │ └── publish-to-topic-config.png └── http │ ├── set-query-string.png │ ├── set-request-url.png │ ├── work-with-cookies.png │ ├── get-binary-response.png │ ├── parse-json-response.png │ ├── serve-a-local-file.png │ ├── serve-json-content.png │ ├── set-request-header.png │ ├── simple-get-request.png │ ├── handle-url-parameters.png │ ├── create-an-http-endpoint.png │ ├── handle-query-parameters.png │ ├── post-form-data-to-a-flow.png │ ├── post-raw-data-to-a-flow.png │ ├── set-request-url-template.png │ ├── access-http-request-headers.png │ ├── include-data-from-another-flow.png │ └── simple-get-request-example-page.png ├── basic ├── index.md ├── delete-message-property.md ├── trigger-at-time.md ├── trigger-at-interval.md ├── copy-message-property.md ├── move-message-property.md ├── trigger-on-start.md ├── set-message-property-fixed.md ├── trigger-on-error.md ├── rate-limit-message-stream.md ├── report-by-exception.md ├── rate-limit-messages.md ├── map-between-different-number-ranges.md ├── trigger-timeout.md ├── convert-yaml.md ├── convert-json.md ├── parse-csv.md ├── retry-on-error.md ├── operate-on-array.md ├── route-on-property.md ├── split-text.md ├── join-streams.md ├── trigger-placeholder.md ├── convert-xml.md ├── route-on-context.md └── generate-csv.md ├── http ├── index.md ├── access-http-request-headers.md ├── get-binary-response.md ├── post-raw-data-to-a-flow.md ├── post-json-data-to-a-flow.md ├── serve-a-local-file.md ├── handle-query-parameters.md ├── simple-get-request.md ├── serve-json-content.md ├── parse-json-response.md ├── handle-url-parameters.md ├── set-request-header.md ├── post-form-data-to-a-flow.md ├── set-query-string.md ├── create-an-http-endpoint.md ├── set-request-url-template.md ├── include-data-from-another-flow.md ├── set-request-url.md └── work-with-cookies.md ├── mqtt ├── index.md ├── publish-to-topic.md ├── set-publish-topic.md ├── publish-retained-message.md ├── subscribe-to-topic.md ├── receive-json.md └── connect-to-broker.md ├── css ├── generate-style.sh └── style.min.css ├── README.md ├── index.md ├── _layouts ├── index.html └── default.html ├── styleguide.md └── LICENSE /CNAME: -------------------------------------------------------------------------------- 1 | cookbook.nodered.org 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _site/ 3 | .sass-cache/ 4 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | name: Node-RED 2 | markdown: kramdown 3 | -------------------------------------------------------------------------------- /_includes/indexes/functions.md: -------------------------------------------------------------------------------- 1 | #### Function node 2 | 3 | - Create an HTTP Endpoint 4 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/favicon.ico -------------------------------------------------------------------------------- /node-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/node-red.png -------------------------------------------------------------------------------- /images/node-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/node-red.png -------------------------------------------------------------------------------- /basic/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: index 3 | title: Basic recipes 4 | --- 5 | 6 | {% include indexes/basic.md %} 7 | -------------------------------------------------------------------------------- /http/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: index 3 | title: HTTP recipes 4 | --- 5 | 6 | {% include indexes/http.md %} 7 | -------------------------------------------------------------------------------- /mqtt/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: index 3 | title: MQTT Recipes 4 | --- 5 | 6 | {% include indexes/mqtt.md %} 7 | -------------------------------------------------------------------------------- /images/basic/convert-xml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/convert-xml.png -------------------------------------------------------------------------------- /images/basic/parse-csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/parse-csv.png -------------------------------------------------------------------------------- /images/basic/split-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/split-text.png -------------------------------------------------------------------------------- /images/mqtt/receive-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/receive-json.png -------------------------------------------------------------------------------- /images/basic/convert-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/convert-json.png -------------------------------------------------------------------------------- /images/basic/convert-yaml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/convert-yaml.png -------------------------------------------------------------------------------- /images/basic/generate-csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/generate-csv.png -------------------------------------------------------------------------------- /images/basic/join-streams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/join-streams.png -------------------------------------------------------------------------------- /images/basic/operate-on-array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/operate-on-array.png -------------------------------------------------------------------------------- /images/basic/retry-on-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/retry-on-error.png -------------------------------------------------------------------------------- /images/basic/route-on-context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/route-on-context.png -------------------------------------------------------------------------------- /images/basic/trigger-at-time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/trigger-at-time.png -------------------------------------------------------------------------------- /images/basic/trigger-on-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/trigger-on-error.png -------------------------------------------------------------------------------- /images/basic/trigger-on-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/trigger-on-start.png -------------------------------------------------------------------------------- /images/basic/trigger-timeout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/trigger-timeout.png -------------------------------------------------------------------------------- /images/http/set-query-string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/set-query-string.png -------------------------------------------------------------------------------- /images/http/set-request-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/set-request-url.png -------------------------------------------------------------------------------- /images/http/work-with-cookies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/work-with-cookies.png -------------------------------------------------------------------------------- /images/mqtt/connect-to-broker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/connect-to-broker.png -------------------------------------------------------------------------------- /images/mqtt/publish-to-topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/publish-to-topic.png -------------------------------------------------------------------------------- /images/mqtt/set-publish-topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/set-publish-topic.png -------------------------------------------------------------------------------- /images/basic/route-on-property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/route-on-property.png -------------------------------------------------------------------------------- /images/http/get-binary-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/get-binary-response.png -------------------------------------------------------------------------------- /images/http/parse-json-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/parse-json-response.png -------------------------------------------------------------------------------- /images/http/serve-a-local-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/serve-a-local-file.png -------------------------------------------------------------------------------- /images/http/serve-json-content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/serve-json-content.png -------------------------------------------------------------------------------- /images/http/set-request-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/set-request-header.png -------------------------------------------------------------------------------- /images/http/simple-get-request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/simple-get-request.png -------------------------------------------------------------------------------- /images/mqtt/subscribe-to-topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/subscribe-to-topic.png -------------------------------------------------------------------------------- /images/basic/copy-message-property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/copy-message-property.png -------------------------------------------------------------------------------- /images/basic/move-message-property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/move-message-property.png -------------------------------------------------------------------------------- /images/basic/rate-limit-messages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/rate-limit-messages.png -------------------------------------------------------------------------------- /images/basic/report-by-exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/report-by-exception.png -------------------------------------------------------------------------------- /images/basic/trigger-at-interval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/trigger-at-interval.png -------------------------------------------------------------------------------- /images/basic/trigger-placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/trigger-placeholder.png -------------------------------------------------------------------------------- /images/http/handle-url-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/handle-url-parameters.png -------------------------------------------------------------------------------- /images/basic/delete-message-property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/delete-message-property.png -------------------------------------------------------------------------------- /images/http/create-an-http-endpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/create-an-http-endpoint.png -------------------------------------------------------------------------------- /images/http/handle-query-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/handle-query-parameters.png -------------------------------------------------------------------------------- /images/http/post-form-data-to-a-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/post-form-data-to-a-flow.png -------------------------------------------------------------------------------- /images/http/post-raw-data-to-a-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/post-raw-data-to-a-flow.png -------------------------------------------------------------------------------- /images/http/set-request-url-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/set-request-url-template.png -------------------------------------------------------------------------------- /images/mqtt/publish-retained-message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/publish-retained-message.png -------------------------------------------------------------------------------- /images/mqtt/publish-to-topic-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/mqtt/publish-to-topic-config.png -------------------------------------------------------------------------------- /images/basic/rate-limit-message-stream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/rate-limit-message-stream.png -------------------------------------------------------------------------------- /images/basic/set-message-property-fixed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/set-message-property-fixed.png -------------------------------------------------------------------------------- /images/http/access-http-request-headers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/access-http-request-headers.png -------------------------------------------------------------------------------- /images/http/include-data-from-another-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/include-data-from-another-flow.png -------------------------------------------------------------------------------- /images/http/simple-get-request-example-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/http/simple-get-request-example-page.png -------------------------------------------------------------------------------- /images/basic/map-between-different-number-ranges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-red/cookbook.nodered.org/master/images/basic/map-between-different-number-ranges.png -------------------------------------------------------------------------------- /css/generate-style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Generates the stylesheet based on the main site css that assumed to be co-located 3 | 4 | echo > style.css 5 | for x in simplegrid.css style.css front.css docs.css blog.css syntax.css 6 | do 7 | cat "../../node-red.github.io/css/"$x >> style.css 8 | done 9 | scss -t compressed style.css > style.min.css 10 | rm style.css 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-red.github.io 2 | ================== 3 | 4 | [Node-RED Site](http://nodered.org) 5 | 6 | ### Contributing / Fixes 7 | 8 | For simple typos and single line fixes please just raise an issue pointing out 9 | our mistakes. If you need to raise a pull request please read our 10 | [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) 11 | before doing so. 12 | -------------------------------------------------------------------------------- /_includes/indexes/mqtt.md: -------------------------------------------------------------------------------- 1 | #### MQTT 2 | 3 | - [Connect to an MQTT broker](/mqtt/connect-to-broker) 4 | - [Publish messages to a topic](/mqtt/publish-to-topic) 5 | - [Set the topic of a published message](/mqtt/set-publish-topic) 6 | - [Publish a retained message to a topic](/mqtt/publish-retained-message) 7 | - [Subscribe to a topic](/mqtt/subscribe-to-topic) 8 | - [Receive a parsed JSON message](/mqtt/receive-json) 9 | -------------------------------------------------------------------------------- /_includes/toc-recipe.html: -------------------------------------------------------------------------------- 1 |
Change node to delete the property.
17 |
18 | #### Example
19 |
20 | {:width="616px"}
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"91cd2fa9.e0a96","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":140,"y":180,"wires":[["54ec03e4.5714bc"]]},{"id":"54ec03e4.5714bc","type":"change","z":"535331d8.55c1f","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":180,"wires":[["321900de.3cbea"]]},{"id":"321900de.3cbea","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":550,"y":180,"wires":[]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | ### Discussion
30 |
31 | The Change node can be used to delete properties of a message.
32 |
--------------------------------------------------------------------------------
/_includes/indexes/http.md:
--------------------------------------------------------------------------------
1 | #### HTTP endpoints
2 |
3 | - [Create an HTTP Endpoint](/http/create-an-http-endpoint)
4 | - [Handle query parameters passed to an HTTP endpoint](/http/handle-query-parameters)
5 | - [Handle url parameters in an HTTP endpoint](/http/handle-url-parameters)
6 | - [Access HTTP request headers](/http/access-http-request-headers)
7 | - [Include data captured in another flow](/http/include-data-from-another-flow)
8 | - [Serve JSON content](/http/serve-json-content)
9 | - [Serve a local file](/http/serve-a-local-file)
10 | - [Post raw data to a flow](/http/post-raw-data-to-a-flow)
11 | - [Post form data to a flow](/http/post-form-data-to-a-flow)
12 | - [Post JSON data to a flow](/http/post-json-data-to-a-flow)
13 | - [Work with cookies](/http/work-with-cookies)
14 |
15 | #### HTTP requests
16 | - [Simple GET request](/http/simple-get-request)
17 | - [Set the url of a request](/http/set-request-url)
18 | - [Set the url of a request using a template](/http/set-request-url-template)
19 | - [Set query string parameters](/http/set-query-string)
20 | - [Get a parsed JSON response](/http/parse-json-response)
21 | - [Get a binary response](/http/get-binary-response)
22 | - [Set a request header](/http/set-request-header)
23 |
--------------------------------------------------------------------------------
/basic/trigger-at-time.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Trigger a flow at a specific time
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - trigger at time
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to trigger a flow at a specific time, such as at 4pm every weekday.
13 |
14 | ### Solution
15 |
16 | Use an Inject node configured to trigger at the desired
17 | time.
18 |
19 | #### Example
20 |
21 | {:width="530px"}
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"24579bcb.5c9814","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"It is 4pm on a weekday!","payloadType":"str","repeat":"","crontab":"00 16 * * 1,2,3,4,5","once":false,"x":190,"y":660,"wires":[["145b508a.f3325f"]]},{"id":"145b508a.f3325f","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":410,"y":660,"wires":[]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | The Inject node can be configured to trigger at a specific
33 | time on specific days of the week.
34 |
35 | If multiple different times are required, multiple Inject
36 | nodes should be used.
37 |
--------------------------------------------------------------------------------
/basic/trigger-at-interval.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Trigger a flow at regular intervals
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - trigger at interval
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to trigger a flow at regular intervals. For example, to periodically
13 | call an api to retrieve its current state.
14 |
15 | ### Solution
16 |
17 | Use an Inject node configured to repeat at the desired
18 | interval.
19 |
20 | To stop - you must re-configure the node and set Repeat to none. Click done to save the change and deploy.
21 |
22 | #### Example
23 |
24 | {:width="530px"}
25 |
26 | {% raw %}
27 | ~~~json
28 | [{"id":"372cfc32.bcd244","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"","payloadType":"date","repeat":"5","crontab":"","once":false,"x":150,"y":600,"wires":[["6c63c499.ce3adc"]]},{"id":"6c63c499.ce3adc","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":410,"y":600,"wires":[]}]
29 | ~~~
30 | {: .flow}
31 | {% endraw %}
32 |
33 | ### Discussion
34 |
35 | The Inject node can be configured to repeat at a fixed
36 | interval. If desired, it can also be constrained to do so between certain times on
37 | certain days.
38 |
--------------------------------------------------------------------------------
/basic/copy-message-property.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Set a message property to another property
4 | slug:
5 | - label: messages
6 | url: /#messages
7 | - copy property
8 | ---
9 | *** Not published ***
10 |
11 | ### Problem
12 |
13 | You want to copy a property of a message to another property.
14 |
15 | ### Solution
16 |
17 | Use the Change node to set the property of the message.
18 |
19 | #### Example
20 |
21 | {:width="616px"}
22 |
23 | {% raw %}
24 | ~~~json
25 | []
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | The Change node can be used to set properties of a message.
33 |
34 | The node supports setting various JavaScript types as well as some Node-RED specific
35 |
36 | - strings: `"hello world"`
37 | - numbers: `42`
38 | - boolean: `true`/`false`
39 | - timestamp: the current time, in milliseconds, since epoch (January 1st, 1970)
40 | - JSON: a JSON string that will be parsed to its Object representation
41 |
42 | It also supports setting a property to a value based on the value of context properties,
43 | other message properties or an JSONata expression. These are each explored more in the
44 | following recipes:
45 |
46 | - [Set a message property to a context value]()
47 | - [Set a message property to another message property]()
48 |
--------------------------------------------------------------------------------
/mqtt/publish-to-topic.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Publish messages to a topic
4 | slug:
5 | - label: mqtt
6 | url: /#mqtt
7 | - publish
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to publish a message to an MQTT topic on a broker.
13 |
14 | ### Solution
15 |
16 | Use the MQTT Output node to publish messages to a topic.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | 
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"9c138886.116928","type":"mqtt out","z":"eda2a949.74ea98","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"","broker":"61de5090.0f5d9","x":430,"y":100,"wires":[]},{"id":"ff654e7f.32e9e","type":"inject","z":"eda2a949.74ea98","name":"temperature","topic":"","payload":"22","payloadType":"num","repeat":"","crontab":"","once":false,"x":230,"y":100,"wires":[["9c138886.116928"]]},{"id":"61de5090.0f5d9","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ### Discussion
32 |
33 | The MQTT Output node with an associated MQTT Config node connected to an MQTT broker can be used to publish messages to a pre-configured topic.
34 |
--------------------------------------------------------------------------------
/basic/move-message-property.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Move a message property
4 | slug:
5 | - label: messages
6 | url: /#messages
7 | - move property
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to move a message property to a different property.
13 |
14 | ### Solution
15 |
16 | Use the Change node to move a property.
17 |
18 | #### Example
19 |
20 | {:width="616px"}
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"d11f7311.77c15","type":"inject","z":"535331d8.55c1f","name":"","topic":"Hello","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":160,"y":280,"wires":[["13c01487.eb13cb"]]},{"id":"13c01487.eb13cb","type":"change","z":"535331d8.55c1f","name":"","rules":[{"t":"move","p":"topic","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":280,"wires":[["89cc4fb1.9b208"]]},{"id":"89cc4fb1.9b208","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":550,"y":280,"wires":[]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | ### Discussion
30 |
31 | The Change node can be used to move a property of a message.
32 |
33 | It can be done as two separate actions in the Change node;
34 | first using a Set action to copy the property to its new location and then a Delete
35 | action to remove the original.
36 |
37 | Alternatively, the node supports a Move action that does it in one step.
38 |
--------------------------------------------------------------------------------
/mqtt/set-publish-topic.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Set the topic of a published message
4 | slug:
5 | - label: mqtt
6 | url: /#mqtt
7 | - publish topic
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to set the topic of a published MQTT message dynamically.
13 |
14 | ### Solution
15 |
16 | Set the `topic` message property, before sending the message to an MQTT Output node.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"73abc692.bb3838","type":"mqtt out","z":"eda2a949.74ea98","name":"","topic":"","qos":"","retain":"","broker":"61de5090.0f5d9","x":410,"y":300,"wires":[]},{"id":"ef5a01ee.a940d","type":"inject","z":"eda2a949.74ea98","name":"kitchen temperature","topic":"sensors/kitchen/temperature","payload":"22","payloadType":"num","repeat":"","crontab":"","once":false,"x":250,"y":300,"wires":[["73abc692.bb3838"]]},{"id":"61de5090.0f5d9","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | In this example, the Inject node sets the `msg.topic`,
30 | but you don't always need to use an inject node to do this.
31 |
32 | ### Discussion
33 |
34 | Ensure the `Topic` field in the MQTT Output configuration dialog is left blank to use the `topic` message property.
35 |
--------------------------------------------------------------------------------
/basic/trigger-on-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Trigger a flow whenever Node-RED starts
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - trigger on start
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to trigger a flow whenever Node-RED starts.
13 |
14 | This could be used to initialise context variables, or to send a notification
15 | that Node-RED has been restarted.
16 |
17 | ### Solution
18 |
19 | Use an Inject node configured to fire once on start. Double click the inject node to open it - scroll down and tick the checkbox
20 |
21 | ✅ Inject once after [0.1] seconds, then
22 |
23 | Click Done to save the change.
24 |
25 | #### Example
26 |
27 | {:width="530px"}
28 |
29 | {% raw %}
30 | ~~~json
31 | [{"id":"e60b12c1.93bb3","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"Started!","payloadType":"str","repeat":"","crontab":"","once":true,"x":140,"y":540,"wires":[["9b1d7727.56d0f8"]]},{"id":"9b1d7727.56d0f8","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":410,"y":540,"wires":[]}]
32 | ~~~
33 | {: .flow}
34 | {% endraw %}
35 |
36 | ### Discussion
37 |
38 | When configured to fire on start, the Inject node will
39 | be automatically triggered a few hundred milliseconds after it is deployed. This
40 | delay is used to help ensure the rest of the flows have been created and Started
41 | by this point.
42 |
43 | The node will trigger whenever it is deployed.
44 |
--------------------------------------------------------------------------------
/mqtt/publish-retained-message.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Publish a retained message to a topic
4 | slug:
5 | - label: mqtt
6 | url: /#mqtt
7 | - retained
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to publish a retained message to an MQTT topic on a broker.
13 |
14 | ### Solution
15 |
16 | Set the `Retain` option to `true` in the MQTT Output node
17 | configuration dialog, or set the `msg.retain` message property to `true` in the
18 | message sent to the node.
19 |
20 | #### Example
21 |
22 | 
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"4a7dc819.3aa6f8","type":"mqtt out","z":"eda2a949.74ea98","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"true","broker":"61de5090.0f5d9","x":430,"y":420,"wires":[]},{"id":"fb7b873.c391878","type":"inject","z":"eda2a949.74ea98","name":"temperature","topic":"","payload":"22","payloadType":"num","repeat":"","crontab":"","once":false,"x":230,"y":420,"wires":[["4a7dc819.3aa6f8"]]},{"id":"61de5090.0f5d9","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ### Discussion
32 |
33 | Once you have sent a retained message to a topic, all subscribers will receive
34 | that message when they subscribe.
35 |
36 | To clear a previously retained topic from the broker, send a blank message to
37 | that topic with the retain flag set.
38 |
--------------------------------------------------------------------------------
/http/access-http-request-headers.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Access HTTP request headers
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - headers
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to access the HTTP headers sent in a request.
13 |
14 | ### Solution
15 |
16 | Use the `msg.req.headers` property of the message sent by the HTTP In
17 | node to access the headers.
18 |
19 | #### Example
20 |
21 | {:width="800px"}
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"c1460268.3eba","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-headers","method":"get","swaggerDoc":"","x":130,"y":380,"wires":[["24199456.dbe66c"]]},{"id":"24199456.dbe66c","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP Request node will return the body of a response in the `msg.payload` as a string by default.
17 | Change the `Return` configuration of this node to `a binary buffer` to return the response as a binary buffer in the `msg.payload`.
18 |
19 | #### Example
20 |
21 | {:width="556px"}
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"871ee927.0d69c8","type":"inject","z":"c9a81b70.8abed8","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":240,"y":660,"wires":[["8ea4e52a.03d678"]]},{"id":"8ea4e52a.03d678","type":"http request","z":"c9a81b70.8abed8","name":"binary http request","method":"GET","ret":"bin","url":"http://localhost:1880/binary","tls":"","x":410,"y":660,"wires":[["70309d0c.4dc504"]]},{"id":"70309d0c.4dc504","type":"debug","z":"c9a81b70.8abed8","name":"","active":true,"console":"false","complete":"false","x":590,"y":660,"wires":[]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | We have modified the flow from the [Set the URL of a Request URL recipe](set-request-url.html) by changing the
31 | HTTP Request node `Return` configuration to `a binary buffer`. The Debug node
32 | will display the payload as a binary buffer such as:
33 |
34 | {% raw %}
35 | ~~~text
36 | [ 80, 75, 3, 4, 20, 0, 6, 0, 8, 0 … ]
37 | ~~~
38 | {% endraw %}
39 |
--------------------------------------------------------------------------------
/http/post-raw-data-to-a-flow.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Post raw data to a flow
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - post data
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to post raw text data in to a flow.
13 |
14 | ### Solution
15 |
16 | Use the HTTP In node to listen for POST requests that
17 | have their `Content-Type` set to `text/plain` and access the posted data as `msg.payload`.
18 |
19 | #### Example
20 |
21 | 
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"3e1c5107.c1e3ae","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-raw","method":"post","swaggerDoc":"","x":120,"y":920,"wires":[["cf679478.309868"]]},{"id":"cf679478.309868","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP In node receives a request with the `Content-Type`
44 | header set to `text/plain` it makes the body available as `msg.payload`:
45 |
46 | ~~~javascript
47 | var name = msg.payload;
48 | ~~~
49 |
--------------------------------------------------------------------------------
/http/post-json-data-to-a-flow.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Post JSON data to a flow
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - post json
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to post JSON data in to a flow.
13 |
14 | ### Solution
15 |
16 | Use the HTTP In node to listen for POST requests that
17 | have their `Content-Type` set to `application/json` and access the parsed JSON as
18 | properties of `msg.payload`.
19 |
20 | #### Example
21 |
22 | 
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"5b98a8ac.a46758","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-form","method":"post","swaggerDoc":"","x":120,"y":820,"wires":[["bba61009.4459f"]]},{"id":"bba61009.4459f","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP In node receives a request with the `Content-Type`
45 | header set to `application/json` it parses the body of the request and makes the data
46 | available under `msg.payload`:
47 |
48 | ~~~javascript
49 | var name = msg.payload.name;
50 | ~~~
51 |
--------------------------------------------------------------------------------
/basic/set-message-property-fixed.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Set a message property to a fixed value
4 | slug:
5 | - label: messages
6 | url: /#messages
7 | - set property
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to set a message property to a fixed value.
13 |
14 | ### Solution
15 |
16 | Use the Change node to set the property of the message.
17 |
18 | #### Example
19 |
20 | {:width="616px"}
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"d72dc4ce.89b368","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":140,"y":80,"wires":[["78075f19.e0174"]]},{"id":"78075f19.e0174","type":"change","z":"535331d8.55c1f","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"Hello World!","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":80,"wires":[["78dc7c25.b90d54"]]},{"id":"78dc7c25.b90d54","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":550,"y":80,"wires":[]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | ### Discussion
30 |
31 | The Change node can be used to set properties of a message.
32 |
33 | The node supports setting various JavaScript types as well as some Node-RED specific types.
34 |
35 | - strings: `"hello world"`
36 | - numbers: `42`
37 | - boolean: `true`/`false`
38 | - timestamp: the current time, in milliseconds, since epoch (January 1st, 1970)
39 | - JSON: a JSON string that will be parsed to its Object representation
40 | - Buffer: a Node.js Buffer object
41 |
42 | It also supports setting a property to a value based on the value of context properties,
43 | other message properties or a JSONata expression.
44 |
--------------------------------------------------------------------------------
/_includes/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Catch node to receive the error and trigger a flow.
17 |
18 | #### Example
19 |
20 | {:width="401px"}
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"2bd6810d.e22ece","type":"catch","z":"fc046f99.4be08","name":"","scope":["2c94a22c.91012e"],"uncaught":false,"x":130,"y":160,"wires":[["d16b9fac.8212a"]]},{"id":"2c94a22c.91012e","type":"function","z":"fc046f99.4be08","name":"Throw Error","func":"node.error(\"an example error\", msg); ","outputs":1,"noerr":0,"x":310,"y":100,"wires":[[]]},{"id":"d16b9fac.8212a","type":"debug","z":"fc046f99.4be08","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"error","targetType":"msg","x":300,"y":160,"wires":[]},{"id":"c5ee9670.5dbbd8","type":"inject","z":"fc046f99.4be08","name":"Trigger error","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":100,"wires":[["2c94a22c.91012e"]]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | ### Discussion
30 |
31 | The Catch node can be configured to catch errors from
32 | specific nodes in the flow or from any node. This allows you to create different
33 | error handling flows for different nodes.
34 |
35 | The Catch node sends on the message that was logged with
36 | the error. It also sets `msg.error` with details of the error and which node triggered
37 | it.
38 |
39 | Note that this requires nodes to properly log their errors so that they can be caught.
40 |
--------------------------------------------------------------------------------
/basic/rate-limit-message-stream.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Handle messages at a regular rate
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - rate limit
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to handle messages at a regular rate, ignoring messages that arrive too
13 | quickly. For example, you have a sensor sending data every second but you only
14 | want to handle an update every 5 seconds. The messages you handle must be the most
15 | recent.
16 |
17 | ### Solution
18 |
19 | Use a Delay node configured to rate limit the messages
20 | passing through it with the option to drop intermediate messages enabled.
21 |
22 | #### Example
23 |
24 | {:width="601px"}
25 |
26 | {% raw %}
27 | ~~~json
28 | [{"id":"8a1bcd7d.f6b67","type":"inject","z":"ac14500e.2c57d","name":"Inject Array","topic":"","payload":"[0,1,2,3,4,5,6,7,8,9]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":1380,"wires":[["bd4bdd42.bd1b"]]},{"id":"bd4bdd42.bd1b","type":"delay","z":"ac14500e.2c57d","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":320,"y":1380,"wires":[["be20c513.237c78"]]},{"id":"be20c513.237c78","type":"debug","z":"ac14500e.2c57d","name":"Debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":510,"y":1380,"wires":[]}]
29 | ~~~
30 | {: .flow}
31 | {% endraw %}
32 |
33 | ### Discussion
34 |
35 | The rate limiting mode of the Delay node can be used to
36 | change the rate of messages passing through it. With the option to drop intermediate
37 | messages enabled, it will discard any message that arrives within the rate limit
38 | interval.
39 |
--------------------------------------------------------------------------------
/_layouts/default.html:
--------------------------------------------------------------------------------
1 | {% include header.html %}
2 |
51 | MQTT Input node to subscribe to the broker and
17 | receive messages published to matching topics.
18 |
19 | #### Example
20 |
21 | 
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"8024cb4.98c5238","type":"mqtt in","z":"eda2a949.74ea98","name":"","topic":"sensors/#","qos":"2","broker":"61de5090.0f5d9","x":240,"y":180,"wires":[["15d727dd.33e808"]]},{"id":"15d727dd.33e808","type":"debug","z":"eda2a949.74ea98","name":"","active":true,"console":"false","complete":"false","x":390,"y":180,"wires":[]},{"id":"61de5090.0f5d9","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | The MQTT Input node must be hardcoded with the topic filter
33 | to use - it cannot be changed dynamically.
34 |
35 | One possible workaround is to set the topic to an environment variable such as
36 | `$(MY_TOPIC)`. When the Node-RED runtime starts it will substitute the environment
37 | variable value into that property of the node. This does allow the topic to be changed, although
38 | doing so does require a restart of Node-RED to pickup changes to the environment variable.
39 |
40 | You can also use MQTT wildcards, `+` for a single topic level or `#` for multiple. This allows
41 | you to receive multiple topics with a single node. The messages will be sent from
42 | the node with `msg.topic` set to the actual topic received.
43 |
--------------------------------------------------------------------------------
/http/serve-a-local-file.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Serve a local file
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - serve file
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to create an HTTP endpoint that responds to GET requests with content
13 | from a local file, such an png image.
14 |
15 | ### Solution
16 |
17 | Use the File In node to load the required content and
18 | set the `Content-Type` to the appropriate value for the file type being returned.
19 |
20 | #### Example
21 |
22 | 
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"c7e341a0.381cc","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-file","method":"get","swaggerDoc":"","x":110,"y":720,"wires":[["2fb1c354.d04e3c"]]},{"id":"2fb1c354.d04e3c","type":"file in","z":"3045204d.cfbae","name":"","filename":"/tmp/node-red.png","format":"","x":290,"y":720,"wires":[["c9e28681.361d78"]]},{"id":"c9e28681.361d78","type":"change","z":"3045204d.cfbae","name":"Set Headers","rules":[{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.content-type","pt":"msg","to":"image/png","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":720,"wires":[["88974243.7768c"]]},{"id":"88974243.7768c","type":"http response","z":"3045204d.cfbae","name":"","x":610,"y":720,"wires":[]}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ~~~text
32 | [~]$ curl http://localhost:1880/hello-file > file.png
33 | ~~~
34 | {: .shell}
35 |
36 | ### Discussion
37 |
38 | When loading a non-text file such as an image, the File In
39 | node must be configured to return a `Buffer` object.
40 |
41 | So that the receiver knows how to handle the file, the `Content-Type` header must
42 | be set to the appropriate mime type. The example above, which returns a `.png` file
43 | sets the `Content-Type` header to `image/png`.
44 |
--------------------------------------------------------------------------------
/_includes/indexes/basic.md:
--------------------------------------------------------------------------------
1 | #### Messages
2 |
3 | - [Set a message property to a fixed value](/basic/set-message-property-fixed)
4 | - [Delete a message property](/basic/delete-message-property)
5 | - [Move a message property](/basic/move-message-property)
6 | - [Map a property between different numeric ranges](/basic/map-between-different-number-ranges)
7 |
8 |
9 | #### Flow control
10 |
11 | - [Trigger a flow whenever Node-RED starts](/basic/trigger-on-start)
12 | - [Trigger a flow at regular intervals](/basic/trigger-at-interval)
13 | - [Trigger a flow at a specific time](/basic/trigger-at-time)
14 | - [Route a message based on one of its properties](/basic/route-on-property)
15 | - [Route a message based on a context value](/basic/route-on-context)
16 | - [Perform an operation on each element in an array](/basic/operate-on-array)
17 | - [Trigger a flow if a message isn't received after a defined time](/basic/trigger-timeout)
18 | - [Send placeholder messages when a stream stops sending](/basic/trigger-placeholder)
19 | - [Slow down messages passing through a flow](/basic/rate-limit-messages)
20 | - [Handle messages at a regular rate](/basic/rate-limit-message-stream)
21 | - [Drop messages that have not changed value](/basic/report-by-exception)
22 | - [Create a single message from separate streams of messages](/basic/join-streams)
23 |
24 | #### Error handling
25 |
26 | - [Trigger a flow when a node throws an error](/basic/trigger-on-error)
27 | - [Automatically retry an action after an error](/basic/retry-on-error)
28 |
29 | #### Working with data formats
30 |
31 | - [Convert to/from JSON](/basic/convert-json)
32 | - [Convert to/from XML](/basic/convert-xml)
33 | - [Convert to/from YAML](/basic/convert-yaml)
34 | - [Generate CSV output](/basic/generate-csv)
35 | - [Parse CSV input](/basic/parse-csv)
36 | - [Extracting data from an HTML page](/http/simple-get-request)
37 | - [Split text into one message per line](/basic/split-text)
38 |
--------------------------------------------------------------------------------
/basic/report-by-exception.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Drop messages that have not changed value
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - rbe
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to drop a message if the value of its payload has not changed since the
13 | last message. For example, you have a sensor sending the state of a switch at
14 | regular intervals and you only want to know when the value has changed.
15 |
16 |
17 | ### Solution
18 |
19 | Use the RBE node (Report By Exception) to block messages
20 | unless its value has changed.
21 |
22 | #### Example
23 |
24 | {:width="618px"}
25 |
26 | {% raw %}
27 | ~~~json
28 | [{"id":"6079638d.df403c","type":"inject","z":"ac14500e.2c57d","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":1500,"wires":[["87129503.c7b358"]]},{"id":"87129503.c7b358","type":"rbe","z":"ac14500e.2c57d","name":"report-by-exception","func":"deadband","gap":"","start":"","inout":"out","property":"payload","x":300,"y":1520,"wires":[["5e2ffc27.c61dd4"]]},{"id":"5e2ffc27.c61dd4","type":"debug","z":"ac14500e.2c57d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":510,"y":1520,"wires":[]},{"id":"2dc49f96.3070c","type":"inject","z":"ac14500e.2c57d","name":"","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":1540,"wires":[["87129503.c7b358"]]}]
29 | ~~~
30 | {: .flow}
31 | {% endraw %}
32 |
33 | ### Discussion
34 |
35 | The RBE can be used to drop messages unless their value
36 | has changed. This is useful for detecting changes.
37 |
38 | If the property being checked is a number, the node can also be configured with
39 | a threshold for how much the value must change for the message to be passed on.
40 |
--------------------------------------------------------------------------------
/http/handle-query-parameters.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Handle query parameters passed to an HTTP endpoint
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - query parameters
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to access the query parameters passed to an HTTP endpoint, such as:
13 |
14 | http://example.com/hello-query?name=Nick
15 |
16 | ### Solution
17 |
18 | Use the `msg.req.query` property of the message sent by the HTTP In
19 | node to access the parameters.
20 |
21 | #### Example
22 |
23 | 
24 |
25 | {% raw %}
26 | ~~~json
27 | [{"id":"b34dd1af.4cb23","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP Request node to make an HTTP request and an
17 | HTML node to extract elements from the retrieved html document.
18 |
19 | #### Example
20 |
21 | 
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"d88dd470.0ac7b8","type":"inject","z":"18c99b30.cf9d35","name":"make request","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":130,"y":180,"wires":[["874a3d4e.9b666"]]},{"id":"874a3d4e.9b666","type":"http request","z":"18c99b30.cf9d35","name":"","method":"GET","ret":"txt","url":"https://nodered.org","tls":"","x":294.5,"y":180,"wires":[["90243cc1.87edc"]]},{"id":"7403c68f.21d7c8","type":"debug","z":"18c99b30.cf9d35","name":"","active":true,"console":"false","complete":"false","x":650,"y":180,"wires":[]},{"id":"90243cc1.87edc","type":"html","z":"18c99b30.cf9d35","name":"","property":"","tag":".node-red-latest-version","ret":"text","as":"single","x":471.5,"y":180,"wires":[["7403c68f.21d7c8"]]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | To find content in a web page, the Chrome browser’s ‘Inspect Element’ can be a
33 | useful tool. Using the browser, right click on a page element to see the tags,
34 | ids and classes applied to an element as shown.
35 |
36 | In this example we retrieve the latest version of Node-RED from [https://nodered.org]().
37 | Using the inspector we can see the version is located in a `` tag with the
38 | class `node-red-latest-version`.
39 |
40 | The HTML node can be configured with the CSS selector
41 | `.node-red-latest-version` to return a message for each matching element.
42 |
43 | 
44 |
--------------------------------------------------------------------------------
/http/serve-json-content.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Serve JSON content
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - serve json
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to respond to an HTTP request with JSON data.
13 |
14 | ### Solution
15 |
16 | Set the `content-type` of the response to `application/json` using the `msg.headers`
17 | object.
18 |
19 | #### Example
20 |
21 | 
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"c8107088.37ef9","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-json","method":"get","swaggerDoc":"","x":120,"y":620,"wires":[["4e8237da.b17dc8"]]},{"id":"4e8237da.b17dc8","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{ \"Hello\": \"World\" }","x":290,"y":620,"wires":[["65401623.9abfe8"]]},{"id":"65401623.9abfe8","type":"change","z":"3045204d.cfbae","name":"Set Headers","rules":[{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.content-type","pt":"msg","to":"application/json","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":620,"wires":[["f7d3e35a.082c2"]]},{"id":"f7d3e35a.082c2","type":"http response","z":"3045204d.cfbae","name":"","x":610,"y":620,"wires":[]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ~~~text
31 | [~]$ curl -i http://localhost:1880/hello-json
32 | HTTP/1.1 200 OK
33 | X-Powered-By: Express
34 | Access-Control-Allow-Origin: *
35 | Content-Type: application/json; charset=utf-8
36 | Content-Length: 20
37 | ETag: W/"14-jgfjeX8FTECC4q5nXp6n5g"
38 | Date: Sat, 26 Nov 2016 23:07:50 GMT
39 | Connection: keep-alive
40 |
41 | { "Hello": "World" }
42 | ~~~
43 | {: .shell}
44 |
45 | ### Discussion
46 |
47 | The HTTP headers returned in the response can be set using the `msg.headers`
48 | property. It should be an object of key/value pairs for each header.
49 |
50 | To return well-formed JSON, the `Content-Type` header should be set to
51 | `application/json` so the receiver knows to handle it as JSON data.
52 |
--------------------------------------------------------------------------------
/basic/rate-limit-messages.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Slow down messages passing through a flow
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - rate limit
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to slow down the messages passing through a flow. For example,
13 | you have a message containing an array of values that you
14 | [split into a stream of messages](/basic/operate-on-array) and want to process
15 | each message in that stream at a rate of one per second.
16 |
17 | ### Solution
18 |
19 | Use a Delay node configured to rate limit the messages
20 | passing through it.
21 |
22 | #### Example
23 |
24 | {:width="615px"}
25 |
26 | {% raw %}
27 | ~~~json
28 | [{"id":"1fccc223.7ba87e","type":"inject","z":"ac14500e.2c57d","name":"Inject Array","topic":"","payload":"[0,1,2,3,4,5,6,7,8,9]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":1280,"wires":[["b2837466.e02a38"]]},{"id":"b2837466.e02a38","type":"split","z":"ac14500e.2c57d","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":250,"y":1280,"wires":[["bd97c8ed.a5c8d8"]]},{"id":"bd97c8ed.a5c8d8","type":"delay","z":"ac14500e.2c57d","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":390,"y":1280,"wires":[["bd66f03e.bdf0c"]]},{"id":"bd66f03e.bdf0c","type":"debug","z":"ac14500e.2c57d","name":"Debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":530,"y":1280,"wires":[]}]
29 | ~~~
30 | {: .flow}
31 | {% endraw %}
32 |
33 | ### Discussion
34 |
35 | The rate limiting mode of the Delay node can be used to
36 | change the rate of messages passing through it. It is configured with the desired
37 | number of messages to pass through the node per time interval. It will evenly
38 | spread the delivery of messages across the time period.
39 |
--------------------------------------------------------------------------------
/basic/map-between-different-number-ranges.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Map a property between different numeric ranges
4 | slug:
5 | - label: messages
6 | url: /#messages
7 | - map range
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to scale a number from one numeric range to another. For example, a
13 | sensor reading in the range 0 - 1023 should be mapped to a voltage range of 0 - 5.
14 |
15 | ### Solution
16 |
17 | Use the Range node to map between the defined ranges.
18 |
19 | #### Example
20 |
21 | {:width="616px"}
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"80dae67d.b4d8f8","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":380,"wires":[["81f13534.456348"]]},{"id":"81f13534.456348","type":"range","z":"535331d8.55c1f","minin":"0","maxin":"1023","minout":"0","maxout":"5","action":"clamp","round":false,"name":"","x":350,"y":420,"wires":[["e80b61d7.4b399"]]},{"id":"cb21de23.75a2f","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"512","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":420,"wires":[["81f13534.456348"]]},{"id":"342552de.255a1e","type":"inject","z":"535331d8.55c1f","name":"","topic":"","payload":"1023","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":460,"wires":[["81f13534.456348"]]},{"id":"e80b61d7.4b399","type":"debug","z":"535331d8.55c1f","name":"","active":true,"console":"false","complete":"false","x":550,"y":420,"wires":[]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | The Range node can be used to linearly scale between two
33 | different numeric ranges.
34 |
35 | By default, the result is not constrained to the range defined in the node. This means
36 | using the voltage example above, a value of 2046 would map to a result of 10.
37 |
38 | The node can be configured to constrain the result to the target range, or apply simple
39 | modulo arithmetic so the value wraps within the target range.
40 |
--------------------------------------------------------------------------------
/mqtt/receive-json.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Receive a parsed JSON message
4 | slug:
5 | - label: mqtt
6 | url: /#mqtt
7 | - subscribe json
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to receive a parsed JSON message from an MQTT broker.
13 |
14 | ### Solution
15 |
16 | Use the MQTT Input node and a JSON node to receive a parsed JSON message.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"8024cb4.98c5238","type":"mqtt in","z":"eda2a949.74ea98","name":"","topic":"sensors/#","qos":"2","broker":"61de5090.0f5d9","x":260,"y":580,"wires":[["b5098b7f.2361d8"]]},{"id":"15d727dd.33e808","type":"debug","z":"eda2a949.74ea98","name":"","active":true,"console":"false","complete":"false","x":530,"y":580,"wires":[]},{"id":"2aed678c.3de738","type":"mqtt out","z":"eda2a949.74ea98","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"false","broker":"61de5090.0f5d9","x":310,"y":520,"wires":[]},{"id":"3b613a69.a247c6","type":"inject","z":"eda2a949.74ea98","name":"temp json","topic":"","payload":"{\"sensor_id\":1234,\"temperature\":13}","payloadType":"json","repeat":"","crontab":"","once":false,"x":120,"y":520,"wires":[["2aed678c.3de738"]]},{"id":"b5098b7f.2361d8","type":"json","z":"eda2a949.74ea98","name":"","pretty":false,"x":390,"y":580,"wires":[["15d727dd.33e808"]]},{"id":"61de5090.0f5d9","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | ### Discussion
30 |
31 | The payload of an MQTT Input node is a string unless it was detected as a binary buffer. To parse the JSON string and convert it to a JavaScript Object, use the JSON node.
32 |
33 | Newer versions of the MQTT node (Node-RED version 0.19+) now have a select option to choose the required output format so the JSON node may no longer be required.
34 |
--------------------------------------------------------------------------------
/http/parse-json-response.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Get a parsed JSON Response
4 | slug:
5 | - label: http
6 | url: /#http-requests
7 | - parse json
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to return the JSON response of an HTTP request as a parsed Javascript object.
13 |
14 | ### Solution
15 |
16 | The HTTP Request node will return the body of a JSON response in the `msg.payload` as a string by default.
17 | Change the `Return` configuration of this node to `a parsed JSON object` to parse the JSON response in the `msg.payload` that
18 | can be easily accessed by downstream nodes.
19 |
20 | #### Example
21 |
22 | 
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"14c60a10.794df6","type":"http request","z":"c9a81b70.8abed8","name":"","method":"GET","ret":"obj","url":"https://jsonplaceholder.typicode.com/posts/{{post}}","tls":"","x":390,"y":500,"wires":[["b4ea8dd4.61a05"]]},{"id":"b4ea8dd4.61a05","type":"debug","z":"c9a81b70.8abed8","name":"","active":true,"console":"false","complete":"payload.title","x":570,"y":500,"wires":[]},{"id":"3479192a.04f016","type":"inject","z":"c9a81b70.8abed8","name":"post id","topic":"","payload":"2","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":500,"wires":[["e69250cf.368fd"]]},{"id":"e69250cf.368fd","type":"change","z":"c9a81b70.8abed8","name":"","rules":[{"t":"set","p":"post","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":230,"y":500,"wires":[["14c60a10.794df6"]]}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | We have reconfigured the flow from the [Set the URL of a Request URL recipe](set-request-url.html)
32 | by changing the HTTP Request node configuration. The Debug
33 | node has been modified to display only the `title` property of the parsed JSON response:
34 |
35 | {% raw %}
36 | ~~~text
37 | "qui est esse"
38 | ~~~
39 | {% endraw %}
40 |
41 | ### Discussion
42 |
43 | If your HTTP request returns XML, the XML node can be used to parse Javascript objects from XML documents.
44 |
--------------------------------------------------------------------------------
/http/handle-url-parameters.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Handle url parameters in an HTTP endpoint
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - url parameters
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to create a single HTTP endpoint that can handle requests where parts
13 | of the path are set per-request.
14 |
15 | For example, a single endpoint that can handle requests to both:
16 |
17 | http://example.com/hello-param/Nick
18 | http://example.com/hello-param/Dave
19 |
20 |
21 | ### Solution
22 |
23 | Use named path parameters in your HTTP In node's `URL`
24 | property and then access the specific value provided in a request using the
25 | `msg.req.params` property of the message.
26 |
27 | #### Flow
28 |
29 | 
30 |
31 | {% raw %}
32 | ~~~json
33 | [{"id":"ce53954b.31ac68","type":"http response","z":"3045204d.cfbae","name":"","x":490,"y":280,"wires":[]},{"id":"288a7c0.fd77584","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP request node.
18 |
19 | #### Example
20 |
21 | 
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"cb1dfcde.fd153","type":"function","z":"124f654c.7a7c6b","name":"set payload and headers","func":"msg.payload = \"data to post\";\nmsg.headers = {};\nmsg.headers['X-Auth-User'] = 'mike';\nmsg.headers['X-Auth-Key'] = 'fred-key';\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":275,"y":600,"wires":[["e44209e7.752698"]]},{"id":"dcf34aab.218928","type":"inject","z":"124f654c.7a7c6b","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"","payloadType":"date","x":85,"y":600,"wires":[["cb1dfcde.fd153"]]},{"id":"e44209e7.752698","type":"http request","z":"124f654c.7a7c6b","name":"post to HttpBin","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://httpbin.org/post","tls":"","persist":false,"proxy":"","authType":"","x":485,"y":600,"wires":[["ee306582.f0dde8"]]},{"id":"ee306582.f0dde8","type":"debug","z":"124f654c.7a7c6b","name":"","active":true,"console":"false","complete":"false","x":655,"y":600,"wires":[]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | In this example we set the `X-Auth-User` and `X-Auth-Key` request headers to call public HttpBin post test service.
31 |
32 | The code in the Function node below adds these additional message
33 | fields by adding a `msg.headers` object, and setting the header field/values in this object as shown.
34 |
35 | {% raw %}
36 | ~~~text
37 | msg.payload = "data to post";
38 | msg.headers = {};
39 | msg.headers['X-Auth-User'] = 'mike';
40 | msg.headers['X-Auth-Key'] = 'fred-key';
41 | return msg;
42 | ~~~
43 | {: .javascript}
44 | {% endraw %}
45 |
46 | These can be seen by expanding the debug object headers twistie - as the test service echos back the request.
47 |
--------------------------------------------------------------------------------
/basic/trigger-timeout.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Trigger a flow if a message isn’t received after a defined time
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - trigger timeout
8 | ---
9 |
10 | ### Problem
11 |
12 | You want a flow to be triggered if a message is not received after a defined time.
13 | For example, you expect to receive a sensor reading every 5 seconds and need to know
14 | if it fails to arrive.
15 |
16 | ### Solution
17 |
18 | Use the Trigger node to detect when a message has not
19 | arrived after a defined interval.
20 |
21 | #### Example
22 |
23 | {:width="555px"}
24 |
25 | {% raw %}
26 | ~~~json
27 | [{"id":"6ea53ad8.2362a4","type":"debug","z":"ac14500e.2c57d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":450,"y":1160,"wires":[]},{"id":"3da6946e.184a5c","type":"inject","z":"ac14500e.2c57d","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1160,"wires":[["38caaff4.03f6d","6ea53ad8.2362a4"]]},{"id":"38caaff4.03f6d","type":"trigger","z":"ac14500e.2c57d","op1":"","op2":"timeout","op1type":"nul","op2type":"str","duration":"5","extend":true,"units":"s","reset":"","bytopic":"all","name":"Watchdog","x":270,"y":1200,"wires":[["ae477709.016088"]]},{"id":"ae477709.016088","type":"debug","z":"ac14500e.2c57d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":450,"y":1200,"wires":[]}]
28 | ~~~
29 | {: .flow}
30 | {% endraw %}
31 |
32 | ### Discussion
33 |
34 | In the example flow, the top branch represents the normal flow of the messages.
35 | They also get passed to the Trigger node on a second
36 | branch of the flow.
37 |
38 | The Trigger node is configured to initially send nothing,
39 | then to wait for 5 seconds before sending a `"timeout"` message. The option to
40 | extend the delay if new messages arrive is also selected. This means as long as
41 | messages continue to arrive, the node will not do anything. Once 5 seconds passes
42 | after the last message to arrive, it will send on the `"timeout"` message.
43 |
--------------------------------------------------------------------------------
/mqtt/connect-to-broker.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Connect to an MQTT Broker
4 | slug:
5 | - label: mqtt
6 | url: /#mqtt
7 | - connect
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to connect to an MQTT broker running locally.
13 |
14 | ### Solution
15 |
16 | Use the MQTT Input input or MQTT Output node
17 | and an associated MQTT Config node to connect to an MQTT broker.
18 |
19 | #### Example
20 |
21 | 
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"2c6873d2.992abc","type":"mqtt out","z":"eda2a949.74ea98","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"","broker":"407a01e4.6b637","x":330,"y":80,"wires":[]},{"id":"d9beed59.94155","type":"inject","z":"eda2a949.74ea98","name":"","topic":"","payload":"22","payloadType":"num","repeat":"","crontab":"","once":false,"x":150,"y":80,"wires":[["2c6873d2.992abc"]]},{"id":"be80048.8f232f8","type":"mqtt in","z":"eda2a949.74ea98","name":"","topic":"sensors/livingroom/temp","qos":"2","broker":"407a01e4.6b637","x":170,"y":160,"wires":[["8640b8ff.f82ff8"]]},{"id":"8640b8ff.f82ff8","type":"debug","z":"eda2a949.74ea98","name":"","active":true,"console":"false","complete":"false","x":370,"y":160,"wires":[]},{"id":"407a01e4.6b637","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | Many users will run an MQTT broker such as [mosquitto](http://mosquitto.org) on
33 | the same Raspberry Pi or PC that Node-RED is running on. Once you have an
34 | MQTT input or output node in your flow, you create an
35 | MQTT Config node by double clicking on the node, then clicking on the pencil button to the right of the `Add an MQTT broker...` dropdown. Assuming your broker is open,
36 | set the server host to `localhost` and leave the port set to `1883`.
37 |
38 | To connect to non-local, secured brokers, other MQTT Config
39 | node options will need to be set according to your broker's connectivity requirements.
40 |
--------------------------------------------------------------------------------
/basic/convert-yaml.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Convert to/from YAML
4 | slug:
5 | - label: formats
6 | url: /#working-with-data-formats
7 | - yaml
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to convert a message property between a YAML string and the JavaScript object
13 | it represents.
14 |
15 | ### Solution
16 |
17 | The YAML node can be used to convert between the two
18 | formats.
19 |
20 | #### Example
21 |
22 | {:width="682px"}
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"f231967.0251a68","type":"inject","z":"64133d39.bb0394","name":"YAML String","topic":"","payload":"{\"a\":1}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":320,"wires":[["a0110756.ecfa48"]]},{"id":"8f8f31b7.1f916","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":320,"wires":[]},{"id":"5138ba3.c972444","type":"inject","z":"64133d39.bb0394","name":"Object","topic":"","payload":"{\"a\":1, \"b\":[1,2,3]}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":360,"wires":[["2fa653cc.60d3dc"]]},{"id":"50f2f4c.4a6e60c","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":430,"y":360,"wires":[]},{"id":"a0110756.ecfa48","type":"template","z":"64133d39.bb0394","name":"","field":"payload","fieldType":"msg","format":"yaml","syntax":"plain","template":"a: 1\nb:\n - 1\n - 2\n - 3","output":"str","x":280,"y":320,"wires":[["104b80e2.51068f"]]},{"id":"2fa653cc.60d3dc","type":"yaml","z":"64133d39.bb0394","property":"payload","name":"","x":250,"y":360,"wires":[["50f2f4c.4a6e60c"]]},{"id":"104b80e2.51068f","type":"yaml","z":"64133d39.bb0394","property":"payload","name":"","x":430,"y":320,"wires":[["8f8f31b7.1f916"]]}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ### Discussion
32 |
33 | In the example, the first flow injects the YAML:
34 |
35 | ~~~yaml
36 | a: 1
37 | b:
38 | - 1
39 | - 2
40 | - 3
41 | ~~~
42 |
43 | The YAML node then converts it to the equivalent JavaScript
44 | object.
45 |
46 | The second flow does the reverse, injecting the object `{ a: 1, b: [1,2,3] }`
47 | and converting it to YAML.
48 |
--------------------------------------------------------------------------------
/basic/convert-json.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Convert to/from JSON
4 | slug:
5 | - label: formats
6 | url: /#working-with-data-formats
7 | - json
8 |
9 | ---
10 |
11 | ### Problem
12 |
13 | You want to convert a message property between a JSON string and the JavaScript object
14 | it represents.
15 |
16 | ### Solution
17 |
18 | The JSON node can be used to convert between the two
19 | formats.
20 |
21 | #### Example
22 |
23 | {:width="534px"}
24 |
25 | {% raw %}
26 | ~~~json
27 | [{"id":"634256b7.2d6818","type":"inject","z":"64133d39.bb0394","name":"JSON String","topic":"","payload":"{\"a\":1}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":80,"wires":[["a2fe0fc8.095e1"]]},{"id":"a2fe0fc8.095e1","type":"json","z":"64133d39.bb0394","name":"","property":"payload","action":"","pretty":false,"x":270,"y":80,"wires":[["9a4ce2b8.47698"]]},{"id":"9a4ce2b8.47698","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":430,"y":80,"wires":[]},{"id":"80032e2.7c92cd","type":"inject","z":"64133d39.bb0394","name":"Object","topic":"","payload":"{\"a\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":120,"wires":[["cd40a0f4.4f5ac"]]},{"id":"cd40a0f4.4f5ac","type":"json","z":"64133d39.bb0394","name":"","property":"payload","action":"","pretty":false,"x":270,"y":120,"wires":[["478b4106.4fd7c"]]},{"id":"478b4106.4fd7c","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":430,"y":120,"wires":[]}]
28 | ~~~
29 | {: .flow}
30 | {% endraw %}
31 |
32 | ### Discussion
33 |
34 | In the example, the first flow injects the JSON string `'{"a":1}'` which the
35 | JSON node converts to the equivalent JavaScript object.
36 |
37 | The second flow does the reverse, injecting the object `{ a: 1 }` and converting
38 | it to JSON.
39 |
40 | The JSON will, by default, detect what it is being given
41 | to convert. It can also be configured to ensure the property is a given type. For
42 | example if your flow could receive either JSON or an Object, the JSON
43 | node can be configured to ensure the property is an Object.
44 |
--------------------------------------------------------------------------------
/http/post-form-data-to-a-flow.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Post form data to a flow
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - post form data
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to post form data in to a flow.
13 |
14 | ### Solution
15 |
16 | Use the HTTP In node to listen for POST requests that
17 | have their `Content-Type` set to `application/x-www-form-urlencoded` and access
18 | the form data as properties of `msg.payload`.
19 |
20 | #### Example
21 |
22 | 
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"5b98a8ac.a46758","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-form","method":"post","swaggerDoc":"","x":120,"y":820,"wires":[["bba61009.4459f"]]},{"id":"bba61009.4459f","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP In node receives such a request, it
69 | parses the body of the request and makes the form data available under
70 | `msg.payload`:
71 |
72 | ~~~javascript
73 | var name = msg.payload.name;
74 | ~~~
75 |
--------------------------------------------------------------------------------
/http/set-query-string.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Set the query string parameters in a URL
4 | slug:
5 | - label: http
6 | url: /#http-requests
7 | - set query string
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to set the query string parameters of a URL for an HTTP request.
13 |
14 | ### Solution
15 |
16 | Use the HTTP Request node's support for [mustache](http://mustache.github.io/mustache.5.html) to substitute query parameter strings in URLs directly.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"e95c6faa.ab2e1","type":"http request","z":"c9a81b70.8abed8","name":"","method":"GET","ret":"txt","url":"https://query.yahooapis.com/v1/public/yql?q={{{query}}}&format=json","tls":"","x":470,"y":420,"wires":[["7cf30700.5bc978"]]},{"id":"7cf30700.5bc978","type":"debug","z":"c9a81b70.8abed8","name":"","active":true,"console":"false","complete":"payload","x":630,"y":420,"wires":[]},{"id":"637d3c55.eb3084","type":"inject","z":"c9a81b70.8abed8","name":"query parameter","topic":"","payload":"select astronomy.sunset from weather.forecast where woeid in (select woeid from geo.places(1) where text=\"maui, hi\")","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":420,"wires":[["b001d489.d8f818"]]},{"id":"b001d489.d8f818","type":"change","z":"c9a81b70.8abed8","name":"","rules":[{"t":"set","p":"query","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":420,"wires":[["e95c6faa.ab2e1"]]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | The Inject node generates a query string that is to be sent in the URL. The Change node changes this to `msg.query` which is substituted in the mustache template in the HTTP Request node URL property configured as shown:
30 |
31 | {% raw %}
32 | ~~~text
33 | https://query.yahooapis.com/v1/public/yql?q={{{query}}}&format=json
34 | ~~~
35 | {% endraw %}
36 |
37 | The returned JSON content is the sunset in Hawaii:
38 |
39 | {% raw %}
40 | ~~~text
41 | "{"query":{"count":1,"created":"2017-01-22T01:31:07Z","lang":"en-US","results":{"channel":{"astronomy":{"sunset":"6:9 pm"}}}}}"
42 | ~~~
43 | {% endraw %}
44 |
45 |
46 | #### Discussion
47 |
48 | By default, mustache will escape any HTML entities in the values it substitutes. To ensure HTML escaping is not used in your URL use `{% raw %}{{{triple}}}{% endraw %}` braces.
49 |
--------------------------------------------------------------------------------
/_includes/toc-footer.html:
--------------------------------------------------------------------------------
1 |
2 |
84 |
--------------------------------------------------------------------------------
/basic/parse-csv.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Parse CSV input
4 | slug:
5 | - label: formats
6 | url: /#working-with-data-formats
7 | - csv
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to parse CSV data to work with the values it contains.
13 |
14 | ### Solution
15 |
16 | The CSV node can be used to parse CSV and generate
17 | JavaScript objects from it.
18 |
19 |
20 | #### Example
21 |
22 | {:width="660px"}
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"73e4e16.4d9742","type":"inject","z":"64133d39.bb0394","name":"Inject","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":780,"wires":[["2bef78fd.ae70f8"]]},{"id":"90ed51dc.dcc71","type":"csv","z":"64133d39.bb0394","name":"","sep":",","hdrin":true,"hdrout":false,"multi":"mult","ret":"\\n","temp":"","skip":"1","x":410,"y":780,"wires":[["9aace6e7.adc538"]]},{"id":"9aace6e7.adc538","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":570,"y":780,"wires":[]},{"id":"2bef78fd.ae70f8","type":"template","z":"64133d39.bb0394","name":"CSV data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"# This is some random data\na,b,c\n80,18,2\n52,36,10\n91,18,61\n32,47,65","output":"str","x":260,"y":780,"wires":[["90ed51dc.dcc71"]]}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ### Discussion
32 |
33 | In the example, the flow injects a payload containing CSV data:
34 |
35 | ```javascript
36 | # This is some random data
37 | a,b,c
38 | 80,18,2
39 | 52,36,10
40 | 91,18,61
41 | 32,47,65
42 | ```
43 |
44 | The CSV has been configured to ignore the first line of
45 | the input so it ignores the initial comment line. It then uses the next line to
46 | get the column names, and the remaining rows for the data.
47 |
48 |
49 | In this particular example, the node has also been configured to send a single
50 | message with all of the data. This results in a message with the payload:
51 |
52 | ```javascript
53 | [
54 | { a: 80, b: 18, c: 2},
55 | { a: 52, b: 36, c: 10},
56 | { a: 91, b: 18, c: 61},
57 | { a: 32, b: 47, c: 65},
58 | ]
59 | ```
60 |
61 | It is also possible to configure the node to emit one message for each row of data.
62 | In this mode, the messages will also include the `msg.parts` property that allows
63 | them to be passed to a Join node to reassemble them back
64 | into a single array.
65 |
--------------------------------------------------------------------------------
/http/create-an-http-endpoint.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Create an HTTP Endpoint
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - create endpoint
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to create an HTTP endpoint that responds to GET requests with some static
13 | content, such as an HTML page or CSS stylesheet.
14 |
15 | ### Solution
16 |
17 | Use the HTTP In node to listen for requests, a
18 | Template node to include the static content, and an
19 | HTTP Response node to reply to the request.
20 |
21 | #### Example
22 |
23 | 
24 |
25 | {% raw %}
26 | ~~~json
27 | [{"id":"59ff2a1.fa600d4","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello","method":"get","swaggerDoc":"","x":100,"y":80,"wires":[["54c1e70d.ab3e18"]]},{"id":"54c1e70d.ab3e18","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n HTTP In and HTTP Response
46 | pair of nodes are the starting point for all HTTP endpoints you create.
47 |
48 | Any flow that starts with an HTTP In node must have a
49 | path to an HTTP Response node otherwise requests will
50 | eventually timeout.
51 |
52 | The HTTP Response node uses the `payload` property of
53 | messages it receives as the body of the response. Other properties can be used to
54 | further customize the response - they are covered in other recipes.
55 |
56 | The Template node provides a convenient way to embed
57 | a body of content into a flow. It may be desirable to maintain such static content
58 | outside of the flow.
59 |
60 | If you have turned on http authentication then you may need add your userid and password
61 | to the curl command. e.g.
62 |
63 | ~~~text
64 | [~]$ curl -u userid:password http://localhost:1880/hello
65 | ~~~
--------------------------------------------------------------------------------
/http/set-request-url-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Set the URL of a request using a template
4 | slug:
5 | - label: http
6 | url: /#http-requests
7 | - set url
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to dynamically set the URL of an HTTP request where only parts of the url change between requests.
13 |
14 | ### Solution
15 |
16 | Configure the HTTP Request node to generate a URL dynamically using a [mustache](http://mustache.github.io/mustache.5.html) URL template.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"41747a17.54ffd4","type":"http request","z":"c9a81b70.8abed8","name":"","method":"GET","ret":"txt","url":"https://jsonplaceholder.typicode.com/posts/{{post}}","tls":"","x":550,"y":480,"wires":[["d682318c.36823"]]},{"id":"d682318c.36823","type":"debug","z":"c9a81b70.8abed8","name":"","active":true,"console":"false","complete":"payload","x":710,"y":480,"wires":[]},{"id":"90bfea22.dd2b98","type":"inject","z":"c9a81b70.8abed8","name":"post id","topic":"","payload":"2","payloadType":"str","repeat":"","crontab":"","once":false,"x":250,"y":480,"wires":[["e67a0cc.596d4f"]]},{"id":"e67a0cc.596d4f","type":"change","z":"c9a81b70.8abed8","name":"","rules":[{"t":"set","p":"post","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":480,"wires":[["41747a17.54ffd4"]]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | In this flow, the Inject node sends an id for a post we would like to request from an API. The Change node changes this to `msg.post`. The HTTP Request node generates a URL by substituting `msg.post` of the URL property configured as shown:
30 |
31 | {% raw %}
32 | ~~~text
33 | https://jsonplaceholder.typicode.com/posts/{{post}}
34 | ~~~
35 | {% endraw %}
36 |
37 | The JSON output from this API in the debug panel will look as follows:
38 |
39 | {% raw %}
40 | ~~~text
41 | {
42 | "userId": 1,
43 | "id": 2,
44 | "title": "qui est esse",
45 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
46 | }
47 | ~~~
48 | {% endraw %}
49 |
50 | ### Discussion
51 |
52 | By default, mustache will escape any HTML entities in the values it substitutes. To ensure HTML escaping is not used in your URL use `{% raw %}{{{triple}}}{% endraw %}` braces.
53 |
--------------------------------------------------------------------------------
/basic/retry-on-error.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Automatically retry an action after an error
4 | slug:
5 | - label: error handling
6 | url: /#error-handling
7 | - retry
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to retry an action after an error is thrown.
13 |
14 | ### Solution
15 |
16 | Use the Catch node to receive the error and connect it
17 | back to the node that needs to retry the action.
18 |
19 | #### Example
20 |
21 | {:width="610px"}
22 |
23 | {% raw %}
24 | ~~~json
25 | [{"id":"27e61f12.c1a15","type":"inject","z":"fc046f99.4be08","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":320,"wires":[["d7d08440.31b678"]]},{"id":"d7d08440.31b678","type":"function","z":"fc046f99.4be08","name":"Random error","func":"// Randomly throw an error rather than\n// pass on message.\nif (Math.random() < 0.5) {\n node.error(\"a random error\", msg);\n} else {\n return msg;\n}","outputs":1,"noerr":0,"x":320,"y":320,"wires":[["f22b1e9a.5d89b"]]},{"id":"f22b1e9a.5d89b","type":"debug","z":"fc046f99.4be08","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":320,"wires":[]},{"id":"2166290d.98d736","type":"delay","z":"fc046f99.4be08","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":240,"y":380,"wires":[["d7d08440.31b678"]]},{"id":"139b836e.7950ed","type":"catch","z":"fc046f99.4be08","name":"","scope":["d7d08440.31b678"],"uncaught":false,"x":90,"y":380,"wires":[["2166290d.98d736","9c8ab214.0ecaa"]]},{"id":"9c8ab214.0ecaa","type":"debug","z":"fc046f99.4be08","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"error","targetType":"msg","x":240,"y":440,"wires":[]}]
26 | ~~~
27 | {: .flow}
28 | {% endraw %}
29 |
30 | ### Discussion
31 |
32 | Some errors are transitory and an action simply needs to be retried in order to succeed.
33 | Alternatively, there may be some remedial action needed before retrying.
34 |
35 | In the example flow, a Function simulates a random
36 | error - there is a 50% chance it will throw an error rather than pass on the message.
37 |
38 | The Catch receives the error which passes the message
39 | back to the Function node to retry. It also includes
40 | a Delay node as, in some circumstances, it is suitable
41 | to wait for a short interval before retrying.
42 |
--------------------------------------------------------------------------------
/http/include-data-from-another-flow.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Include data captured in another flow
4 | slug:
5 | - label: http
6 | url: /#http-endpoints
7 | - context
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to respond to an HTTP request using data captured by another flow.
13 |
14 | ### Solution
15 |
16 | Store data using `flow context` so that it can be retrieved within the HTTP flow.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"92eaf6c0.6d1508","type":"inject","z":"3045204d.cfbae","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":100,"y":480,"wires":[["8055b557.7faa48"]]},{"id":"8055b557.7faa48","type":"change","z":"3045204d.cfbae","name":"Store time","rules":[{"t":"set","p":"timestamp","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":480,"wires":[[]]},{"id":"93bf2335.6c40e","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-data","method":"get","swaggerDoc":"","x":120,"y":520,"wires":[["9e3aa25e.61c56"]]},{"id":"9e3aa25e.61c56","type":"change","z":"3045204d.cfbae","name":"Copy time","rules":[{"t":"set","p":"timestamp","pt":"msg","to":"timestamp","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":520,"wires":[["f2c385a.f0d3c78"]]},{"id":"f2c385a.f0d3c78","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n Inject
49 | node into `flow context` using a Change node. The flow
50 | that handles the HTTP request then uses another Change node
51 | to retrieve the value, attaching it to the message which is then passed to a
52 | Template node to generate the response.
53 |
--------------------------------------------------------------------------------
/basic/operate-on-array.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Perform an operation on each element in an array
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - operate on array
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to perform an operation on every element in an array. For example,
13 | given an array of numbers, you want to round each value to the nearest integer.
14 |
15 | ### Solution
16 |
17 | The Split node can be used to send a message for every
18 | element in the array. It can be followed by the nodes needed to operate on the
19 | individual elements, followed by a Join node to recombine
20 | them back into a single array.
21 |
22 | #### Example
23 |
24 | {:width="645px"}
25 |
26 | {% raw %}
27 | ~~~json
28 | [{"id":"3149f240.c0e25e","type":"inject","z":"ac14500e.2c57d","name":"Array of decimals","topic":"","payload":"[1.67,2.98,3.12,4.99,5.50]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":960,"wires":[["bd57baa6.00f998"]]},{"id":"bd57baa6.00f998","type":"split","z":"ac14500e.2c57d","name":"Split array","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":200,"y":1020,"wires":[["7ab9e9ed.d514b8"]]},{"id":"7ab9e9ed.d514b8","type":"range","z":"ac14500e.2c57d","minin":"0","maxin":"10","minout":"0","maxout":"10","action":"scale","round":true,"property":"payload","name":"Round value","x":350,"y":1020,"wires":[["f26660ab.007b3"]]},{"id":"f26660ab.007b3","type":"join","z":"ac14500e.2c57d","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":490,"y":1020,"wires":[["f9b5abac.f13828"]]},{"id":"f9b5abac.f13828","type":"debug","z":"ac14500e.2c57d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":550,"y":1080,"wires":[]}]
29 | ~~~
30 | {: .flow}
31 | {% endraw %}
32 |
33 | ### Discussion
34 |
35 | In other programming environments, this task would be accomplished by creating a loop
36 | over the elements of the array.
37 |
38 | In Node-RED, the way to achieve the same thing is to turn the single message containing
39 | the array into a stream of messages that can be processed individually and finally
40 | recombine them back into one message.
41 |
42 | The Split/Join node pair are
43 | commonly used together to achieve this. The Split node
44 | adds the `msg.parts` property to each message in the stream which allows the
45 | Join node to properly reassemble the original message.
46 |
--------------------------------------------------------------------------------
/styleguide.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Cookbook Style Guide
4 | lcb: "{"
5 | ---
6 |
7 | The cookbook recipes are intended to be task-focused guides to solving specific
8 | problems.
9 |
10 | They should follow a standard structure. Lines beginning with `>` are comments
11 | that should be removed:
12 |
13 | ~~~~~markdown
14 | ---
15 | layout: default
16 | title: A short (<10 words) summary of the task addressed
17 | ---
18 |
19 | ### Problem
20 | > A description of the problem solved by this recipe. It should be phrased as:
21 | You want to do X.
22 |
23 | ### Solution
24 | > A description of the solution (the 'how') without going into too much detail (the 'why').
25 | Use the Inject node to do X.
26 |
27 | #### Example
28 | > The recipe should provide an example of the solution to illustrate it in action.
29 |
30 | 
31 |
32 | > Paste a sample flow json that can be imported by the reader
33 | {{ page.lcb }}% raw %}
34 | ~~~json
35 | [{"id":"7c87b536.83784c","type":"inject","z":"55635136.aa9cb","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":100,"y":80,"wires":[["7de918a6.8216e8"]]}]
36 | ~~~
37 | {: .flow}
38 | {{ page.lcb }}% endraw %}
39 |
40 | > If the recipe can be meaningfully demonstrated in action via static text, add it here.
41 |
42 | ### Discussion
43 | > A more detailed discussion of the solution and additional relevant information
44 | > that will help the reader apply it to their own scenario.
45 | The Inject node code can be configured to do X. This
46 | means it can...
47 |
48 | ~~~~~
49 |
50 | The following styles should be used consistently.
51 |
52 | #### Message properties
53 |
54 | Message properties should be enclosed in back-ticks:
55 |
56 | ~~~~~markdown
57 | Use the `msg.payload` property to ...
58 | ~~~~~
59 |
60 | #### Node types
61 |
62 | When a specific node type is mentioned, it should be styled as:
63 |
64 | ~~~~~markdown
65 | Use the HTTP In node to ...
66 | ~~~~~
67 |
68 | #### Example flows
69 |
70 | ~~~~~markdown
71 | {{ page.lcb }}% raw %}
72 | ~~~json
73 | > insert flow json here. It should be minified and on a single line.
74 | ~~~
75 | {: .flow}
76 | {{ page.lcb }}% endraw %}
77 | ~~~~~
78 |
79 | #### Terminal output
80 |
81 | ~~~~~markdown
82 | ~~~text
83 | [~]$ date
84 | Mon 28 Nov 2016 10:55:48 GMT
85 | ~~~
86 | {: .shell}
87 | ~~~~~
88 |
89 | #### JavaScript samples
90 |
91 | ~~~~~markdown
92 | ~~~javascript
93 | var name = msg.payload.name;
94 | ~~~
95 | ~~~~~
96 |
97 | #### JSON samples
98 |
99 | ~~~~~markdown
100 | ~~~json
101 | {
102 | "name": "Nick"
103 | }
104 | ~~~
105 | ~~~~~
106 |
--------------------------------------------------------------------------------
/basic/route-on-property.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Route a message based on one of its properties
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - route on property
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to route a message to different flows according to the value of the
13 | `msg.topic` property. For example, you have an MQTT node
14 | subscribed to multiple sensors and you want to pass the messages to different
15 | Dashboard ui_gauge nodes.
16 |
17 | ### Solution
18 |
19 | Use the Switch node to check the value of the property
20 | against different values corresponding to different outputs of the node.
21 |
22 | #### Example
23 |
24 | {:width="601px"}
25 |
26 | {% raw %}
27 | ~~~json
28 | [{"id":"3bc8e1d2.744abe","type":"switch","z":"ac14500e.2c57d","name":"Route ","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"temperature","vt":"str"},{"t":"eq","v":"humidity","vt":"str"},{"t":"eq","v":"pressure","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":330,"y":420,"wires":[["907bf3b8.def45"],["fe425938.926838"],["ec261304.52f73"]]},{"id":"be3da36c.1c142","type":"inject","z":"ac14500e.2c57d","name":"","topic":"temperature","payload":"27","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":380,"wires":[["3bc8e1d2.744abe"]]},{"id":"f271ceef.172b3","type":"inject","z":"ac14500e.2c57d","name":"","topic":"humidity","payload":"45","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":420,"wires":[["3bc8e1d2.744abe"]]},{"id":"907bf3b8.def45","type":"debug","z":"ac14500e.2c57d","name":"Temperature","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":510,"y":380,"wires":[]},{"id":"fe425938.926838","type":"debug","z":"ac14500e.2c57d","name":"Humidity","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":500,"y":420,"wires":[]},{"id":"ec261304.52f73","type":"debug","z":"ac14500e.2c57d","name":"Pressure","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":500,"y":460,"wires":[]},{"id":"fca957dd.9d8078","type":"inject","z":"ac14500e.2c57d","name":"","topic":"pressure","payload":"1001","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":460,"wires":[["3bc8e1d2.744abe"]]}]
29 | ~~~
30 | {: .flow}
31 | {% endraw %}
32 |
33 | ### Discussion
34 |
35 | The Switch node will send on messages it receives on the
36 | outputs that corresponding to rules that match.
37 |
38 | It can be configured to send on all rules that match, or only on the first one that
39 | matches.
40 |
--------------------------------------------------------------------------------
/basic/split-text.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Split text into one message per line
4 | slug:
5 | - label: formats
6 | url: /#working-with-data-formats
7 | - text
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to perform an operation on every line in a block text. For example,
13 | you want to add the line number to the beginning of each line.
14 |
15 | ### Solution
16 |
17 | The Split node can be used to split the message into
18 | one message per line. It can be followed by the nodes needed to operate on the
19 | individual lines of text, followed by a Join node to
20 | recombine them back into a single block of text.
21 |
22 |
23 | #### Example
24 |
25 | {:width="717px"}
26 |
27 | {% raw %}
28 | ~~~json
29 | [{"id":"df6514f0.029748","type":"inject","z":"64133d39.bb0394","name":"inject","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":"","x":110,"y":900,"wires":[["11f53f61.2f7be1"]]},{"id":"11f53f61.2f7be1","type":"template","z":"64133d39.bb0394","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"one\ntwo\nthree\nfour\nfive","x":240,"y":900,"wires":[["760c1d71.c29744"]]},{"id":"760c1d71.c29744","type":"split","z":"64133d39.bb0394","name":"","splt":"\\n","x":190,"y":960,"wires":[["3e427aac.9b9596"]]},{"id":"3e427aac.9b9596","type":"change","z":"64133d39.bb0394","name":"Prepend line number","rules":[{"t":"set","p":"payload","pt":"msg","to":"(parts.index+1) & \": \" & payload","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":960,"wires":[["d44d4767.945fd8"]]},{"id":"d44d4767.945fd8","type":"join","z":"64133d39.bb0394","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","timeout":"","count":"","x":530,"y":960,"wires":[["bfe3e43b.85fa88"]]},{"id":"bfe3e43b.85fa88","type":"debug","z":"64133d39.bb0394","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":650,"y":960,"wires":[]}]
30 | ~~~
31 | {: .flow}
32 | {% endraw %}
33 |
34 | ### Discussion
35 |
36 | In the example, the Inject and Template
37 | nodes are used to inject a block of text with multiple lines.
38 |
39 | ~~~text
40 | one
41 | two
42 | three
43 | four
44 | five
45 | ~~~
46 |
47 | The Split node's default behaviour when passed a string
48 | is to split it into one message per line.
49 |
50 | The Change node modifies each message payload using
51 | a JSONata expression: `(parts.index+1) & ": " & payload` - which uses `msg.parts.index`
52 | to get the line number and prepends it to the existing `msg.payload`.
53 |
54 | Finally the Join node reassembles the messages into
55 | a single block of text:
56 |
57 | ~~~text
58 | 1: one
59 | 2: two
60 | 3: three
61 | 4: four
62 | 5: five
63 | ~~~
64 |
--------------------------------------------------------------------------------
/http/set-request-url.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Set the URL of a request
4 | slug:
5 | - label: http
6 | url: /#http-requests
7 | - set url
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to set the URL of an HTTP request node dynamically.
13 |
14 | ### Solution
15 |
16 | Set the URL property of the HTTP Request node.
17 |
18 | #### Example
19 |
20 | 
21 |
22 | {% raw %}
23 | ~~~json
24 | [{"id":"b36aa30.3a7276","type":"http request","z":"c9a81b70.8abed8","name":"","method":"GET","ret":"txt","url":"","x":470,"y":300,"wires":[["1ef9987c.956c78"]]},{"id":"11167f67.5d5031","type":"inject","z":"c9a81b70.8abed8","name":"cars on craigslist","topic":"","payload":"http://vancouver.craigslist.org/search/sss?format=rss&query=cars","payloadType":"str","repeat":"","crontab":"","once":false,"x":140,"y":300,"wires":[["70154cd4.de1444"]]},{"id":"70154cd4.de1444","type":"change","z":"c9a81b70.8abed8","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":300,"wires":[["b36aa30.3a7276"]]},{"id":"1ef9987c.956c78","type":"debug","z":"c9a81b70.8abed8","name":"","active":true,"console":"false","complete":"false","x":630,"y":300,"wires":[]}]
25 | ~~~
26 | {: .flow}
27 | {% endraw %}
28 |
29 | The Inject node generates a string URL, and the Change node sets the msg.url property. In this flow the URL is set to:
30 |
31 | {% raw %}
32 | ~~~text
33 | http://vancouver.craigslist.org/search/sss?format=rss&query=cars
34 | ~~~
35 | {% endraw %}
36 |
37 | To return an RSS feed for cars for sale in Vancouver on Craigslist. It returns something like the following XML content in the debug window:
38 |
39 | {% raw %}
40 | ~~~text
41 |
42 |
43 | XML node can be added after the HTTP Request to change the XML RSS content returned to a JavaScript object for easy access to the data.
71 |
--------------------------------------------------------------------------------
/basic/join-streams.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Create a single message from separate streams of messages
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - join streams
8 | ---
9 |
10 | ### Problem
11 |
12 | You have messages arriving from different sources that you need to combine into
13 | a single message.
14 |
15 | For example, you have three different sensors publishing values and you want to
16 | insert them into a database as a single entry.
17 |
18 | ### Solution
19 |
20 | Give each stream a unique `msg.topic` value and use the Join
21 | node to group them into a single message.
22 |
23 | #### Example
24 |
25 | {:width="571px"}
26 |
27 | {% raw %}
28 | ~~~json
29 | [{"id":"8ccddb9a.a55f38","type":"inject","z":"ac14500e.2c57d","name":"temperature","topic":"temperature","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":1760,"wires":[["47b769c5.cb0e28"]]},{"id":"47b769c5.cb0e28","type":"join","z":"ac14500e.2c57d","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"3","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":310,"y":1800,"wires":[["f9afb265.b11b7"]]},{"id":"f9afb265.b11b7","type":"debug","z":"ac14500e.2c57d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":470,"y":1800,"wires":[]},{"id":"2d269127.4f04ce","type":"inject","z":"ac14500e.2c57d","name":"humidity","topic":"humidity","payload":"","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1800,"wires":[["47b769c5.cb0e28"]]},{"id":"d6fbe805.0e4628","type":"inject","z":"ac14500e.2c57d","name":"pressure","topic":"pressure","payload":"999","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1840,"wires":[["47b769c5.cb0e28"]]}]
30 | ~~~
31 | {: .flow}
32 | {% endraw %}
33 |
34 | ### Discussion
35 |
36 | In the example flow, each Inject node represents a
37 | different source of messages. They each set a unique `msg.topic` value so they
38 | can be identified later in the flow.
39 |
40 | The Join node has been configured in manual mode to
41 | create a key/value object using `msg.topic` as the key name. As we know there
42 | are three separate streams of messages to join, the node has been to configure to
43 | send on a message when it receives that number of parts.
44 |
45 | This means it will send on a message each time it receives at least one message
46 | from three different topics - using the most recent value from each topic.
47 |
48 | ```json
49 | {
50 | "temperature":10,
51 | "humidity":0,
52 | "pressure":999
53 | }
54 | ```
55 |
56 | The node has further options to change its behaviour that have not been used in
57 | this recipe. For example, a timeout can be set to ensure it sends *something*
58 | in case one of the sensors stops sending values. If that is a concern, you may
59 | consider [this recipe](/basic/trigger-placeholder) for providing a placeholder
60 | value.
61 |
--------------------------------------------------------------------------------
/basic/trigger-placeholder.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Send placeholder messages when a stream stops sending
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - trigger placeholder
8 | ---
9 |
10 | ### Problem
11 |
12 | You have a stream of messages coming from a sensor at regular intervals. If the
13 | sensor stops sending messages, you want to send placeholder messages at the same
14 | rate.
15 |
16 | For example, the sensor data may be feeding a Dashboard chart. If the sensor
17 | stops sending, the chart will stop updating. So placeholder messages are needed
18 | for the chart to update with a `0` value to highlight the sensor has stopped.
19 |
20 | ### Solution
21 |
22 | Use the Trigger node to detect when a message has not
23 | arrived after a defined interval and a second Trigger node
24 | to send the placeholder messages at a regular interval.
25 |
26 | #### Example
27 |
28 | {:width="711px"}
29 |
30 | {% raw %}
31 | ~~~json
32 | [{"id":"9ccdf268.c96ff","type":"inject","z":"ac14500e.2c57d","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1660,"wires":[["38950a5.28d15f6","2c532f67.0330e"]]},{"id":"38950a5.28d15f6","type":"debug","z":"ac14500e.2c57d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":1660,"wires":[]},{"id":"2c532f67.0330e","type":"trigger","z":"ac14500e.2c57d","op1":"reset","op2":"true","op1type":"str","op2type":"bool","duration":"2","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":260,"y":1700,"wires":[["e4e42b96.97a338"]]},{"id":"e4e42b96.97a338","type":"trigger","z":"ac14500e.2c57d","op1":"0","op2":"0","op1type":"num","op2type":"str","duration":"-2","extend":false,"units":"s","reset":"reset","bytopic":"all","name":"","x":420,"y":1700,"wires":[["38950a5.28d15f6"]]}]
33 | ~~~
34 | {: .flow}
35 | {% endraw %}
36 |
37 | ### Discussion
38 |
39 | In the example flow, the top branch represents the normal flow of the messages,
40 | from the Inject node to the Debug
41 | node.
42 |
43 | The messages also get passed to the first Trigger node
44 | on a second branch of the flow. That node is configured to initially send a payload
45 | of `"reset"`, then to wait for 2 seconds before sending a timeout message. The
46 | option to extend the delay if new messages arrive is also selected. This means
47 | as long as messages continue to arrive, the node will not do anything. Once 2
48 | seconds passes after the last message to arrive, it will send on the timeout message.
49 |
50 | The timeout message feeds into a second Trigger node. This
51 | node is configured to send on `0` every two seconds and feeds back into the top
52 | branch. The node is also configured to stop sending if it receives a `msg.payload`
53 | of `"reset"`. As this is the initial message sent by the first
54 | Trigger node when it receives a sensor message, this will
55 | cause the second Trigger node to be reset when the sensor
56 | resumes sending its own messages.
57 |
--------------------------------------------------------------------------------
/basic/convert-xml.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Convert to/from XML
4 | slug:
5 | - label: formats
6 | url: /#working-with-data-formats
7 | - xml
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to convert a message property between an XML string and the JavaScript object
13 | it represents.
14 |
15 | ### Solution
16 |
17 | The XML node can be used to convert between the two
18 | formats.
19 |
20 | #### Example
21 |
22 | {:width="684px"}
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"1b546d47.9474e3","type":"inject","z":"64133d39.bb0394","name":"XML String","topic":"","payload":"{\"a\":1}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":260,"wires":[["d72b2bfd.77d068"]]},{"id":"1adf407d.6c4fe","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":260,"wires":[]},{"id":"46638890.8ae758","type":"inject","z":"64133d39.bb0394","name":"Object","topic":"","payload":"{\"note\":{\"$\":{\"priority\":\"high\"},\"to\":[\"Nick\"],\"from\":[\"Dave\"],\"heading\":[\"Reminder\"],\"body\":[\"Update the website\"]}}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":300,"wires":[["dae1d291.de0d2"]]},{"id":"6fefca67.3669e4","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":430,"y":300,"wires":[]},{"id":"d72b2bfd.77d068","type":"template","z":"64133d39.bb0394","name":"","field":"payload","fieldType":"msg","format":"text","syntax":"plain","template":"XML node then converts it to the equivalent JavaScript
45 | object:
46 |
47 | ~~~json
48 | {
49 | "note": {
50 | "$": {
51 | "priority":"high"
52 | },
53 | "to": ["Nick"],
54 | "from": ["Dave"],
55 | "heading": ["Reminder"],
56 | "body": ["Update the website"]
57 | }
58 | }
59 | ~~~
60 |
61 | Note how the attributes of the `XML node to see the necessary
68 | JavaScript object required to generate it when fed back the other way.
69 |
--------------------------------------------------------------------------------
/basic/route-on-context.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Route or block a message based on a context value
4 | slug:
5 | - label: flow control
6 | url: /#flow-control
7 | - route on context
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to route a message to different flows, or stop it entirely, according to the current value
13 | of another variable.
14 |
15 | ### Solution
16 |
17 | Save the switching variable into a flow context variable, and then use a Switch node to check the value of that flow context
18 | property against different values corresponding to different outputs of the node.
19 |
20 | #### Example
21 |
22 | {:width="643px"}
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"a62d8cdf.1bd82","type":"inject","z":"9138b11f.f64d5","name":"Inject","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"2","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":585,"wires":[["b8bbbc41.f272"]]},{"id":"b8bbbc41.f272","type":"switch","z":"9138b11f.f64d5","name":"Context based routing","property":"state","propertyType":"flow","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"}],"checkall":"true","repair":false,"outputs":3,"x":350,"y":585,"wires":[["9aa9c6b2.18a8e8"],["6ba4ec46.476794"],["a2e806c8.ffa168"]]},{"id":"9aa9c6b2.18a8e8","type":"debug","z":"9138b11f.f64d5","name":"Output 1","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":590,"y":525,"wires":[]},{"id":"6ba4ec46.476794","type":"debug","z":"9138b11f.f64d5","name":"Output 2","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":590,"y":585,"wires":[]},{"id":"a2e806c8.ffa168","type":"debug","z":"9138b11f.f64d5","name":"Output 3","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":590,"y":645,"wires":[]},{"id":"8aabdb51.e8b538","type":"inject","z":"9138b11f.f64d5","name":"Set state 0 - turn off","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":180,"y":675,"wires":[["e46083e4.1f17b"]]},{"id":"d1722dee.48db4","type":"inject","z":"9138b11f.f64d5","name":"Set state 1 - send to output 1","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":210,"y":720,"wires":[["e46083e4.1f17b"]]},{"id":"4bdb08de.706328","type":"inject","z":"9138b11f.f64d5","name":"Set state 2 - send to output 2","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2","payloadType":"num","x":210,"y":765,"wires":[["e46083e4.1f17b"]]},{"id":"220ce0a6.cf81e","type":"inject","z":"9138b11f.f64d5","name":"Set state 3 - send to output 3","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"3","payloadType":"num","x":210,"y":810,"wires":[["e46083e4.1f17b"]]},{"id":"e46083e4.1f17b","type":"change","z":"9138b11f.f64d5","name":"Set flow.state","rules":[{"t":"set","p":"state","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":720,"wires":[[]]}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ### Discussion
32 |
33 | In the example flow, the top flow represents the stream of messages that can be stopped or routed to one of the three outputs by the Switch node.
34 |
35 | The bottom flow provides a set of Inject nodes to change
36 | the current value of the `flow.state` context property.
37 |
38 | This can be used as a simple gate like function - based on the value of some other input, that you store into the `flow.state` context property.
39 |
40 | This shows how the routing in one flow can be changed by a separate flow.
41 |
--------------------------------------------------------------------------------
/basic/generate-csv.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Generate CSV output
4 | slug:
5 | - label: formats
6 | url: /#working-with-data-formats
7 | - csv
8 | ---
9 |
10 | ### Problem
11 |
12 | You want to generate valid CSV output from a message containing key/value pairs of
13 | data.
14 |
15 | ### Solution
16 |
17 | The CSV node can be used to generate well-formatted CSV
18 | strings.
19 |
20 | #### Example
21 |
22 | {:width="688px"}
23 |
24 | {% raw %}
25 | ~~~json
26 | [{"id":"457d9ad6.b737b4","type":"inject","z":"64133d39.bb0394","name":"single","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":640,"wires":[["1e05fafd.887b05"]]},{"id":"1e05fafd.887b05","type":"change","z":"64133d39.bb0394","name":"Generate single payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"{ \"a\":$floor(100*$random()),\"b\":$floor(100*$random()),\"c\":$floor(100*$random())}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":640,"wires":[["e9546682.b39898"]]},{"id":"e9546682.b39898","type":"csv","z":"64133d39.bb0394","name":"","sep":",","hdrin":"","hdrout":false,"multi":"one","ret":"\\n","temp":"a,b,c","skip":"0","x":450,"y":640,"wires":[["f83ad3b0.78d32"]]},{"id":"f83ad3b0.78d32","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":640,"wires":[]},{"id":"ae242f2c.d1c8a","type":"inject","z":"64133d39.bb0394","name":"array","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":700,"wires":[["7535f521.4a88bc"]]},{"id":"7535f521.4a88bc","type":"change","z":"64133d39.bb0394","name":"Generate array payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"[\t { \"a\":$floor(100*$random()),\"b\":$floor(100*$random()),\"c\":$floor(100*$random())},\t { \"a\":$floor(100*$random()),\"b\":$floor(100*$random()),\"c\":$floor(100*$random())},\t { \"a\":$floor(100*$random()),\"b\":$floor(100*$random()),\"c\":$floor(100*$random())},\t { \"a\":$floor(100*$random()),\"b\":$floor(100*$random()),\"c\":$floor(100*$random())}\t]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":700,"wires":[["f4e0465f.ef0338"]]},{"id":"f4e0465f.ef0338","type":"csv","z":"64133d39.bb0394","name":"","sep":",","hdrin":"","hdrout":true,"multi":"one","ret":"\\n","temp":"a,b,c","skip":"0","x":450,"y":700,"wires":[["6eb67fdf.58626"]]},{"id":"6eb67fdf.58626","type":"debug","z":"64133d39.bb0394","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":700,"wires":[]}]
27 | ~~~
28 | {: .flow}
29 | {% endraw %}
30 |
31 | ### Discussion
32 |
33 | In the example, the first flow injects a payload containing a single object with three
34 | properties containing randomly generated values.
35 |
36 | ```javascript
37 | {
38 | a: 10,
39 | b: 20,
40 | c: 30
41 | }
42 | ```
43 |
44 | The CSV has been configured with the desired column names
45 | and uses the corresponding object properties to fill in those columns.
46 |
47 | The resulting message contains the well-formatted CSV string for that single row
48 | of data - including a newline character at the end.
49 |
50 | ```javascript
51 | "10,20,30\n"
52 | ```
53 |
54 | This is suitable for passing to a File Out node to
55 | append to an existing CSV file.
56 |
57 | The second flow injects an array of objects with randomly generated values:
58 |
59 | ```javascript
60 | [
61 | { a: 80, b: 18, c: 2},
62 | { a: 52, b: 36, c: 10},
63 | { a: 91, b: 18, c: 61},
64 | { a: 32, b: 47, c: 65},
65 | ]
66 | ```
67 |
68 | Again the CSV node has been configured with the column names to use. It has also
69 | been configured to include the column names as the first row of output.
70 |
71 | ```javascript
72 | a,b,c
73 | 80,18,2
74 | 52,36,10
75 | 91,18,61
76 | 32,47,65
77 | ```
78 |
--------------------------------------------------------------------------------
/_includes/footer.html:
--------------------------------------------------------------------------------
1 | Node-RED: Low-code programming for event-driven applications.
5 |Copyright OpenJS Foundation and Node-RED contributors. All rights reserved. The OpenJS Foundation has registered trademarks and uses trademarks. For a list of trademarks of the OpenJS Foundation, please see our Trademark Policy and Trademark List. Trademarks and logos not indicated on the list of OpenJS Foundation trademarks are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
37 |The OpenJS Foundation | Terms of Use | Privacy Policy | OpenJS Foundation Bylaws | Trademark Policy | Trademark List | Cookie Policy
38 |HTTP In node include the
17 | `msg.req.cookies` property that lists the cookies set on the current request.
18 |
19 | The HTTP Response node will use the `msg.cookies` property
20 | in order to set or clear cookies.
21 |
22 | The HTTP Request node will accept an input property of `msg.cookies` containing the cookies to be sent with that request.
23 | #### Example
24 |
25 | 
26 |
27 | {% raw %}
28 | ~~~json
29 | [{"id":"c362b989.954ae8","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-cookie","method":"get","swaggerDoc":"","x":130,"y":1020,"wires":[["21ddf71f.d00518"]]},{"id":"21ddf71f.d00518","type":"function","z":"3045204d.cfbae","name":"Format cookies","func":"msg.payload = JSON.stringify(msg.req.cookies,null,4);\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":1020,"wires":[["f3aa98c1.befc18"]]},{"id":"f3aa98c1.befc18","type":"template","z":"3045204d.cfbae","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n \n {{ payload }}\n \n","x":530,"y":1020,"wires":[["f52e2880.180968"]]},{"id":"f52e2880.180968","type":"http response","z":"3045204d.cfbae","name":"","x":750,"y":1020,"wires":[]},{"id":"9a2a9a4.0fc0768","type":"change","z":"3045204d.cfbae","name":"Redirect to /hello-cookie","rules":[{"t":"set","p":"statusCode","pt":"msg","to":"302","tot":"num"},{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.location","pt":"msg","to":"/hello-cookie","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":1080,"wires":[["f52e2880.180968"]]},{"id":"afefb90.53dcf48","type":"function","z":"3045204d.cfbae","name":"Add a cookie","func":"msg.cookies = { };\nmsg.cookies[\"demo-\"+(Math.floor(Math.random()*1000))] = Date.now();\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":1060,"wires":[["9a2a9a4.0fc0768"]]},{"id":"d5205a2c.db9018","type":"function","z":"3045204d.cfbae","name":"Clear cookies","func":"// Find demo cookies and clear them\nvar cookieNames = Object.keys(msg.req.cookies).filter(function(cookieName) { return /^demo-/.test(cookieName);});\nmsg.cookies = {};\n\ncookieNames.forEach(function(cookieName) {\n msg.cookies[cookieName] = null;\n});\n\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":1100,"wires":[["9a2a9a4.0fc0768"]]},{"id":"fda60c66.04975","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-cookie/add","method":"get","swaggerDoc":"","x":140,"y":1060,"wires":[["afefb90.53dcf48"]]},{"id":"35285a76.1f8636","type":"http in","z":"3045204d.cfbae","name":"","url":"/hello-cookie/clear","method":"get","swaggerDoc":"","x":140,"y":1100,"wires":[["d5205a2c.db9018"]]}]
30 | ~~~
31 | {: .flow}
32 | {% endraw %}
33 |
34 | This example provides three HTTP endpoints:
35 |
36 | - `/hello-cookie` returns a page that lists the cookies currently set
37 | - `/hello-cookie/add` adds a new cookie and redirects back to `/hello-cookie`
38 | - `/hello-cookie/clear` clears all cookies created by the example and redirects back to `/hello-cookie`
39 |
40 | ### Discussion
41 |
42 | The `msg.req.cookies` property is an object of key/value pairs containing the cookies
43 | set on the current request.
44 |
45 | ~~~javascript
46 | var mySessionId = msg.req.cookies['sessionId'];
47 | ~~~
48 |
49 | In order to set a cookie in the response, the `msg.cookies` property should be set
50 | to a similar key/value object.
51 |
52 | The value can be either a string to set the value of the cookie with default
53 | options, or it can be an object of options.
54 |
55 | The following example sets two cookies - one called `name` with a value of `Nick`, the other called `session` with a value of `1234` and an expiry set to 15 minutes.
56 |
57 | ~~~javascript
58 | msg.cookies = {
59 | name: 'nick',
60 | session: {
61 | value: '1234',
62 | maxAge: 900000
63 | }
64 | }
65 | ~~~
66 |
67 | The valid options include:
68 |
69 | - `domain` - (String) domain name for the cookie
70 | - `expires` - (Date) expiry date in GMT. If not specified or set to 0, creates a session cookie
71 | - `maxAge` - (String) expiry date as relative to the current time in milliseconds
72 | - `path` - (String) path for the cookie. Defaults to /
73 | - `value` - (String) the value to use for the cookie
74 |
75 | To delete a cookie, set its value to null.
76 |
77 | #### URL Encoding of Cookies
78 | The HTTP Request node will accept a property of `encode : false` within the cookie which will avoid the value being URL Encoded when sent in the request
79 |
80 | ~~~javascript
81 | msg.cookies = {
82 | myCookie : {
83 | Path : "/",
84 | value : "ysjLVJA==",
85 | encode : false
86 | }
87 | }
88 | ~~~
89 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/css/style.min.css:
--------------------------------------------------------------------------------
1 | *,*:after,*:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0px}[class*='col-']{float:left;padding-left:17px;padding-right:17px}[class*='col-']:last-of-type{padding-right:0px}[class*='col-']:first-of-type{padding-left:0px}.grid{width:100%;max-width:1155px;min-width:755px;margin:0 auto;overflow:hidden;padding:0px 75px 0 75px}.grid:after{content:"";display:table;clear:both}.col-1-1{width:100%}.col-2-3,.col-8-12{width:66.66%}.col-1-2,.col-6-12{width:50%}.col-1-3,.col-4-12{width:33.33%}.col-1-4,.col-3-12{width:25%}.col-3-4,.col-4-12{width:75%}.col-1-5{width:20%}.col-1-6,.col-2-12{width:16.667%}.col-1-7{width:14.28%}.col-1-8{width:12.5%}.col-1-9{width:11.1%}.col-1-10{width:10%}.col-1-11{width:9.09%}.col-1-12{width:8.33%}.col-11-12{width:91.66%}.col-10-12{width:83.333%}.col-9-12{width:75%}.col-5-12{width:41.66%}.col-7-12{width:58.33%}@media handheld, only screen and (max-width: 767px){.grid{width:100%;min-width:0;margin-left:0px;margin-right:0px;padding-left:15px !important;padding-right:15px !important}[class*='col-']{width:auto;float:none;margin-left:0px;margin-right:0px;margin-top:10px;margin-bottom:10px;padding-left:0px !important;padding-right:0px !important}}body{color:#555;background:#eee;font-family:'Open Sans', sans-serif;font-size:16px;line-height:1.6em}a{text-decoration:none}a:hover{text-decoration:underline}a.button{box-shadow:rgba(0,0,0,0.4) 5px 5px 20px;text-decoration:none;display:inline-block;padding:20px 60px;border-radius:5px;background:#aa6767;color:#eee}a.button:hover{background:#7F4545}h1,h2,h3,h4,h5{font-family:"Roboto Slab";font-weight:normal}h1{font-size:36px;font-weight:bold}h2{font-size:30px}h3{font-size:24px}h4{font-size:18px}dd{margin-bottom:10px}.header{font-family:"Roboto Slab";font-size:20px;line-height:50px;color:#999;padding:0px 10px;min-height:50px;background:#333}.header-content{width:100%;max-width:1155px;min-width:755px;margin:0 auto;background:#333;border-bottom:5px solid #333}.header-content .brand{display:inline-block;float:left;margin-top:3px}.header-content .brand a{display:block;font-size:20px;border-bottom:5px solid #333;padding:0 15px 0 15px;color:#eee}.header-content .logo{vertical-align:middle;height:20px}.header-content a{color:#999}.header-content ul{margin-left:170px;text-align:right;list-style-type:none;margin:-0;padding:0}.header-content li{display:inline-block;margin:0;padding:0}.header-content li a{display:block;font-size:16px;padding:0 15px 0 15px;border-bottom:5px solid #333}.header-content li.current a{color:#fff;border-bottom:5px solid #fff}.header a:hover{text-decoration:none;color:#eee}.header a:hover{border-bottom:5px solid #eee}.header .menu{position:absolute;top:7px;right:10px;display:none;width:55px;height:45px;color:#999;text-align:center}.footer{background:#333}.footer .grid{color:#eee;padding:20px 0;font-family:Arial}.footer a{color:#eee}.footer .content{height:auto;min-height:0;margin:20px auto}.footer .headline{margin:80px auto 20px auto}.footer{text-align:center}.ets-link{margin:10px 0px}.ets-globe{width:60px;vertical-align:middle}.hide{display:none}.title>.grid{overflow:visible}.title>.grid>.col-1-1{position:relative}.ribbon{position:absolute;left:-5px;top:-5px;z-index:1;width:400px;padding:30px;text-align:right}.ribbon>a{border-top-right-radius:10px;border-top-left-radius:10px;font-weight:bold;color:#e9e9e9;text-align:center;line-height:20px;transform:rotate(-45deg);width:400px;display:block;background:#c15555;box-shadow:0 3px 10px -5px #000;position:absolute;top:76px;left:-110px;font-size:22px;line-height:1.1em;padding:10px;font-family:"Roboto Slab";box-shadow:0 10px 10px -5px #7b7b7b}.ribbon>a:hover{text-decoration:none;color:#fff}.ribbon>a>span{font-size:18px}.ribbon>a::before{content:"";position:absolute;left:0px;top:100%;z-index:-1;border-left:8px solid #6F0808;border-right:8px solid transparent;border-bottom:8px solid transparent;border-top:8px solid #6F0808}.ribbon .edge{position:absolute;width:80px;height:380px;left:-15px;top:0px;box-shadow:-11px 0 22px -14px grey}.ribbon>a::after{content:"";position:absolute;right:0px;top:100%;z-index:-1;border-left:8px solid transparent;border-right:8px solid #6F0808;border-bottom:8px solid transparent;border-top:8px solid #6F0808}@media handheld, only screen and (max-width: 767px){.ribbon{margin:auto;transform:none;position:static;width:100%}.ribbon>a{width:100%;transform:none;position:static;border-radius:5px;box-shadow:none}.ribbon>a::after{display:none}.ribbon>a::before{display:none}.ribbon .edge{display:none}}@media handheld, only screen and (max-width: 755px){.header .menu{display:inline-block}.header-content{min-width:0}.header-content .brand{float:none}.header-content ul{display:none;margin:0;text-align:right}.header-content li{display:block;line-height:26px}.header-content li.current a{border:none}.header ul a:hover{border:none}}.title{background:url(../images/title-wave.png) no-repeat 0% 100% #8f0000;border-top:10px solid #a22222;text-align:center}.intro,.nodes{background:#eee}.intro{border-bottom:2px solid #a22222}.features{background:#fff}.links{background:#444}.platforms{background:#fff;border-top:2px solid #a22222;border-bottom:2px solid #a22222}.platforms img{width:100%;max-width:300px}.platforms h4{text-align:center;margin:5px 0}a{color:#aa6767}a:hover{color:#B77777}.openjs-logo{max-width:200px}.links .grid{font-size:16px;color:#aaa;padding-top:20px;padding-bottom:20px;font-family:Arial}.links .openjs{font-size:13px;line-height:1.4em}.links p{margin:0 0 10px 0}.links a{color:#eee}.links ul{margin:0;padding:0;padding-left:15px}.links .content{height:auto;min-height:0;margin:10px auto}.content{min-height:250px;padding:60px 0;margin:0}.blurb p{margin-top:0}.blurb h3,.nodes h3,.features h3,.community h3,.platforms h3{margin-top:0;margin-bottom:0.5em}.feature{max-width:485px;margin-left:auto;margin-right:auto;text-align:center}.feature img{max-width:445px;width:100%}.title .content{height:280px}.title h1{margin-top:20px;margin-bottom:10px;color:#f0f0f0;font-size:2.5em;font-weight:normal}.title h2{margin-top:0px;font-size:20px;font-family:"Open Sans", sans-serif;font-weight:normal;color:#c19e9e}.title p{color:#c19e9e}.title img{margin:auto;max-width:769px;width:100%}.nodes .content{height:auto;min-height:0;margin:40px auto}.nodes .col-1-2 .content{width:290px}.nodes .grid{padding-top:40px;padding-bottom:40px}.node-image{width:100px;vertical-align:top;display:inline-block}.node-block{vertical-align:top;display:inline-block;margin-left:10px}.headline h3{text-align:center}.nodes h4{font-family:"Arial";font-weight:normal;margin-top:3px;height:50px;font-size:16px}.helplink{text-align:center;font-size:14px}.helplink a{color:#aa6767}.community{background:#fff}.community ul{list-style-type:none;margin:0;padding:0}.community h4{text-align:center}.community .blog ul li a{display:inline-block;padding:10px 5px;width:100%;height:100%}.community .blog ul li{padding:0}.community .blog ul li:not(:last-child){border-bottom:1px dashed #999}.community .blog ul li span.date{float:right;font-size:0.8em}.community .blog ul li .box-link{border:none}.community .social ul li{display:inline-block;box-sizing:border-box;width:calc( 50% - 25px );height:120px;margin:10px;text-align:center}.community .social ul li a{display:block;width:100%;height:100%;padding-top:25px}.community .social ul li a:hover{text-decoration:none;background:#aa6767;color:#eee}.users{background:#fff;border-bottom:2px solid #a22222}.users h3{margin-top:0;text-align:center}.users ul{text-align:center;list-style-type:none;margin:0;padding:0}.users ul li{margin:10px;padding:10px;display:inline-block;width:200px;vertical-align:middle;background:white}.users ul li img{width:100%}h3 a.box-link{margin-left:30px}a.box-link{font-size:14px;display:inline-block;padding:3px 12px;border:1px solid #aa6767;border-radius:1px}a.box-link:hover{text-decoration:none;background:#aa5555;color:#eee}a.box-link:not(:first-child){margin-left:20px}a.box-link img{width:150px}.node-red-latest-version{color:#c19e9e}.docs-intro{background:#8f0000;border-top:10px solid #a22222}.docs-intro .content{height:100px}.docs-intro h1{text-align:center;font-size:2em;margin:80px 0 100px 0;padding:0;color:#f0f0f0;font-weight:normal}.doc-items{list-style-type:none;padding:0;margin:0 30px 0}.doc-items li{box-sizing:border-box;background:#eee;display:inline-block;width:calc(33% - 30px);margin:10px 10px 50px 10px}.doc-items li a.box-link{padding:15px 10px;width:100%;height:100%}.doc-items img{vertical-align:top;margin-top:-50px}.doc-items h2{margin:0;font-size:20px;color:#333}.doc-items li a.box-link:hover h2{color:#eee}.doc-item-info{padding:10px}.docs{background:#eee;font-size:16px}.docs .grid{background:#fff;padding:0 30px;min-height:730px}h1.docs-title{border-bottom:2px solid #B68181;padding-bottom:10px;margin-top:30px;margin-bottom:40px;font-weight:normal}ul.fixed-toc{position:fixed;top:-28px}ul.toc{overflow:hidden;list-style-type:none;margin:40px 0 20px 0;padding:0;font-size:14px;line-height:16px;z-index:1}ul.toc ul{list-style-type:none;padding:0}ul.toc li:not(.tocheader) a,ul.toc li span{padding:6px 10px;display:block;width:100%;height:100%;color:#666;border-left:8px solid #eee;-border-right:2px solid #B68181;-margin-bottom:3px}ul.toc li.tocheader>span a{display:block;width:100%;height:100%;color:#fff}ul.toc li.tocheader{margin-top:3px}ul.toc li:not(.tocheader).active a{border-left-color:#B68181;-border-right-color:#eee;background:#eee}ul.toc li:not(.tocheader) a:hover{border-left-color:#B68181}ul.toc li.tocheader>span{background:#B68181;border-left-color:#B68181;color:#fff}ul.toc li.tocsubheader span{background:none;border-left-color:#eee;color:#666;padding-left:20px}ul.toc li.tocheader li:not(.toctitle) a{padding-left:30px;font-size:14px}ul.toc li.tocheader li.toctitle a{font-size:15px;line-height:18px}.docs-content a{color:#aa4444}.docs-content img{max-width:100%}.docs-content pre{padding:10px;background:#564848;color:#eee;border-radius:3px}.docs-content pre code{background:inherit;color:inherit}pre,code,.code{font-family:'Ubuntu Mono', Monospace}.code{color:#533;background:#F3E7E7;padding:2px}code{color:#533;background:#F3E7E7;padding:2px 4px;border-radius:2px}pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}pre>code{padding:0}h1{font-size:2em;line-height:1.3em;margin:1.5em 0 0.8em -0.3em}h2{font-size:1.953em;line-height:1.2em;margin:1.5em 0 0.8em -0.3em}h3{font-size:1.563em;margin:1.5em 0 0.8em -0.3em}h4{font-size:1.25em;margin:1.5em 0 0.8em -0.3em}h5{font-size:1.15em;margin:1.5em 0 0.8em -0.3em}.doc-callout{margin:10px 0px;background:#FFFFE0;padding:10px;border-radius:3px;font-size:0.85em;border:1px solid #BE9A9A}ul.toc li.toc-expander{display:none;position:absolute;width:35px;right:0;top:3px;height:37px;background:#B68181;text-align:center;line-height:37px;border-left:1px solid #fff;color:#eee;z-index:10}code.node{border-radius:6px;border:1px solid #B68181;background:#fff0f0;color:#555;white-space:nowrap}div.figure{max-width:100%}div.figure img{display:block;max-width:100%;height:auto;box-shadow:4px 4px 8px 0px #ddd}div.figure.align-left{float:left;width:auto;margin:5px 20px 5px 0}div.figure.align-right{float:right;width:auto;margin:5px 0 5px 20px}div.figure.align-center{margin:5px auto}div.figure p.caption{margin-top:3px;font-size:0.9em;font-style:italic;color:#999}div.figure pre{margin-bottom:0px}table.action-ref{width:auto;min-width:310px;float:right;font-size:0.9em;background:#ffeecc;margin-bottom:10px;margin-left:20px}table.action-ref.inline{float:none;margin-left:0}table.action-ref th{font-weight:bold;font-family:inherit;border-bottom:inherit;text-align:left;font-size:inherit;padding:0px 20px 0px 5px}table.action-ref td{padding:0px 5px;border:none}table.action-ref td:first-child{width:110px;border:none}table.action-ref code{background:none;font-size:1.1em}ul.multi-column-toc{column-count:3}@media handheld, only screen and (max-width: 755px){ul.toc:not(.open) li.tocheader>span{display:none}ul.toc:not(.open) li.tocheader li:not(.active){display:none}ul.toc:not(.open) li.tocheader li.active{padding-right:37px}ul.toc li.toc-expander{display:inline}ul.toc.open li.toc-expander div{transform:rotate(180deg)}.doc-items li{width:calc(50% - 30px)}ul.fixed-toc{position:relative;top:auto}}@media handheld, only screen and (max-width: 450px){.doc-items li{width:100%}ul.multi-column-toc{column-count:2}}table{border-collapse:collapse;border-spacing:0;width:100%;max-width:100%}th{font-family:"Roboto Slab";font-weight:normal;text-align:left;font-size:20px;padding:0 5px;border-bottom:2px solid #B68181}th:not(:first-child),td:not(:first-child){border-left:1px solid #F4DEDE}td{padding:6px 5px;border-bottom:1px solid #F4DEDE}td:first-child span.method{font-family:"Ubuntu Mono";font-size:0.9em;background:#F4DEDE;border:1px solid #F4DEDE;border-radius:3px;width:60px;text-align:center;display:inline-block;margin-right:10px}td:first-child{padding:6px 15px 6px 5px;width:1px;white-space:nowrap}th:first-child{padding:6px 15px 6px 5px;width:1px;white-space:nowrap}.breadcrumbs{min-height:0;height:50px}.breadcrumbs>div.grid{color:white;background:#aa4444;min-height:0;line-height:50px;font-size:20px;font-family:Roboto Slab}.breadcrumbs>div a{color:white;opacity:0.9;display:inline-block;height:45px;box-sizing:border-box;border-bottom:4px solid transparent}.breadcrumbs>div a:hover,.breadcrumbs>div a.active{text-decoration:none;border-color:white;opacity:1}.breadcrumbs>div>a:not(:first-child){margin-left:10px}.breadcrumbs>div>a{margin-right:10px}.post-header h2{margin-bottom:10px}.sidebar a.fa{margin:0 10px;font-size:20px}.sidebar h4{margin-top:0px;margin-bottom:5px}.sidebar p{margin:5px 0}.pagination{padding:25px 0;text-align:center}.page-number{display:inline-block;width:200px}.sidebar{margin-top:30px}.post-meta{color:#999}.post-footer{margin:30px auto;border:1px solid #999;padding:10px}.blog-posts .grid{background:#f3f3f3}.blog-posts .post-preview{margin:20px;top:-50px;border-color:#fff;width:calc(100% / 3 - 60px);height:300px}.blog-posts .post-preview .post-header{text-align:left}.blog-posts .post-preview .post-header .post-meta{text-align:center}.post-preview{background:white;position:relative;display:inline-block;margin:0 10px 10px;width:calc(100% / 3 - 30px);overflow:hidden;height:250px;text-overflow:ellipsis;border:1px solid #999;border-radius:3px}.post-preview .post-header{text-align:center}.post-preview .post-header img{max-width:100px}.post-preview>a{padding:10px 15px;position:absolute;top:0;left:0;right:0;bottom:0}.post-preview>a:hover{text-decoration:none}.post-preview:hover{border-color:#999;box-shadow:0px 2px 3px 0 #aaa}.post-preview .post-content{margin-top:5px;color:#666;font-size:0.9em;overflow:hidden;max-height:180px}.post-preview p{margin:0}.post-preview h2{margin:5px 0 5px;font-size:22px}.post-preview h3{margin:5px 0 5px;font-size:18px}.post-preview .post-link{position:absolute;bottom:0;left:0;right:0;height:30px;padding-right:10px;background:rgba(255,255,255,0.5);text-align:right}.post-preview .post-meta{font-size:0.9em}blockquote{border-left:10px solid #eee;padding-left:10px;font-style:italic;color:#888}.blog-posts-title{height:100px;background:url(../images/title-wave.png) no-repeat 0% 25% #8f0000;border-top:10px solid #a22222;text-align:center}.blog-posts .grid{overflow:visible}@media handheld, only screen and (max-width: 850px){.blog-posts .post-preview{width:calc(100% / 2 - 50px);height:200px}}@media handheld, only screen and (max-width: 767px){.blog-posts .post-preview{width:calc(100% - 40px);height:200px}}.highlight pre{background-color:#564848}.highlight .hll{background-color:#564848}.highlight .c{color:#75715e}.highlight .err{color:#ff58b1;background-color:#564848}.highlight .k{color:#66d9ef}.highlight .l{color:#ae81ff}.highlight .n{color:#f8f8f2}.highlight .o{color:#dc8f8f}.highlight .p{color:#f8f8f2}.highlight .cm{color:#afa98c}.highlight .cp{color:#afa98c}.highlight .c1{color:#afa98c}.highlight .cs{color:#afa98c}.highlight .ge{font-style:italic}.highlight .gs{font-weight:bold}.highlight .kc{color:#66d9ef}.highlight .kd{color:#66d9ef}.highlight .kn{color:#dc8f8f}.highlight .kp{color:#66d9ef}.highlight .kr{color:#66d9ef}.highlight .kt{color:#66d9ef}.highlight .ld{color:#e6db74}.highlight .m{color:#ae81ff}.highlight .s{color:#e6db74}.highlight .na{color:#a6e22e}.highlight .nb{color:#f8f8f2}.highlight .nc{color:#a6e22e}.highlight .no{color:#66d9ef}.highlight .nd{color:#a6e22e}.highlight .ni{color:#f8f8f2}.highlight .ne{color:#a6e22e}.highlight .nf{color:#a6e22e}.highlight .nl{color:#f8f8f2}.highlight .nn{color:#f8f8f2}.highlight .nx{color:#a6e22e}.highlight .py{color:#f8f8f2}.highlight .nt{color:#dc8f8f}.highlight .nv{color:#f8f8f2}.highlight .ow{color:#dc8f8f}.highlight .w{color:#f8f8f2}.highlight .mf{color:#ae81ff}.highlight .mh{color:#ae81ff}.highlight .mi{color:#ae81ff}.highlight .mo{color:#ae81ff}.highlight .sb{color:#e6db74}.highlight .sc{color:#e6db74}.highlight .sd{color:#e6db74}.highlight .s2{color:#e6db74}.highlight .se{color:#ae81ff}.highlight .sh{color:#e6db74}.highlight .si{color:#e6db74}.highlight .sx{color:#e6db74}.highlight .sr{color:#e6db74}.highlight .s1{color:#e6db74}.highlight .ss{color:#e6db74}.highlight .bp{color:#f8f8f2}.highlight .vc{color:#f8f8f2}.highlight .vg{color:#f8f8f2}.highlight .vi{color:#f8f8f2}.highlight .il{color:#ae81ff}.highlight .gu{color:#75715e}.highlight .gd{color:#dc8f8f}.highlight .gi{color:#a6e22e}
2 |
--------------------------------------------------------------------------------