<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Node-RED Q &amp; A on Much Ado About IT</title><link>https://it.knightnet.org.uk/kb/nr-qa/</link><description>
Recent content about Node-RED Q &amp; A from Much Ado About IT |
Ramblings and rantings from IT Architect &amp; Designer, Julian Knight</description><generator>Hugo | gohugo.io | Theme twenty-sixteen</generator><language>en-gb</language><copyright>This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.</copyright><lastBuildDate>Mon, 24 Apr 2023 21:27:28 +0000</lastBuildDate><atom:link href="https://it.knightnet.org.uk/kb/nr-qa/feed.xml" rel="self" type="application/rss+xml"/><item><title>Node-RED communications protocols</title><link>https://it.knightnet.org.uk/kb/nr-qa/nr-comms/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/nr-comms/</guid><pubDate>Thu, 20 Aug 2020 17:53:20 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/nr-comms/</guid><description><div>Node-RED has an excellent choice of communications protocols available to it. This article looks at the main options and their strengths and weaknesses. It also gives suggestions as to when you may wish to use them.</div><div>&lt;p>Node-RED is renown for its MQTT support since that is where it started - as an IBM demonstrator for their experteese on IoT.&lt;/p>
&lt;p>However, this is only one of many ways to send/receive data between Node-RED and other systems or services. Each of tese protocols has its own advantages and disadvantages.&lt;/p>
&lt;h2 id="the-protocols">The protocols&lt;/h2>
&lt;p>In rough order of descending order of ease of use (very rough!):&lt;/p>
&lt;ul>
&lt;li>MQTT&lt;/li>
&lt;li>Websocket&lt;/li>
&lt;li>HTTP&lt;/li>
&lt;li>TCP&lt;/li>
&lt;li>UDP&lt;/li>
&lt;li>UNIX Pipes&lt;/li>
&lt;/ul>
&lt;h3 id="mqtt">MQTT&lt;/h3>
&lt;p>This is likely to be the easiest to use even though it requires an extra service to be running, a &amp;ldquo;Broker&amp;rdquo;.&lt;/p>
&lt;p>There is even a custom node available that lets you run a broker from within Node-RED itself. However, I don&amp;rsquo;t recommend doing that because it adds significant overheads that are easily avoided. The most commonly used broker is &amp;ldquo;Mosquito&amp;rdquo; which has low resource overheads, is fast, secure and capable. It is easily installed and configured.&lt;/p>
&lt;p>While MQTT data payloads are just strings, Node-RED lets you send and receive more complex data structures (JSON).&lt;/p>
&lt;p>The things that put MQTT at the top of the list are:&lt;/p>
&lt;ul>
&lt;li>The ability to easily handle more complex data&lt;/li>
&lt;li>The availability of MQTT libraries and clients for many platforms&lt;/li>
&lt;/ul>
&lt;h3 id="websocket">Websocket&lt;/h3>
&lt;h3 id="http">HTTP&lt;/h3>
&lt;h3 id="tcp">TCP&lt;/h3>
&lt;h3 id="udp">UDP&lt;/h3>
&lt;h3 id="unix-pipes">UNIX Pipes&lt;/h3></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/communications">Communications</category><category domain="https://it.knightnet.org.uk/tags/protocols">Protocols</category><category domain="https://it.knightnet.org.uk/tags/mqtt">MQTT</category><category domain="https://it.knightnet.org.uk/tags/websockets">Websockets</category><category domain="https://it.knightnet.org.uk/tags/tcp">TCP</category><category domain="https://it.knightnet.org.uk/tags/udp">UDP</category></item><item><title>FAQ 4: How do I see the Node-RED log?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq4-show-node-red-log/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq4-show-node-red-log/</guid><pubDate>Tue, 17 Mar 2020 16:28:07 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq4-show-node-red-log/</guid><description><div>Just as there are several possible ways to run Node-RED, there are several ways to access the log.</div><div>&lt;p>In line with most server type applications, Node-RED outputs all sorts of operational and error information to a log. In addition to Node-RED&amp;rsquo;s own logging, each node that you use may also add to the log.&lt;/p>
&lt;p>You can also output your own information to the log from your flows, those methods are shown at the end of this article.&lt;/p>
&lt;p>There are three categories of ways to actually run Node-RED and each will require you to access the log in a slightly different way.&lt;/p>
&lt;h2 id="running-node-red-as-a-service">Running Node-RED as a &amp;ldquo;Service&amp;rdquo;&lt;/h2>
&lt;p>If you install Node-RED using the script supplied for installation on a Raspberry Pi (or any other Debian-like host), Node-RED will be run as a system service. That is to say that it will be started up when the system boots. You can also do this on other platforms including Windows.&lt;/p>
&lt;h3 id="linux">Linux&lt;/h3>
&lt;p>In these cases, typically system log output goes to a standard service such as &lt;code>syslog&lt;/code>. Typically, the syslog output is found in a file at &lt;code>/var/log/syslog&lt;/code> and you can use the &lt;code>tail&lt;/code> command from a terminal command prompt to view it.&lt;/p>
&lt;p>On most modern versions of Linux though, the syslog is being overtaken by logging built into the &lt;code>systemd&lt;/code> service. In these cases, it is better to use the &lt;code>journalctl&lt;/code> command to show the log output. This has the advantage that you only need to know the service name (&lt;code>node-red&lt;/code> on a standard Pi install) and you don&amp;rsquo;t need to worry about where the actual data is stored. You can also use the more advanced features of that command to output logs in different formats.&lt;/p>
&lt;p>The following command will show you the last 50 lines of the log, jumps to the last output and &amp;ldquo;follows&amp;rdquo; any further output.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">journalctl -u node-red -e -f -n &lt;span class="m">50&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="windows">Windows&lt;/h3>
&lt;p>Windows does not use log output in the same way that Linux does as it has the &amp;ldquo;Event Logs&amp;rdquo;. Typically, log output is redirected to a file and you will need to look at the startup command for Node-RED to see where the logs are being written to.&lt;/p>
&lt;h2 id="running-node-red-manually">Running Node-RED manually&lt;/h2>
&lt;p>On all platforms, if you run Node-RED manually from the command line, the log output is shown in the same terminal. Using the keyboard command &lt;!-- raw HTML omitted -->ctrl&lt;!-- raw HTML omitted -->-&lt;!-- raw HTML omitted -->c&lt;!-- raw HTML omitted --> will both stop Node-RED and close the log.&lt;/p>
&lt;h2 id="using-a-runner-to-run-node-red">Using a &amp;ldquo;runner&amp;rdquo; to run Node-RED&lt;/h2>
&lt;p>Sometimes, especially during development, it is helpful to use a &amp;ldquo;runner&amp;rdquo; application such as &lt;code>PM2&lt;/code> or &lt;code>nodemon&lt;/code> to start Node-RED. These will recover from failures and can be made to &amp;ldquo;watch&amp;rdquo; for changes to files and restart automatically.&lt;/p>
&lt;p>Each of these tools may have their own ways of viewing log output. For example, when using the popular pm2 runnner, the command is &lt;code>pm2 logs&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="changing-log-output-levels">Changing log output levels&lt;/h2>
&lt;p>By default, Node-RED will show the following types of output from both Node-RED and any installed nodes:&lt;/p>
&lt;ul>
&lt;li>&lt;code>fatal&lt;/code> - only those errors which make the application unusable should be recorded&lt;/li>
&lt;li>&lt;code>error&lt;/code> - record errors which are deemed fatal for a particular request + fatal errors&lt;/li>
&lt;li>&lt;code>warn&lt;/code> - record problems which are non fatal + errors + fatal errors&lt;/li>
&lt;li>&lt;code>info&lt;/code> - record information about the general running of the application + warn + error + fatal errors&lt;/li>
&lt;/ul>
&lt;p>You can change the logging levels to also show:&lt;/p>
&lt;ul>
&lt;li>&lt;code>debug&lt;/code> - record information which is more verbose than info + info + warn + error + fatal errors&lt;/li>
&lt;li>&lt;code>trace&lt;/code> - record very detailed logging + debug + info + warn + error + fatal errors&lt;/li>
&lt;/ul>
&lt;p>Or you can remove levels or turn off logging alltogether (using the &lt;code>off&lt;/code> setting).&lt;/p>
&lt;p>In addition, there are 2 other settings that impact logs:&lt;/p>
&lt;ul>
&lt;li>&lt;code>metrics&lt;/code> - Whether or not to include metric events in the log output&lt;/li>
&lt;li>&lt;code>audit&lt;/code> - Whether or not to include audit events in the log output&lt;/li>
&lt;/ul>
&lt;p>All of these settings are found (complete with instructions) in the &lt;code>settings.js&lt;/code> file typically found in the &lt;code>userDir&lt;/code> folder (normally &lt;code>~/.node-red/settings.js&lt;/code>).&lt;/p>
&lt;h2 id="outputting-your-own-information-to-the-log">Outputting your own information to the log&lt;/h2>
&lt;p>When writing flows in Node-RED, you will normally use the &lt;code>debug&lt;/code> node that, by default, outputs to the debug sidebar in the Node-RED Editor (admin UI). However, you can change the settings in the debug node to also (or instead) output to the log.&lt;/p>
&lt;p>&lt;img src="https://it.knightnet.org.uk/static/uploads/2020/node-red-debug-node-settings.jpg" alt="node-red debug node settings">&lt;/p>
&lt;p>In addition, you can also output to the log from a &lt;code>function&lt;/code> node using the code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">node&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">warn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;some useful text&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">Mar &lt;span class="m">17&lt;/span> 17:12:48 pi node-red&lt;span class="o">[&lt;/span>18577&lt;span class="o">]&lt;/span>: &lt;span class="m">17&lt;/span> Mar 17:12:48 - &lt;span class="o">[&lt;/span>warn&lt;span class="o">]&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="k">function&lt;/span>:My useful fn node&lt;span class="o">]&lt;/span> some useful text
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you give your function node a reasonably name, you will see that in the output as shown. If the node doesn&amp;rsquo;t have a name, the id will be shown, you can use that in the Editor&amp;rsquo;s search feature to find the node.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>FAQ 3: What different ways are there to install Node-RED and which is best?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq3-types-of-installation/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq3-types-of-installation/</guid><pubDate>Tue, 10 Mar 2020 09:26:00 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq3-types-of-installation/</guid><description><div>There are several possible ways to install Node-RED, this post provides an overview and some thoughts about when you might want to use which approach.</div><div>&lt;p>There are three basic approaches to installing Node-RED. Which of these is &amp;ldquo;best&amp;rdquo; for you will depend on your knowledge, willingness to learn, desire or need to gain maximum flexibility and so on. Only you can work that out. It should also be noted that you should be able to mix and max these approaches if you really want to (though I can&amp;rsquo;t say that I would personally recommend that).&lt;/p>
&lt;h2 id="global-install">Global Install&lt;/h2>
&lt;ul>
&lt;li>This is the standard and therefore arguably by far the easiest installation.&lt;/li>
&lt;li>It is good for people who are not overly familiar with their OS&amp;rsquo;s filing system or how node.js and npm work and who don&amp;rsquo;t want to be bothered to find out (that is not a criticism by the way).&lt;/li>
&lt;li>It allows for multiple instances to be run if needed but all instances must use the same version of Node-RED.&lt;/li>
&lt;li>It doesn&amp;rsquo;t &amp;ldquo;pollute&amp;rdquo; your home folder with the node-red and many other required node.js modules.&lt;/li>
&lt;li>It is standard and most tutorials and explanations assume that this is the way it is installed.&lt;/li>
&lt;li>It makes the node-red command global so you can run it from anywhere.&lt;/li>
&lt;/ul>
&lt;h3 id="advantages">Advantages&lt;/h3>
&lt;p>Best for beginners unless you are prepared to learn about Node.js.&lt;/p>
&lt;h3 id="disadvantages">Disadvantages&lt;/h3>
&lt;p>Less flexible and possibly a little less secure. Not the best for &amp;ldquo;production&amp;rdquo; installations. Can confuse beginners into installing other Nodes and packages into global when they shouldn&amp;rsquo;t. Hard to work out where the global files are.&lt;/p>
&lt;h2 id="local-install">Local Install&lt;/h2>
&lt;ul>
&lt;li>This is a more &amp;ldquo;node.js way&amp;rdquo; of installing - global installations being good for exposing global commands but may sometimes be less secure.&lt;/li>
&lt;li>It is a more self-contained installation. Everything can be in 1 place under a single folder structure. This makes it easier to back-up everything together. But it doesn&amp;rsquo;t force you to work this way, you can keep your userDir folder separate if you like.&lt;/li>
&lt;li>It allows you to run different instances of Node-RED using different versions. Good for testing major Node-RED upgrades and for testing custom nodes or flows against different versions.&lt;/li>
&lt;li>You are in control. You know where everything is because you chose to put it there.&lt;/li>
&lt;li>You control access to all files and folders and so this can be a more flexible installation. You could also have different instances of node-red on the same device with different folder/file access levels. Possible development and test instances on the same device.&lt;/li>
&lt;li>A good way to create a more portable installation of Node-RED since the whole folder structure can be easily copied/archived, etc.&lt;/li>
&lt;li>It is my personal belief that this is also the best approach for people who want to learn how Node.js and/or Node-RED works. But then again, maybe that&amp;rsquo;s just my warped mind!&lt;/li>
&lt;/ul>
&lt;h3 id="advantages-1">Advantages&lt;/h3>
&lt;p>Best for flexibility and control. Good for control of security. Best for running different versions of Node-RED in parallel on one device. Good for ease of backup/recovery and for creating distributable copies of a Node-RED application. Best for embedding Node-RED into an existing or new Node.js app.&lt;/p>
&lt;h3 id="disadvantages-1">Disadvantages&lt;/h3>
&lt;p>Requires some knowledge of how Node.js and npm work.&lt;/p>
&lt;h2 id="containerised-install">Containerised Install&lt;/h2>
&lt;ul>
&lt;li>Uses either Docker or snap to containerise the installation.&lt;/li>
&lt;li>Isolates Node-RED from the host OS.&lt;/li>
&lt;li>Allow running multiple, independent instances of Node-RED, possible using different versions.&lt;/li>
&lt;/ul>
&lt;h3 id="advantages-2">Advantages&lt;/h3>
&lt;p>Best for enterprise use where containerisation is already well supported.&lt;/p>
&lt;h3 id="disadvantages-2">Disadvantages&lt;/h3>
&lt;p>Adds significant hidden complexity and requires good knowledge of the container technology to isolate and fix issues. Also likely to have higher resource requirements than running separate instances in other ways. Experience from the Node-RED forum suggests that a decent knowledge of Docker/snap is recommended.&lt;/p>
&lt;hr>
&lt;p>There is some additional information that I wrote in a recent blog post:&lt;/p>
&lt;p>&lt;a href="https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/">https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/&lt;/a>&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>FAQ 2: How can I run multiple instances of Node-RED on the same server device?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/</guid><pubDate>Fri, 06 Mar 2020 01:21:33 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/</guid><description><div>There are all sorts of reasons to want to run more than a single instance of Node-RED and several ways to do it.</div><div>&lt;ol>
&lt;li>
&lt;p>Use the command line settings to point to a different userDir folder.&lt;/p>
&lt;p>&lt;code>node-red -u /data/userDirectory&lt;/code>&lt;/p>
&lt;p>That lets you use different flows and configuration settings but only allows a single version of Node-RED.&lt;/p>
&lt;p>You still install Node-RED in the &amp;ldquo;standard&amp;rdquo; way, globally. While this is generally simpler for complete beginners,
it can lead to complexities later on. You should understand the strengths and weaknesses of npm global installs.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Install the Node-RED npm package locally rather than globally.&lt;/p>
&lt;p>This gives you not only the features from 1 but also allows you to run different versions of Node-RED in parallel. The &lt;a href="https://github.com/TotallyInformation/alternate-node-red-installer">alternate-node-red-installer&lt;/a> shows you how to do that.&lt;/p>
&lt;p>It also removes the need to install Node-RED globally which can lead to unexpected security issues.&lt;/p>
&lt;p>This is also the &amp;ldquo;Node.JS way&amp;rdquo; and likely to be a more welcome approach for organisations and teams that run other Node.JS services and systems.&lt;/p>
&lt;p>While slightly more complex to think about initially, especially for Node.JS beginners, it helps you understand how Node.js works, is easier
to work out where everything is kept and is likely to be easier to maintain in the longer term.&lt;/p>
&lt;p>I use npm&amp;rsquo;s script capability to make things really easy to start manually. Here are some examples. Note that I always make the &lt;code>userDir&lt;/code> folder a sub-folder of the master project folder (where Node-RED itself is installed). Keeps things neat and makes it trivial to backup the whole thing.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;start&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;node node_modules/node-red/red.js --userDir ./data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;start2&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;set DEBUG=express:* &amp;amp; nodemon node_modules/node-red/red.js --userDir ./data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inspect&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;node --inspect node_modules/node-red/red.js --userDir ./data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;log&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;sudo journalctl -u node-red -f -n 0 -o cat&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;update&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;npm install --unsafe-perm --production node-red&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So you can start manually using &lt;code>npm start&lt;/code> and start with debugging port active using &lt;code>npm run inspect&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Run Node-RED in a container such as the &lt;a href="https://github.com/node-red/node-red-docker">Docker container&lt;/a>.&lt;/p>
&lt;p>Allows multiple versions of Node-RED along with different configurations and supporting software and services.&lt;/p>
&lt;p>However, this comes at the cost of significantly greater complexity and resource overheads.
Unlikely to be worth doing except in specific circumstances &amp;amp; needs a reasonable level of understanding
of how Docker works.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>You will realise that I much prefer method 2 for all of my own installations. That&amp;rsquo;s why I wrote the alternate installer which
goes some way towards making installations easier and more consistent.&lt;/p>
&lt;p>For running Node-RED on system startup, please see the &lt;a href="https://nodered.org/docs/faq/starting-node-red-on-boot"> Starting Node-RED on boot&lt;/a> page in the docs.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>FAQ 1: Should I use a function node or a flow of core nodes?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq1-flow-vs-function/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq1-flow-vs-function/</guid><pubDate>Fri, 06 Mar 2020 01:16:35 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq1-flow-vs-function/</guid><description><div>There are usually many ways to achieve something in Node-RED. A common question is whether or when to use a function node or a collection of core nodes to achieve an outcome.</div><div>&lt;p>Whether I use one approach or the other depends on the complexity of the input vs the complexity of the output.
It really doesn&amp;rsquo;t matter except that it is often easier to read a single function node that several complex change nodes as an example.&lt;/p>
&lt;p>So my general rules of thumb for whether to replace a collection of nodes with a function node are:&lt;/p>
&lt;ul>
&lt;li>How difficult would this be to do in a pure flow? If it is just a couple of nodes, that&amp;rsquo;s fine, if it is 10 nodes then probably not fine.&lt;/li>
&lt;li>If I am using JSONata, how long is it taking me to puzzle over the JSONata code? If it is a few minutes then fine, otherwise use a function node!&lt;/li>
&lt;li>Did someone already write some JavaScript that I can purloin? If so then use it!&lt;/li>
&lt;/ul>
&lt;p>Of course, I know JavaScript reasonably well and if you don&amp;rsquo;t then your own rules might look a little different.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>A Glossary of Node-RED terms</title><link>https://it.knightnet.org.uk/kb/nr-qa/node-red-glossary/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/node-red-glossary/</guid><pubDate>Fri, 21 Jun 2019 17:40:30 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/node-red-glossary/</guid><description><div>For those not used to it, the terminology used in Node-RED can occasionally be confusing. Due in part to the overloading of some terms.
So I've come up with this glossary to help keep myself from getting confused.</div><div>&lt;p>A draft set of terminology for Node-RED, the flow-based visual programming tool.&lt;/p>
&lt;h1 id="glossary">Glossary&lt;/h1>
&lt;ul>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Editor&lt;!-- raw HTML omitted -->&lt;/strong>: The Node-RED admin UI. Where you edit and deploy flows.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Flows&lt;!-- raw HTML omitted -->&lt;/strong>: The collection of node instances and wires defined by the &lt;em>Flows file&lt;/em> loaded by Node-RED at run time.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Flow&lt;!-- raw HTML omitted -->&lt;/strong>: A tab in the Node-RED admin UI used to break Flows into more manageable chunks.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->flow&lt;!-- raw HTML omitted -->&lt;/strong>: A set of node instances and wires with in a Flow tab.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Package&lt;!-- raw HTML omitted -->&lt;/strong>: An npm package used, amongst other things, to install Node-RED Nodes.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Node&lt;!-- raw HTML omitted -->&lt;/strong>: The source definition for nodes that can be used in Node-RED Flows. Defined normally by an npm Package (though actually defined by 3 files: package.json, an html file for the admin UI and a JavaScript file for the server process).&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Node Instance&lt;!-- raw HTML omitted -->&lt;/strong>: An instance of a Node added to a flow. A Node (definition) may have many instances in Flows.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->node(s)&lt;!-- raw HTML omitted -->&lt;/strong>: same as Node Instance(s).&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->wire(s&lt;!-- raw HTML omitted -->)&lt;/strong>: The logical connectors between nodes. Conceptually, messages &amp;ldquo;travel&amp;rdquo; between nodes. In reality, they don&amp;rsquo;t, data is simply passed by reference (except for the edge cases where a message copy is forced).&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->message(s)&lt;!-- raw HTML omitted -->&lt;/strong>: Often referred to by the short name &lt;code>msg&lt;/code> which is the variable name generally used to reference the message. This is the data object used to communicate between nodes. Typically, it has the minimal definition: &lt;code>{{_msgid: uid, topic: undefined|string, payload: Object|Array|string|number}}&lt;/code> but other than requiring &lt;code>_msgid&lt;/code> (which is added by Node-RED), it may contain any valid, serialisable JavaScript.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->userDir&lt;!-- raw HTML omitted -->&lt;/strong>: The server folder that contains the &lt;em>Flows file&lt;/em>, &lt;code>settings.js&lt;/code> and other Node-RED configuration information. Typically residing at &lt;code>~/.node-red&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Project&lt;!-- raw HTML omitted -->&lt;/strong>: a &lt;em>Flows file&lt;/em> and other configuration files that allow rapid switching between Flows. Note that a project shares the same set of Packages (and therefore Nodes) and global Node-RED settings as all other projects. Only the &lt;em>Flows file&lt;/em>, matching credentials, a README and a minimalist package.json are part of a project. Projects are designed to enable teams to work together and can use GIT to manage the data collaboration.&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category></item><item><title>Creating a notification in the Admin UI</title><link>https://it.knightnet.org.uk/kb/nr-qa/notifying-admin/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/notifying-admin/</guid><pubDate>Sun, 16 Jun 2019 19:22:16 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/notifying-admin/</guid><description><div>Node-RED's admin UI has a built-in notification (toast) pop-up message feature.
This article explains how to use it when creating custom nodes as it isn't currently well documented.</div><div>&lt;p>&lt;code>RED.notify('Your message here', options)&lt;/code>&lt;/p>
&lt;p>This can be called from the script in your admin ui code &lt;code>&amp;lt;nodeName&amp;gt;.html&lt;/code>.&lt;/p>
&lt;p>By default, the notification will disappear after a few seconds.&lt;/p>
&lt;h1 id="options">Options&lt;/h1>
&lt;ul>
&lt;li>&lt;code>type&lt;/code>: {success|warning|error=} Adds style to the message box.&lt;/li>
&lt;li>&lt;code>fixed&lt;/code>: {boolean=false} Defaults to false, the notification will auto-remove after a few seconds.&lt;/li>
&lt;li>&lt;code>modal&lt;/code>: {boolean=false} If true, no other user interactions are allowed until the notification has cleared.&lt;/li>
&lt;li>&lt;code>timeout&lt;/code>: {ms=5000}: Specify the time in milliseconds a non-fixed notification will be displayed for.&lt;/li>
&lt;li>&lt;code>id&lt;/code>: {string=} Allows a notification to be updated.&lt;/li>
&lt;li>&lt;code>width&lt;/code>: {px=} Desired width in pixels. (Will be limited to the parent width)&lt;/li>
&lt;/ul>
&lt;h1 id="methods">Methods&lt;/h1>
&lt;ul>
&lt;li>&lt;code>.close()&lt;/code>: Close the notification (useful if &lt;code>fixed&lt;/code> option is &lt;code>true&lt;/code>).&lt;/li>
&lt;li>&lt;code>update&lt;/code>&lt;/li>
&lt;li>&lt;code>hideNotification&lt;/code>&lt;/li>
&lt;li>&lt;code>showNotification&lt;/code>&lt;/li>
&lt;/ul>
&lt;h1 id="example">Example&lt;/h1>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nx">myNotification&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">RED&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">notify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;My message in a box&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">modal&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">fixed&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;warning&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">buttons&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;text&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;cancel&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;click&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">myNotification&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;text&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;okay&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;class&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;primary&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;click&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">myNotification&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h1 id="references">References&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://discourse.nodered.org/t/node-red-admin-ui-display-message-to-user/12290">https://discourse.nodered.org/t/node-red-admin-ui-display-message-to-user/12290&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/node-red/node-red/blob/ccc3809daa3b03e7171cb6f4ccf4d6e0f1188bef/packages/node_modules/%40node-red/editor-client/src/js/ui/notifications.js#L16">https://github.com/node-red/node-red/blob/ccc3809daa3b03e7171cb6f4ccf4d6e0f1188bef/packages/node_modules/%40node-red/editor-client/src/js/ui/notifications.js#L16&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/node-red/node-red/wiki/API-Reference">https://github.com/node-red/node-red/wiki/API-Reference&lt;/a> (old but has some things not documented elsewhere)&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/node.js">Node.JS</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category></item><item><title>Cleaning up npm package install problems</title><link>https://it.knightnet.org.uk/kb/nr-qa/clean-up-npm/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/clean-up-npm/</guid><pubDate>Wed, 05 Jun 2019 07:05:39 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/clean-up-npm/</guid><description><div>Node-RED uses npm to manage package installations such as its nodes.
Sometimes, you can get into a situation where you start getting lots of npm installation or removal issues and it feels like you are going round in circles trying to fix things. If so, time to call it a day and to get drastic! Here, I try to explain an easy way to fix things quickly and completely without side effects.</div><div>&lt;p>Node-RED is built over Node.js which uses &lt;code>npm&lt;/code> as its library (AKA package) manager. It is great to have a standard mechanism to manage libraries but the complexities of managing JavaScript based packages sometimes trips things up.&lt;/p>
&lt;p>Once you&amp;rsquo;ve tried for a bit to understand what the issues are, it may be time to call time and get drastic.&lt;/p>
&lt;p>The following commmands will clean out the packages installed for your live instance of Node-RED - assuming you have it installed via the &amp;ldquo;standard&amp;rdquo; default method. If not, you will need to adjust the folder you operate in.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/.node-red
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm package-lock.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -R node_modules
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That will cleanly reinstall all of the packages marked in your &lt;code>package.json&lt;/code> file. So make sure that is correct first. Every time you install a package (as long as you have reasonably up-to-date versions of Node.js and npm) whether from the NR admin ui or command line, it gets added to package.json.&lt;/p>
&lt;p>I now always remove the lock file as well if I&amp;rsquo;m having issues as that can be the cause of some issues. The lock file isn&amp;rsquo;t generally needed in NR installations.&lt;/p>
&lt;p>Note, as always, I&amp;rsquo;ve assumed you have a &amp;ldquo;standard&amp;rdquo; install of Node-RED which puts your userDir as &lt;code>~/.node-red&lt;/code> (and the equivalent on Windows). If you use an installation scheme like mine, it will be in a different place as noted by the command used to start NR.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/npm">npm</category><category domain="https://it.knightnet.org.uk/tags/node.js">Node.JS</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/debugging">Debugging</category></item><item><title>Analysing the Performance of Node-RED</title><link>https://it.knightnet.org.uk/kb/nr-qa/analysing-performance/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/analysing-performance/</guid><pubDate>Fri, 19 Apr 2019 13:23:06 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/analysing-performance/</guid><description><div>Node-RED is a powerful platform for prototyping and rapid development but it is complex. It has a lot of moving parts and it can be hard to know what might be causing performance bottlenecks.
This article tries to give some hints and tips about analysing those bottlenecks and how to resolve them.</div><div>&lt;p>Sorry, this is draft and far from complete. Please leave comments if you have something useful to add. Thought I would publish anyway in case anyone finds it useful. I will try to come back to it in the future. If you leave a comment, it will remind me. :-)&lt;/p>
&lt;h1 id="platform">Platform&lt;/h1>
&lt;p>Before starting more detailed analysis, the first thing to do is to look at the platform being used to run Node-RED.&lt;/p>
&lt;p>Often, something like a Raspberry Pi or other single-board computer (SBC) is being used. They have very limited resources and often slow storage (e.g. SD-Cards). So it is very easy to overload them and kill performance.&lt;/p>
&lt;p>To analyse this, you need to use a tool such as &lt;code>top&lt;/code>. Better still, get something a bit more comprehensive such as &lt;code>glances&lt;/code>. Either way, these will tell you how much CPU and memory (RAM) is being used and by what. Start by looking at the three &amp;rsquo;load&amp;rsquo; values, these should all be fairly low, if they are going over about 2-3 regularly then you have an issue.&lt;/p>
&lt;p>Next look at the &amp;lsquo;swap&amp;rsquo;. If this is being used regularly, you will have a performance bottleneck because memory (RAM) is being overused. To fix this, you have to unload some services. If using the &lt;code>glances&lt;/code> tool, it will show a warning if the memory is swapping.&lt;/p>
&lt;p>The easiest way to remove load is likely to be turning off the &amp;lsquo;desktop&amp;rsquo;. This gives you a GUI that you directly interact with via keyboard and monitor. Removing this will remove lots of load on memory and CPU. Have a look at articles that explain how to run your device &amp;lsquo;headless&amp;rsquo;. You will need to be able to connect to your device over the network from another device.&lt;/p>
&lt;p>After that, if there are still issues, you need to look at taking off services that you don&amp;rsquo;t actually need running.&lt;/p>
&lt;p>Finally, if you still have issues, you will need to think about splitting services between multiple devices or using a more powerful device.&lt;/p>
&lt;h1 id="back-end-server">Back End (server)&lt;/h1>
&lt;h2 id="using-nodejs---inspect-option">Using Node.JS &lt;code>--inspect&lt;/code> option&lt;/h2>
&lt;h1 id="front-end-browser-node-red-admin-ui">Front End Browser (Node-RED Admin UI)&lt;/h1>
&lt;p>For any browser performance issues, you firstly need to ensure that the problem is actually coming from something related to Node-RED. So you should turn off any browser extensions before continuing. An extension such as SimpleExtManager for Chromium browsers will assist with easily turning on/off extensions.&lt;/p>
&lt;h2 id="browser-performance-profiling">Browser Performance Profiling&lt;/h2>
&lt;p>Using your browser&amp;rsquo;s developer tools, you are able to record and analyse a performance analysis. The Chromium developer tools have three tabs to help with this. Performance, Memory and Application.&lt;/p>
&lt;p>The Performance tab is perhaps the easiest to get going with. Click on that tab and then start profiling. Leave that for an amount of time that you estimate will let you see any ongoing performance issues. That might be just a few seconds or a few minutes. You will want to tick the &amp;ldquo;memory&amp;rdquo; option and probably don&amp;rsquo;t need the &amp;ldquo;Screenshots&amp;rdquo; option.&lt;/p>
&lt;p>The thing to look at first is likely to be the memory utilisation. There is a graph 1/2 way down the display that shows you some important metrics including the &amp;ldquo;JS Heap&amp;rdquo;. See how big that is getting by hovering over the line. Also look at how fast it is growing. You should see that the heap reduces periodically as the JavaScript engine does a &amp;lsquo;garbage collection&amp;rsquo;.&lt;/p>
&lt;p>You can also do multiple recordings and compare the heap over a longer period.&lt;/p>
&lt;h1 id="front-end-dashboard-uibuilder-http-in-out-nodes-etc">Front End (Dashboard, uibuilder, http-in/-out nodes, etc.)&lt;/h1></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/node.js">Node.JS</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/debugging">Debugging</category><category domain="https://it.knightnet.org.uk/tags/performance">Performance</category></item><item><title>A more comfortable way to edit the code for creating custom nodes</title><link>https://it.knightnet.org.uk/kb/nr-qa/easier-writing-custom-node/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/easier-writing-custom-node/</guid><pubDate>Mon, 18 Mar 2019 17:38:40 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/easier-writing-custom-node/</guid><description><div>Node-RED allows us to create custom nodes to extend the features. While this is a great feature, actually writing the code can be tricky. In part because the code for the admin configuration panel is contained in an html file containing 3 script entries that are Node-RED specific. This post shows you a relatively easy way to split that into 3 files and combine them with a build step using an npm cross-platform script.</div><div>&lt;p>When defining a new node in Node-RED, the code is contained in two files. An html file and a
JavaScript file.&lt;/p>
&lt;p>The JavaScript file contains the core code that is loaded into the server and does most of the
hard work. As this is a standard js file, nothing special is needed to edit it, your favourite
code editor or IDE will do the job nicely. My preference is VScode from Microsoft.&lt;/p>
&lt;p>However, the html file isn&amp;rsquo;t very comfortable to edit because any HTML it actually contains is
wrapped in some special &lt;code>&amp;lt;script&amp;gt;&lt;/code> tags that are only recognised by Node-RED and they throw out
your code editor making things really hard to read and process.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span> &lt;span class="nx">js&lt;/span> &lt;span class="nx">that&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">run&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">admin&lt;/span> &lt;span class="nx">ui&lt;/span> &lt;span class="nx">when&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">configuration&lt;/span> &lt;span class="nx">panel&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">opened&lt;/span> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-template-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span> &lt;span class="nx">html&lt;/span> &lt;span class="nx">that&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">used&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">admin&lt;/span> &lt;span class="nx">node&lt;/span> &lt;span class="nx">configuration&lt;/span> &lt;span class="nx">panel&lt;/span> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-help-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span> &lt;span class="nx">html&lt;/span> &lt;span class="nx">that&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">used&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">information&lt;/span> &lt;span class="nx">sidebar&lt;/span> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To get round this, I&amp;rsquo;ve started creating a separate &lt;code>./node-src&lt;/code> folder and splitting the
content for this file into three source files: &lt;code>script.js&lt;/code>, &lt;code>template.html&lt;/code> and &lt;code>help.html&lt;/code>.&lt;/p>
&lt;p>Of course, you can call them whatever you like &amp;amp; will probably want to include the node-name
if you are creating multiple nodes.&lt;/p>
&lt;p>There is then a cross-platform executable that replaces the empty master with the contents of
the three files.&lt;/p>
&lt;p>Now all you have to do is to remember to run the build before pushing your changes to your repo and before publishing a new version to npm. That can also be automated as long as you are using npm to manage git. Look at the &lt;code>prepublishOnly&lt;/code> script which will automatically allow you to run the build before publishing. You can do similar things with git by &lt;a href="https://docs.npmjs.com/misc/scripts">setting up the appropriate scripts&lt;/a>.&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;p>To get this all working, you will need to firstly install a package called &lt;code>replace-in-file&lt;/code>.
Install this to the root of the folder holding you node.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm install replace-in-file -D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that I install it as a devDependency because it is only needed for the node&amp;rsquo;s editors and
not for end users.&lt;/p>
&lt;p>Next, add the following to the &lt;code>package.json&lt;/code> file, also in the root folder of your node.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;build&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;node ./bin/mergehtml&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;prepublishOnly&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;npm run build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>&lt;span class="err">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;bin&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;mergehtml&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;./bin/mergehtml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This lets you run the build on any platform supported by npm, including Windows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm run build
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, create folders &lt;code>./bin&lt;/code> and &lt;code>./node-src&lt;/code>. Into &lt;code>node-src&lt;/code>, put the three files and your master template. Into &lt;code>bin&lt;/code> put the &lt;code>mergehtml.js&lt;/code> file shown below.&lt;/p>
&lt;h2 id="binmergehtmljs">./bin/mergehtml.js&lt;/h2>
&lt;p>This is the code that does the magic. I overwrites the nodes html file (&lt;code>./nodes/node.html&lt;/code> in this example) with the blank template then replaces the three &lt;code>&amp;lt;script&amp;gt;&lt;/code> tags with the contents of the files from &lt;code>node-src&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/env node
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="ch">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/** Merge the various sections of nodes/uibuilder.html from the files in node-src/
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * Note that this is run from `npm run mergehtml` which puts the working directory
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * to the root, not `./bin`
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">*/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">replace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;replace-in-file&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">fs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;fs&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//const path = require(&amp;#39;path&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// nodes\lib\uibuilder-help.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">myhelp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/help.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">mytemplate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/template.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">myscript&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/script.js&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Copy template - overwrite the nodes html file
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">copyFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/node.html&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;./nodes/node.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">files&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;./nodes/uibuilder.html&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sr">/(&amp;lt;script type=&amp;#34;text\/javascript&amp;#34;&amp;gt;)(.|\n)*?(&amp;lt;\/script&amp;gt;)/gmi&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sr">/(&amp;lt;script type=&amp;#34;text\/x-red&amp;#34; data-template-name=&amp;#34;uibuilder&amp;#34;&amp;gt;)(.|\n)*?(&amp;lt;\/script&amp;gt;)/gmi&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sr">/(&amp;lt;script type=&amp;#34;text\/x-red&amp;#34; data-help-name=&amp;#34;uibuilder&amp;#34;&amp;gt;)(.|\n)*?(&amp;lt;\/script&amp;gt;)/gmi&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`$1\n&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">myscript&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">\n$3`&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`$1\n&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">mytemplate&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">\n$3`&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`$1\n&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">myhelp&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">\n$3`&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">options&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">changes&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MERGEHELP: data-help-name Modified files:&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">changes&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;, &amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">error&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MERGEHELP: Error occurred:&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">error&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MERGEHELP: Completed&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="node-srcnodehtml">./node-src/node.html&lt;/h2>
&lt;p>Here is the content of the &lt;code>node.html&lt;/code> file - you can use this for any project. You can put text between the tags if you like, even change the order of them if you prefer, the code should still work just fine. Obviously, any text you put between the open/close tags will be replaced.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-template-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-help-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category></item><item><title>How to create secure certificates</title><link>https://it.knightnet.org.uk/kb/nr-qa/https-valid-certificates/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/https-valid-certificates/</guid><pubDate>Sun, 14 Oct 2018 15:54:20 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/https-valid-certificates/</guid><description><div>Generate certificates for Node-RED that are trusted by all modern browsers. This will let you access Node-RED (and other services) over an encrypted HTTPS link.</div><div>&lt;p>&lt;strong>THIS ARTICLE IS CURRENTLY IN DRAFT - it is still being developed. Please feel free to add constructive comments and corrections below.&lt;/strong>&lt;/p>
&lt;h2 id="the-problem">The problem&lt;/h2>
&lt;p>Argh! Why is it so hard to create and manage trusted certificates for &amp;ldquo;internal&amp;rdquo; services!
While you can create your own &amp;ldquo;self-signed&amp;rdquo; certificates, all modern browsers now mark these as insecure and try
to stop you from accessing them. This is wrong. Browsers should allow access to self-signed certificates if they
point to a non-routable IP address (192.168.&lt;em>.&lt;/em> or 10.&lt;em>.&lt;/em>.* for example) or an invalid root domain such as &lt;code>*.something.local&lt;/code>.&lt;/p>
&lt;p>Also, we really probably don&amp;rsquo;t want to expose all of our internal servers to the bad, wide Internet - this is generally a really
bad idea unless you are good at securing things &lt;strong>and&lt;/strong> have the time to keep making sure they stay secure as things update.&lt;/p>
&lt;h2 id="possible-fixes">Possible fixes&lt;/h2>
&lt;p>You could manually add a new (self-signed) root certificate to all devices needing access to your internal services so that your self-signed certificates are trusted - try getting that past the rest of the family!&lt;/p>
&lt;p>The only other alternative is to use a trusted CA. Since I&amp;rsquo;m assuming you are doing this for testing or for use at home,
I also assume that you don&amp;rsquo;t want to spend lots of money. Trusted certificates usually cost - a lot! Often US$100 per year or more.&lt;/p>
&lt;p>However, there is one supplier that issues free trusted certificates. &lt;a href="https://letsencrypt.org">Let&amp;rsquo;s Encrypt&lt;/a>. This is a great service for a great price. But it comes with some overheads.&lt;/p>
&lt;h2 id="its-never-simple">It&amp;rsquo;s never simple&lt;/h2>
&lt;p>OK, so assuming we want to use Let&amp;rsquo;s Encrypt (LE), what issues do we now need to overcome?&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Firstly, we &lt;strong>have&lt;/strong> to have a publicly known domain address. You cannot issue a publicly trusted certificate to an IP address
or non-routable domain name.&lt;/p>
&lt;p>Note that certificates are generally issued to specific domain names so that &lt;code>www.thing.com&lt;/code> and &lt;code>thing.com&lt;/code> are different names. We don&amp;rsquo;t want to mess with all of that all the time, especially if we are doing lots of tests. So we can now use a &amp;ldquo;wildcard&amp;rdquo; certificate for &lt;code>*.thing.com&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Next, we have to have a way for the Let&amp;rsquo;s Encrypt servers to verify that our domain name is actually ours to do something with.&lt;/p>
&lt;p>By default, the LE service wants to have access back to our server in order to verify that it is ours.
This would bring us back to the issue of exposing our server to the Internet, something that we prefer not
to do unless we really have to.&lt;/p>
&lt;p>Thankfully LE now has an alternative called &lt;code>DNS-01&lt;/code>. Unfortunately, this requires our DNS (Domain Name Service) to support
a particular type of secure API. For that we can use Cloudflare or any of the other DNS services listed on the LE website.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Finally, we have to renew the certificate every 3 months since that is all that Let&amp;rsquo;s Encrypt allows us to keep a certificate for. This is a pain but it does have some security benefits.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s look at the details of how to do this.&lt;/p>
&lt;h2 id="1-get-a-domain">1. Get a domain&lt;/h2>
&lt;p>We need a domain and we need it to be one that we can, at least to some degree, control. So some of the free &amp;ldquo;dynamic DNS&amp;rdquo; services probably won&amp;rsquo;t cut it. However, we can get our very own domain for a few £/$ per year so go ahead and do that. Save yourself some pain in the next bit by using Cloudflare themselves to register your domain.&lt;/p>
&lt;p>Once we have a domain, we need to let it be managed by a DNS that supports the &lt;code>DNS-01&lt;/code> verification API. You might be lucky in that your domain registrar already supports that. In most cases, they won&amp;rsquo;t. So now you have to hand over control of the DNS settings to someone
like &lt;a href="https://cloudflare.com/">Cloudflare&lt;/a> who&amp;rsquo;s free service is plenty for what we need. Your domain registrar will tell you how to
change the name servers that control your domain. Don&amp;rsquo;t worry, your registrar remains the overall controller so renewals are not an issue.&lt;/p>
&lt;p>As we will be using a wildcard certificate, we don&amp;rsquo;t need to worry about setting up specific names at this point.&lt;/p>
&lt;p>Also, as we will be using DNS-01 verification, we don&amp;rsquo;t need to point anything at our public IP address. Use the DNS settings to point the default &amp;ldquo;A&amp;rdquo; DNS entry at a dummy IP address like &lt;code>10.10.10.10&lt;/code>. That&amp;rsquo;s fine and it means that we won&amp;rsquo;t be leaking any information about our private network.&lt;/p>
&lt;h2 id="2a-install-a-client-for-lets-encrypt">2a. Install a client for Let&amp;rsquo;s Encrypt&lt;/h2>
&lt;p>There are lots of clients for LE, see the list on their website. For this post, I&amp;rsquo;m going to use a Raspberry Pi as I have one running permanently controlling my home automation system. You could also use a NAS or any PC. Even some routers such as the ever excellent &lt;a href="https://www.ubnt.com/edgemax/edgerouter-lite/">Ubiquity EdgeRouter Lite&lt;/a> &lt;a href="https://github.com/hungnguyenm/edgemax-acme">can be used&lt;/a>.&lt;/p>
&lt;p>I am going to use a 3rd-party BASH (Linux command-line) script as this is a lot simpler than the official Python based script.&lt;/p>
&lt;p>From your Pi, follow the &lt;a href="https://github.com/Neilpang/acme.sh#1-install-online">instructions to install the script&lt;/a>. Start a remote command line using an SSH client from a convenient computer. Log in using an ID that is allowed to do administration on the Pi. Then install the script using &lt;code>curl https://get.acme.sh | sh&lt;/code>. Note that I didn&amp;rsquo;t bother to become root as I need to use the certificate with a Node.JS service that isn&amp;rsquo;t run globally as root (this is best practice, don&amp;rsquo;t run things as root as that opens up additional security issues). I also ran &lt;code>alias acme.sh=~/.acme.sh/acme.sh&lt;/code> manually rather than logging out and back in again to pick up the defined alias.&lt;/p>
&lt;h2 id="2b-get-the-cloudflare-api-details">2b. Get the Cloudflare API details&lt;/h2>
&lt;p>So, we&amp;rsquo;re ready now right? Not quite. First we need somewhere to actually run the client tool that will initially get our first certificate and that will then run periodically to renew the certificate.&lt;/p>
&lt;p>As we are using DNS-01 validation with Cloudflare, we need the API access details. Jump ahead in the &lt;code>acme.sh&lt;/code> instructions to the part on &lt;a href="https://github.com/Neilpang/acme.sh#7-automatic-dns-api-integration">DNS API integration&lt;/a> since that&amp;rsquo;s what we need in order to avoid exposing our internal servers to the Internet. We need a configuration file. The &lt;a href="https://github.com/Neilpang/acme.sh/tree/master/dnsapi#how-to-use-dns-api">instructions are in the the &lt;code>dnsapi&lt;/code> folder&lt;/a>.&lt;/p>
&lt;p>Log into your Cloudflare account, go to &amp;ldquo;My Profile&amp;rdquo; under the little person icon top-right. Pick up your verified email address then scroll down to the bottom &amp;ldquo;API Keys&amp;rdquo; &amp;amp; click on &amp;ldquo;View&amp;rdquo; against the &amp;ldquo;Global API Key&amp;rdquo;. While you are there, turn on 2-factor authentication to protect your account and services. &lt;strong>Keep this information safe! If someone gets hold of it, they can change your DNS and other settings.&lt;/strong>&lt;/p>
&lt;p>Issue the commands &lt;code>export CF_Key=&amp;quot;sdfsdfsdfljlbjkljlkjsdfoiwje&amp;quot; &amp;amp;&amp;amp; export CF_Email=&amp;quot;xxxx@sss.com&amp;quot;&lt;/code> which temporarily puts the security information into environment variables.&lt;/p>
&lt;h2 id="2c-get-our-first-certificate">2c. Get our first certificate&lt;/h2>
&lt;p>Now we are ready to try and get our first certificate. Run the following from your SSH command line:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">acme.sh --issue --dns dns_cf -d example.com -d *.example.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Obviously replacing the domain names with your own. The entry that starts with &lt;code>*&lt;/code> gives you a wildcard certificate so that you
can use this certificate with any sub-domain like &lt;code>www.example.com&lt;/code> or &lt;code>fred.example.com&lt;/code>.&lt;/p>
&lt;h2 id="3-certificate-renewals">3. Certificate renewals&lt;/h2>
&lt;p>As mentioned, LE certificates expire every 90 days. Thankfully, the script we just ran not only does gets us our first certificate, it &lt;a href="https://github.com/Neilpang/acme.sh#11-how-to-renew-the-certs">sets up a script to renew the certificate every 60 days&lt;/a> - giving some extra time for the occasional renewal failures. You can adjust the renewal in the configuration file if you really want to. You don&amp;rsquo;t have to worry about restarting this if your device reboots.&lt;/p>
&lt;p>Once the script has run for the first time, go ahead and &lt;a href="https://github.com/Neilpang/acme.sh#13-how-to-upgrade-acmesh">run the following so that the script itself auto-updates&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">acme.sh --upgrade --auto-upgrade
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="using-names-instead-of-ip-addresses">Using names instead of IP addresses&lt;/h2>
&lt;p>New we have a certificate that we can use for any service simply by referencing that service by name.&lt;/p>
&lt;p>Note, though, that you can no longer reference your services by IP address.&lt;/p>
&lt;p>For example &lt;code>pi.example.com&lt;/code> but not &lt;code>192.168.1.20&lt;/code>.&lt;/p>
&lt;p>Using an IP address will throw an error in modern browsers.&lt;/p>
&lt;p>So a slight wrinkle in our effort to get rid of browser errors since, most home servers are access via an IP address not a name. How do we fix that? We have a couple of options.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Use your router&amp;rsquo;s DHCP or DNS service to define names for local services.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Install a DNS service on a local device.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Update the &lt;code>hosts&lt;/code> file on every client device.&lt;/p>
&lt;p>This may work if you only have one or two laptops and nothing else but even then it is clunky. With mobile devices, it won&amp;rsquo;t be possible anyway.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Both 1 and 2 will require some configuration. What we are doing is creating names that point to local IP addresses. How you do this, depends on the router or DNS server you have.&lt;/p>
&lt;p>In either case, we really want a &lt;em>fixed&lt;/em> IP address to work with so that our Pi (or other device running our services) is always at the same address. All routers should have the ability to do this so look for the &lt;code>DHCP&lt;/code> settings. You will need to know the MAC address of the device, it looks something like &lt;code>b8:27:eb:df:49:7e&lt;/code> (you may see it with upper case letters and/or without the colons). The router&amp;rsquo;s DHCP pages will have a list of active &amp;ldquo;leases&amp;rdquo; that will show that information. You use that address, which is defined by a network interface on a device, to issue a fixed IP address via the DHCP service. Make sure that your fixed addresses don&amp;rsquo;t overlap with the range defined for DHCP to issue dynamically.&lt;/p>
&lt;p>Sometimes, your DHCP server will let you define a name to go with this configuration. That&amp;rsquo;s great because you can now specify the name to include the domain that the certificate is issued to. e.g. &lt;code>pi.example.com&lt;/code>.&lt;/p>
&lt;p>The Ubiquiti EdgeRouter&amp;rsquo;s will let you define names manually using a Wizard called &amp;ldquo;&lt;a href="https://192.168.1.1/#Wizard/feature/DNS_host_names">DNS Host Names&lt;/a>&amp;rdquo;. Some other routers may give you access to the router&amp;rsquo;s &lt;code>hosts&lt;/code> file.&lt;/p>
&lt;p>If you can&amp;rsquo;t do that on your router, you will need a DNS server that will let you define names to IP addresses. That&amp;rsquo;s a bit more complex and beyond the scope of this, already rather long, blog post I&amp;rsquo;m afraid.&lt;/p>
&lt;h2 id="using-your-certificate">Using your certificate&lt;/h2>
&lt;p>Now you have the certificate and can access your servers via names instead of IP addresses so you are ready - finally - to configure the services to use the certificates.&lt;/p>
&lt;p>You can configure most TCP/IP based services to use TLS (Transport Layer Security) which is what we will mostly want our certificate for. Most people will be familiar with accessing web pages over HTTPS which is TLS applied to HTTP. But we can also use the certificate to secure communications for file transfers (FTPS or SFTP), Email (SMTPS, IMAPS, etc.).&lt;/p>
&lt;h3 id="node-red">Node-RED&lt;/h3>
&lt;p>Node-RED is a service built over NodeJS and ExpressJS. It creates a web server that we can secure using our certificate. The same certificate will also be used to help to secure websocket communications.&lt;/p>
&lt;p>Once you&amp;rsquo;ve changed the settings below, remember to access Node-RED using the server name instead of the IP address. You will need to restart the Node-RED service.&lt;/p>
&lt;h4 id="settingsjs">settings.js&lt;/h4>
&lt;p>This file is where we configure Node-RED to use HTTPS. Note that the settings are the same as those from NodeJS so you can check out any other settings in the NodeJS documentation.&lt;/p>
&lt;p>The &lt;code>settings.js&lt;/code> file is found in your &lt;code>userDir&lt;/code> folder which is generally &lt;code>~/.node-red&lt;/code> if installed according to the instructions on the Node-RED website. &lt;code>~&lt;/code> is the &amp;ldquo;home&amp;rdquo; folder for the user ID running the Node-RED service.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">module&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">exports&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">fs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;fs&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">https&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Don&amp;#39;t forget to adjust the paths below
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// according to your installation
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">key&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;..&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s1">&amp;#39;.acme.sh&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s1">&amp;#39;&amp;lt;server_name&amp;gt;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;lt;server_name&amp;gt;.key&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cert&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;..&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s1">&amp;#39;.acme.sh&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s1">&amp;#39;&amp;lt;server_name&amp;gt;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;fullchain.cer&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Where &lt;code>&amp;lt;server_name&amp;gt;&lt;/code> is something like &lt;code>pi2.example.com&lt;/code> - whatever you have defined as the name associated with the IP address.&lt;/p>
&lt;h3 id="mqtt-broker-mosquitto">MQTT broker Mosquitto&lt;/h3>
&lt;blockquote>
&lt;p>NOTE: This section is not complete as I&amp;rsquo;ve not managed to get this working as yet.&lt;/p>
&lt;/blockquote>
&lt;p>Many IoT systems make use of MQTT for publish and subscribe handling of data from devices. The more we embed IoT into our lives, the more important it is to secure the MQTT brokers. By enabling encrypted communications via TLS and then configuring user ID&amp;rsquo;s and strong passcodes between devices and the broker, we can help make things a lot more secure.&lt;/p>
&lt;p>Mosquitto is one of the most common MQTT brokers due to its small size and high performance.&lt;/p>
&lt;p>On a Linux system, Mosquitto configuration files are found in &lt;code>/etc/mosquitto&lt;/code>. Try not to edit &lt;code>/etc/mosquitto/mosquitto.conf&lt;/code>, instead add your own file to &lt;code>/etc/mosquitto/conf.d&lt;/code>. It will be loaded automatically and will not be overridden when Mosquitto is upgraded.&lt;/p>
&lt;h4 id="etcmosquittoconfdcustomconf">/etc/mosquitto/conf.d/custom.conf&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="webmin">Webmin&lt;/h3>
&lt;p>Webmin is a really helpful remote administration tool for Linux servers. Being web-based means that you can use your certificate with it. Replace the default certificate by going to &lt;em>Webmin &amp;gt; Webmin Configuration &amp;gt; SSL Settings&lt;/em> (https://&amp;lt;domain_name&amp;gt;:10000/webmin/edit_ssl.cgi?xnavigation=1).&lt;/p>
&lt;p>Then change the default &lt;em>Private key file&lt;/em> path with the the one generated by the &lt;code>acme.sh&lt;/code> script (it ends with &lt;code>.key&lt;/code>). Also change the &lt;em>certificate file&lt;/em> setting to be the file &lt;code>fullchain.cer&lt;/code> in the same folder.&lt;/p>
&lt;p>Now restart Webmin from the main Webmin configuration page or issue the command &lt;code>sudo systemctl restart webmin&lt;/code>.&lt;/p>
&lt;p>No more certificate errors as long as you remember to use your server name not IP address.&lt;/p>
&lt;h3 id="web-servers">Web servers&lt;/h3>
&lt;p>There are so many posts about configuring any of the regular web servers with certificates that I&amp;rsquo;m not going to repeat them here.&lt;/p>
&lt;p>Just remember that you have all the certificate and key files that you need so you only need to make the folder available (read-only) to the user ID that runs the web server. Then to configure the appropriate files.&lt;/p>
&lt;h3 id="router-ubiquiti-edgerouter">Router (Ubiquiti EdgeRouter)&lt;/h3>
&lt;p>There is a &lt;a href="https://github.com/hungnguyenm/edgemax-acme">dedicated script for EdgeOS&lt;/a> which you may wish to use for simplicity. Otherwise, you will need to remember to securely transfer the fullchain.cer and xxx.key files to the router&amp;rsquo;s filing system each time they are updated.&lt;/p>
&lt;p>You can change to custom key and certificate files using the &amp;ldquo;Config Tree&amp;rdquo; &lt;em>service / gui&lt;/em>.&lt;/p>
&lt;h3 id="influxdb-and-telegraf">InfluxDB and Telegraf&lt;/h3>
&lt;p>InfluxDB is a timeseries database that is very efficient at recording data over time. Great for sensor data. All access is, by default, over HTTP so it is possible to configure it to use HTTPS.&lt;/p>
&lt;p>Telegraf is from the same vendor as InfluxDB. It can also be configured to talk to InfluxDB over HTTPS.&lt;/p>
&lt;h3 id="grafana">Grafana&lt;/h3>
&lt;blockquote>
&lt;p>NOTE: Grafana seems to want to be able to &lt;strong>write&lt;/strong> to something - either the folder or the cert/key files - that it shouldn&amp;rsquo;t do so currently is failing. I haven&amp;rsquo;t had time to resolve this as yet.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;code>/etc/grafana/grafana.ini&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">[server]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Protocol (http, https, socket)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">protocol = https
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># https certs &amp;amp; key file
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cert_file = /home/pi/.acme.sh/&amp;lt;server_name&amp;gt;/fullchain.cer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cert_key = /home/pi/.acme.sh/&amp;lt;server_name&amp;gt;/&amp;lt;server_name&amp;gt;.key
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/categories/it-security">it-security</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/security">security</category></item><item><title>How to secure Node-RED</title><link>https://it.knightnet.org.uk/kb/nr-qa/securing-node-red/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/securing-node-red/</guid><pubDate>Sun, 30 Sep 2018 13:48:14 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/securing-node-red/</guid><description><div>Node-RED is increasingly used in situations that require reasonable security. Up to now, however, the information required to secure it correctly has been fragmented. This article aims to give an end-to-end outline to enable anyone to secure their installation.</div><div>&lt;p>&lt;strong>THIS ARTICLE IS CURRENTLY IN DRAFT - it is still being developed. Please feel free to add constructive comments and corrections below.&lt;/strong>&lt;/p>
&lt;p>I am going to attempt to describe the various options and configurations that you will need to think
about in order to secure an instance of Node-RED. This is probably going to be a &lt;em>long&lt;/em> article!&lt;/p>
&lt;p>Please see my other articles &lt;em>&lt;a href="https://it.knightnet.org.uk/kb/nr-qa/node-red-internet/">Making Node-RED available over the Internet&lt;/a>&lt;/em> and &lt;em>&lt;a href="https://it.knightnet.org.uk/kb/nr-qa/telegram-bot/">Secure Home Automation Controls via a Telegram Bot&lt;/a>&lt;/em> for other ideas about the security of Node-RED in regard to use over the Internet and how to avoid having to worry about some of the issues dealt with here.&lt;/p>
&lt;h2 id="warning-and-disclaimer">Warning and disclaimer&lt;/h2>
&lt;p>This is my best view of securing Node-RED. I&amp;rsquo;ve not been a professional developer in a long time and
I am not a professional security analyst (I&amp;rsquo;m a IT technology and information security manager).&lt;/p>
&lt;p>So you must not assume that this article covers every issue. You must also not assume, even if you
follow every best practice, that an instance of Node-RED will be &amp;ldquo;Secure&amp;rdquo;. It may not be for many reasons.&lt;/p>
&lt;p>&lt;strong>Get your system and its infrastructure tested to destruction by professionals.&lt;/strong>&lt;/p>
&lt;p>Hopefully though, this article will at least let you see the issues and have a reasonable go at making
your instance of Node-RED a little more secure.&lt;/p>
&lt;h2 id="terminology">Terminology&lt;/h2>
&lt;p>A few words and phrases that will be used along with the least technical descriptions that I can come up with.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Term&lt;/th>
&lt;th>Meaning&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a href="https://en.wikipedia.org/wiki/Encryption">Encryption&lt;/a>&lt;/td>
&lt;td>Changing human readable information into something that requires a special key before it can be understood.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a href="https://en.wikipedia.org/wiki/Authentication">Authentication&lt;/a>&lt;/td>
&lt;td>Providing a secured identifier to a system to prove that the person accessing the system is who they &lt;em>claim&lt;/em> to be.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a href="https://en.wikipedia.org/wiki/Authorization">Authorisation&lt;/a>&lt;/td>
&lt;td>Controlling what information a user of a system is allowed to see and what actions they are allowed to take.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">TLS&lt;/a>&lt;/td>
&lt;td>A defined protocol for securing connections between systems and applications. In basic use, it provides a minimum level of &lt;em>authentication&lt;/em> of a server (via a certificate chain of trust) and facilitates encrypted communications with that server.&lt;!-- raw HTML omitted -->It also has additional mechanisms that will also provide a minimum level of trust of the client application. However, this is rarely used in Internet web applications.&lt;!-- raw HTML omitted -->TLS may be used to secure many different application and system interactions, not just between a browser and a server.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol">HTTP&lt;/a>(&lt;a href="https://en.wikipedia.org/wiki/HTTPS">S&lt;/a>)&lt;/td>
&lt;td>The main web protocol that lets browsers get human readable information from web servers. HTTPS is HTTP secured with TLS (used to also allow a protocol called SSL but that is deprecated as insecure). Ideally, &lt;em>every&lt;/em> connection to a server from a browser should be over HTTPS since the use of &lt;a href="https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https">HTTP allows some pretty bad things to happen&lt;/a>.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h1 id="the-basic-architecture-of-node-red">The basic architecture of Node-RED&lt;/h1>
&lt;p>To help us understand what needs to be secured, here is the basic technical architecture of Node-RED. From the outside in. This is only one way to view the architecture of course, I&amp;rsquo;ve tried to keep things as simple as possible.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;em>Your flows, Dashboard and other pages served by Node-RED&lt;/em>&lt;/p>
&lt;p>This is the &amp;ldquo;code&amp;rdquo; that you (or your users/administrators) have put together.&lt;/p>
&lt;p>Node-RED is a general purpose tool and so is capable of creating web pages and various other types of connections such as websockets, TCP/UDP connections and much more.&lt;/p>
&lt;p>Anything that is created at this level either must be secured by Node-RED&amp;rsquo;s settings or by your code.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>The Node-RED runtime API&lt;/em>&lt;/p>
&lt;p>This is the bit of magic that makes everything work. At some point, this will be independent to the administration side but at the moment (~ v0.19) it isn&amp;rsquo;t.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>The Node-RED Administration user interface&lt;/em>&lt;/p>
&lt;p>This is a web application (web page plus websocket connections) that lets you build your own applications using Node-RED. It uses various 3rd-party libraries to do some of the heavy lifting (D3, JQuery, etc.)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>The Node-RED core and contributed nodes&lt;/em>&lt;/p>
&lt;p>Here is all of the clever custom code, generally tucked out of the way so you don&amp;rsquo;t need to worry about it.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>ExpressJS&lt;/em>&lt;/p>
&lt;p>ExpressJS is a library for NodeJS that does the heavy lifting of providing a web server.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>NodeJS&lt;/em>&lt;/p>
&lt;p>NodeJS is a collection of JavaScript and C code that lets people build application servers across different operating systems. It lets people use JavaScript (typically a browser language) to create their server applications.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>Operating System&lt;/em>&lt;/p>
&lt;p>Apart from the hardware, we are now at the bottom of the architecture.&lt;/p>
&lt;p>No point in securing everything else unless you have secured things at this level.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>In order to secure Node-RED, we have to pay some attention to all of these layers. Thankfully, the guys to created Node-RED have thought about many of the details and made it at least somewhat easier to provide a basic level of security.&lt;/p>
&lt;h1 id="settings-that-you-need-to-think-about">Settings that you need to think about&lt;/h1>
&lt;h2 id="other-considerations">Other considerations&lt;/h2>
&lt;h3 id="nodejs-and-package-vulnerabilities">NodeJS and package vulnerabilities&lt;/h3>
&lt;p>As Node-RED itself needs to have backwards compatibility with older versions of NodeJS, it may be forced to use packages (AKA modules or libraries) that are now out-of-date. Similarly, nodes that you rely on may not get updated as regularly as needed to stay ahead of vulnerabilities.&lt;/p>
&lt;p>NodeJS itself is very rapidly changing and unless you are updating it regularly (e.g. weekly) it may also have outstanding vulnerabilities.&lt;/p>
&lt;p>To mitigate these issues, you need to:&lt;/p>
&lt;ul>
&lt;li>Update NodeJS weekly or daily in sensitive installations. You will also want a set of regression tests - test that are run after every update - if you want users to be able to rely on rapid update cycles.&lt;/li>
&lt;li>&lt;code>npm&lt;/code> itself may have vulnerabilities and may need to be updated out of cycle from NodeJS.&lt;/li>
&lt;li>Regularly run &lt;code>npm outdated&lt;/code> and &lt;code>npm audit&lt;/code> on both the location you install Node-RED (global by default) and the location where you install contributed nodes. Update nodes regularly or consider the impact of nodes that have dependencies failing audits. Note that &lt;code>npm audit&lt;/code> is only available on newer versions of npm.&lt;/li>
&lt;/ul>
&lt;h1 id="issues-and-limitations">Issues and limitations&lt;/h1>
&lt;h2 id="specifics">Specifics&lt;/h2>
&lt;h1 id="references">References&lt;/h1>
&lt;ol>
&lt;li>&lt;a href="https://nodered.org/docs/security">Node-RED Official documentation on security&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://it.knightnet.org.uk/kb/nr-qa/node-red-internet/">Making Node-RED available over the Internet&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://it.knightnet.org.uk/kb/nr-qa/telegram-bot/">Secure Home Automation Controls via a Telegram Bot&lt;/a>&lt;/li>
&lt;li>Why should we use HTTPS?
&lt;ol>
&lt;li>&lt;a href="https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https">Google&amp;rsquo;s take&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.cloudflare.com/learning/security/why-use-https/">Cloudflare&amp;rsquo;s take&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://https.cio.gov/everything/">The US Government&amp;rsquo;s take&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.troyhunt.com/heres-why-your-static-website-needs-https/">A leading security experts take&lt;/a> (Troy Hunt)&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/categories/it-security">it-security</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/security">security</category></item><item><title>Drayton Wiser heating control</title><link>https://it.knightnet.org.uk/kb/nr-qa/drayton-wiser-heating-control/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/drayton-wiser-heating-control/</guid><pubDate>Mon, 13 Aug 2018 17:31:52 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/drayton-wiser-heating-control/</guid><description><div>Drayton are a very widely used manufacturer of heating controls. They make the "Wiser" control system which is low cost and easily fitted. This article shows you how to use Node-RED to query and control the system.</div><div>&lt;p>Drayton&amp;rsquo;s &lt;a href="https://wiser.draytoncontrols.co.uk/">Wiser smart heating controller&lt;/a> is a low-cost system for controlling boilers and radiators. Note that Drayton is part of Schneider-Electric&lt;/p>
&lt;p>It has the lowest cost &lt;a href="https://en.wikipedia.org/wiki/Thermostatic_radiator_valve">thermostatic radiator valves&lt;/a> (TRV&amp;rsquo;s, smart radiator controls)
of any of the smart home systems - around half the price of other systems. The control unit is also low-cost.&lt;/p>
&lt;p>It also has the advantage of not requiring the Internet or the Drayton cloud servers for the system to keep running so you are not dependent on
Drayton keeping the Wiser cloud service active. This was a really important point for me when choosing a smart heating controller since it is all
too easy to end up with a &amp;ldquo;brick&amp;rdquo; instead of a working system.&lt;/p>
&lt;p>However, the disadvantage of the Wiser system is that it isn&amp;rsquo;t as sophisticated as some others and clearly Drayton don&amp;rsquo;t have the resources
to rapidly develop it as some other manufacturers have (such as Honeywell for example).&lt;/p>
&lt;p>Of course, if you are reading this, you are probably already somewhat knowledgeable about &lt;a href="https://en.wikipedia.org/wiki/Home_automation">home automation&lt;/a>.
You may also be aware of &lt;a href="https://nodered.org/">Node-RED&lt;/a> which is a tool well suited for creating custom home automation systems with a minimum of knowledge and little to no
coding required.&lt;/p>
&lt;p>We can easily use Node-RED to help get information from the Wiser system and even use it to add smarter controls such as connecting to other sensors
or to other systems and services.&lt;/p>
&lt;p>At the end of this article is some code that you can import into your own Node-RED service and start working with the Wiser system straight away.&lt;/p>
&lt;h2 id="connecting-to-your-controller">Connecting to your controller&lt;/h2>
&lt;p>You will need to get a couple of pieces of information before you can start working with your Wiser system and Node-RED.&lt;/p>
&lt;p>Once you have this information, you can configure the example Node-RED flow at the end of this article and you should be able to
query information and override some settings at will. Once you have mastered the basics, you will be able to do pretty much
anything you want to using the power of Node-RED.&lt;/p>
&lt;h3 id="ip-address">IP Address&lt;/h3>
&lt;p>When your Wiser system connects to your home Wi-Fi, it will be given an IP address and we need to know that before we can talk to it.
There is no really easy way to do this. The address will generally be set by your Internet router (or Wi-Fi access point) so you should start
by checking your router&amp;rsquo;s web interface for &amp;ldquo;DHCP&amp;rdquo;. Hopefully you will see a list of assigned DHCP IP addresses, the Wiser controller is likely
to be the highest number if you have just connected it.&lt;/p>
&lt;p>You should configure your router to give the controller a fixed IP address otherwise it may change if the router is restarted.&lt;/p>
&lt;h3 id="system-secret">System Secret&lt;/h3>
&lt;p>In order to interface with the controller, you need to know a very long string of random characters that is its system secret.&lt;/p>
&lt;p>You can get the system secret by doing the following (&lt;a href="https://community.smartthings.com/t/drayton-wiser-home-thermostat/105055/12">reference&lt;/a>):-&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Press the setup button on your HeatHub, the light will start flashing&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Look for the Wi-Fi network (SSID) called &amp;lsquo;WiserHeatXXX&amp;rsquo; where XXX is random&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Connect to the network from a Windows PC&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Once connected run the following command in PowerShell&lt;/p>
&lt;p>&lt;code>Invoke-RestMethod -Method Get -UseBasicParsing -Uri http://192.168.8.1/secret/&lt;/code>&lt;/p>
&lt;p>If you are using a different type of operating system, you will need a tool that will return
data from a web query.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>This will return a string which is your system secret&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Press the setup button on the HeatHub again and it will go back to normal operations&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Copy the secret and save it somewhere.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="node-red-flow-to-configure-ip-address-and-system-secret">Node-RED flow to configure IP address and System Secret&lt;/h3>
&lt;p>To save having to repeatedly enter the IP address and system secret into your flows, use the following flow
to put them into memory. The query and control example flows will use this later on.
This flow will run automatically every time you start Node-RED.&lt;/p>
&lt;p>Don&amp;rsquo;t forget to change the change node (the 2nd node in this flow) to the information you obtained above.&lt;/p>
&lt;figure>&lt;img src="https://it.knightnet.org.uk/uploads/2018/NR-Wiser-Config.PNG"/>&lt;figcaption>
&lt;h4>Example Wiser Configuration Flow&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;738ed75a.9b0dc8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;inject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Save controller configuration for Wiser&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;topic&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payloadType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;repeat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;crontab&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;onceDelay&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mf">0.1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">230&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">460&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;d34f3b88.6b3008&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;d34f3b88.6b3008&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Set Wiser Variables (Secret and Host)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;wiserSecret&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;flow&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;Change_this_to_your_systems_secret_string&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;wiserHost&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;flow&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;your_controllers_ip_address&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">570&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">460&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[]]}]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Copy the code in the black box and use the &amp;ldquo;Import&amp;rdquo; menu in Node-RED.&lt;/p>
&lt;h2 id="controlling-the-system">Controlling the system&lt;/h2>
&lt;p>The following sections contain basic information about how to control the Wiser system.&lt;/p>
&lt;p>Don&amp;rsquo;t forget that the system may be controlled by other applications (like the mobile app) or services such as Google Home or Amazon Alexa integrations.&lt;/p>
&lt;p>Note that you &lt;em>do not need the Internet&lt;/em>
for this at all. You only need your local network. All of this will work even if your Internet connection is down or the Wiser cloud
service stops working.&lt;/p>
&lt;p>Each entry below has a &amp;ldquo;path&amp;rdquo; such as &amp;lsquo;/data/domain/System/RequestOverride&amp;rsquo; and some text or JSON in a grey box. In the example flows, the
information in the grey box goes into the &lt;code>payload&lt;/code> property (&lt;code>msg.payload&lt;/code>) and the the path goes into the &lt;code>path&lt;/code> property (&lt;code>msg.path&lt;/code>).
These property values are then used by the flow and sent to the controller. These property values are set in the node that follows the inject node,
they are the second node in each flow, they are called &amp;ldquo;change&amp;rdquo; nodes.&lt;/p>
&lt;h3 id="room-ids">Room ID&amp;rsquo;s&lt;/h3>
&lt;p>The Wiser system mainly works by controlling &amp;ldquo;rooms&amp;rdquo;. In the mobile app, these are all named and you can find the names in the data you can query as well.
However, in order to control the system from Node-RED or any other home automation system, we need to know the ID of the room.&lt;/p>
&lt;p>Wherever you see &lt;code>&amp;lt;roomNumber&amp;gt;&lt;/code> in the information below, this is the ID not the offset in the &lt;code>/data/domain/Room&lt;/code> array.&lt;/p>
&lt;h3 id="temperature-values">Temperature values&lt;/h3>
&lt;p>The values use to control and query temperatures are multiplied by 10.
So 200 equals 20.0°C, 195 equals 19.5°C.
Note that the value will be rounded to the nearest ½ a degree by the controller.&lt;/p>
&lt;h3 id="set-or-cancel-an-override-of-the-thermostatic-temperature-for-a-room">Set or cancel an override of the thermostatic temperature for a Room&lt;/h3>
&lt;p>&lt;em>Path&lt;/em>: /data/domain/Room/&lt;code>&amp;lt;roomNumber&amp;gt;&lt;/code>&lt;/p>
&lt;p>&lt;em>Payload&lt;/em>: &lt;code>{&amp;quot;RequestOverride&amp;quot;:{&amp;quot;Type&amp;quot;:&amp;quot;Manual&amp;quot;,&amp;quot;SetPoint&amp;quot;:195}}&lt;/code>&lt;/p>
&lt;p>This will be permanent until something else changes the setting.&lt;/p>
&lt;h3 id="setcancel-boost-for-a-room">Set/cancel Boost for a Room&lt;/h3>
&lt;p>/data/domain/Room/&lt;code>&amp;lt;roomNumber&amp;gt;&lt;/code>&lt;/p>
&lt;p>&lt;code>{&amp;quot;RequestOverride&amp;quot;:{&amp;quot;Type&amp;quot;:&amp;quot;Manual&amp;quot;,&amp;quot;DurationMinutes&amp;quot;: 30, &amp;quot;SetPoint&amp;quot;:200, &amp;quot;Originator&amp;quot;:&amp;quot;App&amp;quot;}}&lt;/code>&lt;/p>
&lt;p>&lt;code>{&amp;quot;RequestOverride&amp;quot;:{&amp;quot;Type&amp;quot;:&amp;quot;None&amp;quot;,&amp;quot;DurationMinutes&amp;quot;: 0, &amp;quot;SetPoint&amp;quot;:0, &amp;quot;Originator&amp;quot;:&amp;quot;App&amp;quot;}}&lt;/code>&lt;/p>
&lt;p>Note: Duration is in minutes. The returned info includes a &lt;code>OverrideTimeoutUnixTime&lt;/code> property, to convert this to a real time, you can use the &lt;a href="https://www.unixtimestamp.com/index.php">Unix timestamp converter&lt;/a> website.&lt;/p>
&lt;h3 id="setcancel-manual-mode-for-a-room">Set/Cancel Manual mode for a room&lt;/h3>
&lt;p>/data/domain/Room/&lt;code>&amp;lt;roomNumber&amp;gt;&lt;/code>&lt;/p>
&lt;p>&lt;code>{&amp;quot;Mode&amp;quot;:&amp;quot;Manual&amp;quot;}&lt;/code> or &lt;code>{&amp;quot;Mode&amp;quot;:&amp;quot;Auto&amp;quot;}&lt;/code>&lt;/p>
&lt;h3 id="setcancel-window-state-detection-for-a-room">Set/Cancel window state detection for a room&lt;/h3>
&lt;p>/data/domain/Room/&lt;code>&amp;lt;roomNumber&amp;gt;&lt;/code>/WindowDetectionActive&lt;/p>
&lt;p>&lt;code>true&lt;/code> or &lt;code>false&lt;/code>&lt;/p>
&lt;h3 id="setcancel-away-mode">Set/cancel Away Mode&lt;/h3>
&lt;p>/data/domain/System/RequestOverride&lt;/p>
&lt;p>&lt;code>{&amp;quot;type&amp;quot;:2,&amp;quot;setPoint&amp;quot;:100}&lt;/code>&lt;/p>
&lt;p>&lt;code>{&amp;quot;type&amp;quot;:0,&amp;quot;setPoint&amp;quot;:0}&lt;/code>&lt;/p>
&lt;p>Note: Sets the min temperature to 10°C&lt;/p>
&lt;p>Also note that you should cancel manual overrides for all rooms.&lt;/p>
&lt;h2 id="references">References&lt;/h2>
&lt;p>Much of the above was gleaned from the following reference code.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/andrew-schofield/openhab2-addons/blob/draytonwiser/addons/binding/org.openhab.binding.draytonwiser/src/main/java/org/openhab/binding/draytonwiser/handler/HeatHubHandler.java">andrew-schofield/openhab2-addons&lt;/a> - also has references for hot water, scheduling and smart plugs&lt;/li>
&lt;li>&lt;a href="https://github.com/chrisduffer/drayton-wiser/blob/master/smartapps/chrisduffer/drayton-wiser-connect.src/drayton-wiser-connect.groovy">chrisduffer/drayton-wiser&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="example-control-and-query-code">Example control and query code&lt;/h2>
&lt;p>Copy the code and import it into Node-RED. You will need the &lt;a href="#node-red-flow-to-configure-ip-address-and-system-secret">configuration flow&lt;/a> as well.&lt;/p>
&lt;p>The configuration flow sets the flow variables &lt;code>flow.wiserHost&lt;/code> and &lt;code>flow.wiserSecret&lt;/code>.&lt;/p>
&lt;h3 id="query-the-current-settings">Query the current settings&lt;/h3>
&lt;h4 id="query-everything-or-query-a-single-room">Query everything or query a single room&lt;/h4>
&lt;p>The top inject will return everything that the controller can tell us. It is useful in helping understand what data is available and
how it is structured. The bottom inject queries a single room, change the room ID in the first change node.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;3822a01a.859ea&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;inject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;topic&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Wiser QUERY&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payloadType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;repeat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;crontab&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;onceDelay&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mf">0.1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">160&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">620&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;2dfd4a60.601b06&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fcb37ac1.cb36f8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;http request&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;use&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;ret&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;obj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tls&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">770&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">620&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;c21166d6.4784c8&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;c21166d6.4784c8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;debug&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;active&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tosidebar&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;console&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tostatus&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;complete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">950&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">620&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;a9652fa4.60f24&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;GET&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;\&amp;#34;http://\&amp;#34; &amp;amp; $flowContext(&amp;#39;wiserHost&amp;#39;) &amp;amp; $.path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;headers&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;{\t \&amp;#34;SECRET\&amp;#34;: $flowContext(&amp;#39;wiserSecret&amp;#39;),\t \&amp;#34;HOST\&amp;#34;: $flowContext(&amp;#39;wiserHost&amp;#39;) &amp;amp; \&amp;#34;:80\&amp;#34;\t}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">620&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;fcb37ac1.cb36f8&amp;#34;&lt;/span>&lt;span class="p">]]},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;2dfd4a60.601b06&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;/data/domain/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">330&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">620&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;a9652fa4.60f24&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;9b02c89.7609c38&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;inject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;topic&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Wiser QUERY Room&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payloadType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;repeat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;crontab&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;onceDelay&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mf">0.1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">180&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">680&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;38d8c719.5ae978&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;38d8c719.5ae978&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;/data/domain/Room/6&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">370&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">680&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;a9652fa4.60f24&amp;#34;&lt;/span>&lt;span class="p">]]}]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="get-a-simplified-view-of-all-of-the-rooms">Get a simplified view of all of the rooms&lt;/h4>
&lt;p>This flow queries the &amp;lsquo;/data/domain/Room/&amp;rsquo; path and then simplifies the output using JSONata&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;c8566325.8a07b&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;inject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;topic&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Start Query&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;payloadType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;repeat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;crontab&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;onceDelay&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mf">0.1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">130&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">800&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;82a69e2d.bd5a1&amp;#34;&lt;/span>&lt;span class="p">]]},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;a3f3790.4883288&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;http request&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;use&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;ret&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;obj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tls&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">630&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">800&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;2887038d.8bd21c&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;55b4a3e7.8eb21c&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;debug&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;active&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tosidebar&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;console&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tostatus&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;complete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">950&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">800&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;a8da7133.b0ced&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;GET&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;\&amp;#34;http://\&amp;#34; &amp;amp; $flowContext(&amp;#39;wiserHost&amp;#39;) &amp;amp; $.path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;headers&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;{\t \&amp;#34;SECRET\&amp;#34;: $flowContext(&amp;#39;wiserSecret&amp;#39;),\t \&amp;#34;HOST\&amp;#34;: $flowContext(&amp;#39;wiserHost&amp;#39;) &amp;amp; \&amp;#34;:80\&amp;#34;\t}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">460&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">800&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;a3f3790.4883288&amp;#34;&lt;/span>&lt;span class="p">]]},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;82a69e2d.bd5a1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;/data/domain/Room&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">289&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">800&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;a8da7133.b0ced&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;5d6dc6ef.f8cae8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;comment&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Get basic room info for all rooms&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;info&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">190&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">760&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;2887038d.8bd21c&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;trim output&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;payload{ \t $.Name : {\t \&amp;#34;id\&amp;#34;: $.id,\t \&amp;#34;Name\&amp;#34;: $.Name,\t \&amp;#34;CurrentTemperature\&amp;#34;: $.CalculatedTemperature/10,\t \&amp;#34;DesiredTemperature\&amp;#34;: $.CurrentSetPoint/10,\t \&amp;#34;Override\&amp;#34;: $.OverrideType?\&amp;#34;Yes\&amp;#34;:\&amp;#34;No\&amp;#34;,\t \&amp;#34;OverrideTimeout\&amp;#34;: $.OverrideType?$split($split($fromMillis($.OverrideTimeoutUnixTime),\&amp;#34;T\&amp;#34;)[1],\&amp;#34;.\&amp;#34;)[0]:\&amp;#34;N/A\&amp;#34;\t }\t}\t&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">790&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">800&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;55b4a3e7.8eb21c&amp;#34;&lt;/span>&lt;span class="p">]]}]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The output looks like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Bedroom 2&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Bedroom 2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;CurrentTemperature&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">19.2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;DesiredTemperature&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">12.5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Override&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;No&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;OverrideTimeout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;N/A&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Master Bedroom&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Master Bedroom&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;CurrentTemperature&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">19.2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;DesiredTemperature&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">12.5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Override&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Yes&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;OverrideTimeout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;18:09:42&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="control-the-system">Control the system&lt;/h3>
&lt;p>These flows show you how to make changes to the controller from Node-RED.&lt;/p>
&lt;h4 id="boost-the-temperature-in-a-room-for-30-minutes">Boost the temperature in a room for 30 minutes&lt;/h4>
&lt;p>Applies a 30 minute boost to 18.5°C for room id 1.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;9d700a39.ebbaa8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;http request&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;use&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;ret&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;obj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tls&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">770&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;58845d6d.bf2a24&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;32c33bee.cf6c24&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;inject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Wiser SET&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;topic&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;payloadType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;repeat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;crontab&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;onceDelay&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mf">0.1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">140&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;855deb47.8df6f8&amp;#34;&lt;/span>&lt;span class="p">]]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;58845d6d.bf2a24&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;debug&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;active&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tosidebar&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;console&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tostatus&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;complete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">930&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[]},{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;6ec2a88e.839598&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;PATCH&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;\&amp;#34;http://\&amp;#34; &amp;amp; $flowContext(&amp;#39;wiserHost&amp;#39;) &amp;amp; $.path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;headers&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;{\t \&amp;#34;SECRET\&amp;#34;: $flowContext(&amp;#39;wiserSecret&amp;#39;),\t \&amp;#34;HOST\&amp;#34;: $flowContext(&amp;#39;wiserHost&amp;#39;) &amp;amp; \&amp;#34;:80\&amp;#34;\t}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jsonata&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;9d700a39.ebbaa8&amp;#34;&lt;/span>&lt;span class="p">]]},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;855deb47.8df6f8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;change&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;z&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;fb0c842.c87fc78&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:[{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;payload&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;{\&amp;#34;RequestOverride\&amp;#34;:{\&amp;#34;Type\&amp;#34;:\&amp;#34;Manual\&amp;#34;,\&amp;#34;Originator\&amp;#34;:\&amp;#34;App\&amp;#34;,\&amp;#34;DurationMinutes\&amp;#34;:30,\&amp;#34;SetPoint\&amp;#34;:185}}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;json&amp;#34;&lt;/span>&lt;span class="p">},{&lt;/span>&lt;span class="nt">&amp;#34;t&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;set&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;p&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;pt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;/data/domain/Room/1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;tot&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">}],&lt;/span>&lt;span class="nt">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;property&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;#34;from&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;to&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;reg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">340&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">560&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;wires&amp;#34;&lt;/span>&lt;span class="p">:[[&lt;/span>&lt;span class="s2">&amp;#34;6ec2a88e.839598&amp;#34;&lt;/span>&lt;span class="p">]]}]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The output from this contains updated room info.&lt;/p>
&lt;p>You can easily amend the payload and path to any of the settings listed in the &lt;a href="#controlling-the-system">controlling the system&lt;/a> section above.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/categories/internet-of-things-iot">Internet of Things (IoT)</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/internet-of-things">Internet of Things</category><category domain="https://it.knightnet.org.uk/tags/iot">IoT</category><category domain="https://it.knightnet.org.uk/tags/heating">Heating</category><category domain="https://it.knightnet.org.uk/tags/home-automation">Home Automation</category></item><item><title>Easily search for contributed nodes on the Node-RED Flows site</title><link>https://it.knightnet.org.uk/kb/nr-qa/seach-for-nodes/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/seach-for-nodes/</guid><pubDate>Mon, 19 Mar 2018 22:00:00 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/seach-for-nodes/</guid><description><div>Excellent work has been done to make sure that new nodes are discoverable. Here is a quick way to easily search from your browser.</div><div>&lt;p>The &lt;a href="https://flows.nodered.org/?num_pages=1">Flows&lt;/a> website is the best place to go in order to
find contributed nodes for Node-RED. It also contains example flows showing how to do various tasks.&lt;/p>
&lt;p>You can search on that site by node name, author name and tags and the results are paged.&lt;/p>
&lt;p>You can also use the URL to search and this means that you can add Flows as a custom
search engine in your browser. Or even from Node-RED itself!&lt;/p>
&lt;h2 id="chrome">Chrome&lt;/h2>
&lt;p>Select &amp;ldquo;Settings&amp;rdquo; from the menu. Scroll down to the &amp;ldquo;Search engine&amp;rdquo; section and click on &amp;ldquo;Manage serach engines&amp;rdquo;.&lt;/p>
&lt;p>Click on the Add button and fill in as follows:&lt;/p>
&lt;p>&lt;img src="https://it.knightnet.org.uk/uploads/images/nr-search.PNG" alt="Chrome Search Engine Edit">&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category></item><item><title>How node.send() works</title><link>https://it.knightnet.org.uk/kb/nr-qa/how-node-send-works/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/how-node-send-works/</guid><pubDate>Sun, 04 Mar 2018 22:56:00 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/how-node-send-works/</guid><description><div>Some detail not included in the documentation.</div><div>&lt;p>It is synchronous. See &lt;a href="https://groups.google.com/forum/#!topic/node-red/OCHTT8aA3lk">this discussion&lt;/a> for details.&lt;/p>
&lt;p>If you have code in a function node &lt;em>after&lt;/em> a &lt;code>node.send()&lt;/code>, it will not run until &lt;em>all&lt;/em> downstream connected nodes have &lt;strong>finished&lt;/strong> processing their
sending routines. This is true of nodes further downstream as well.&lt;/p>
&lt;p>Also see &lt;a href="https://github.com/node-red/node-red/issues/833">Issue 833 on GitHub&lt;/a>&lt;/p>
&lt;p>Another impact of this is that, because [msg&amp;rsquo;s may be passed by reference]({{ site.baseurl }}{% link nr-qa/msg-cloning.md %}) to downstream nodes, a subsequent node may alter the msg. This means that any processing after a &lt;code>node.send(msg)&lt;/code> may be getting a msg object that has been altered.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category></item></channel></rss>