Difference between revisions of "Open Control Architecture"

From Open Source Controls Wiki
Jump to navigation Jump to search
 
(115 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Block | Controls software is written in [[Node-RED]]. }}{{Block | A Node-RED system (controller or server) is called a node. }}
== Basic Architecture ==
{{Block | The node identifier is stored under '''''global.node''''' }}[[File:Topology6a.png|center|750x750px]]
{{Block |Features:
 
* Real-time global commutation (<0.5s latency) of any payload type between millions of devices
* Open source and licence free for life
* Battle hardened, standard and secure technologies
* Simple to use for plumbers and electricians
* Can connect to anything, physical or web based, and make use of commercial services and APIs
* Implement a standard dictionary structure to enable interoperability between systems}}{{Block |Controls software is written in [[Node-RED]] version 2+. }}{{Block | Communications between systems is performed using [[MQTT]].}}
We have chosen to base the Open Controls Architecture on Node-RED for a number of reasons:
 
* Open source and free to use at will
*Cross platform, from PCs, to cloud servers to embedded devices, the Raspberry Pi, and many industrial PLCs
* Very stable, having been actively developed for over 10 years with the likes of IBM
* Simple to use with a visual interface that compares to electrical wiring
* Software can be copied and pasted from one system to another, dropped in and wired up
* Infinitely versatile with standard and custom components available from an online library to achieve almost any function or connect to any system
* Complex software can be built in a hurry, dragging components in and wiring up, then refined and packaged into neat and updateable components
* Built on Node.js and JavaScript, possible the world's most active software environment as used on all web pages
* Used by almost everyone - from hobbyists through to mobile phone companies - with considerable community support 
* Provides a means to easily implement new and existing technologies and online services, including machine learning, peer-to-peer communications, databases, and encryption
 
<br>
 
[[File:Nr1.png]]
 
Node-RED version 2 (or higher) is required for the latest active MQTT management. 
 
 


<br>
<br>
{{Block |In addition to the standard Node-RED set of Nodes we make use of the following. These can be easily installed into any instance of Node-RED from the Palette Manager:
* '''''node-red-contrib-heatweb''''' provides a set of nodes to implement the protocols used on this site
* '''''node-red-dashboard''''' provides a live user interface
* '''''node-red-node-email''''' provides email functions
}}
Other Nodes are used, and can be installed as required.{{Block |Software works through payloads of data (messages) passing along virtual (and real) wires, from one node to another. Messages have both a payload and a topic.
A node can be:
* a function block within Node-RED  (a Node-RED Node)
* an instance of Node-RED (a Controller Node)
* any point in the communications network (e.g. an MQTT Broker)}}[[File:Topology6a.png|center|750x750px]]
{{Block | Each instance of Node-RED has an identifier, stored under '''''global.node''''' }}
{{Block |'''camelCase''' is used for variable names and topics, where the first letter of additional words are capitalised, and spaces removed.
* Only letters and numbers should ever be used in naming.
* Dashes (-) may be used to create hierarchy as described below
* Underscores ( _ ) can be used at a software level, to add functionality, but not at an operational or user level.
* Spaces, full stops, commas, apostrophes, or any special characters must '''NEVER''' be used in naming.}}


{{Block | Communications between systems is performed using [[MQTT]] using a standardised 5 level topic structure.  '''''network''' / '''node''' / '''device''' / '''group''' / '''key'''.'' }}
== Communications ==
{{Block |A standardised 5 level MQTT topic structure is used throughout.  '''''network''' / '''node''' / '''device''' / '''vargroup''' / '''varkey'''.''
<br>See https://github.com/heatweb/heat-network}}
[[File:Bmscoms1.png|center|frameless|1176x1176px]]
[[File:Bmscoms1.png|center|frameless|1176x1176px]]


Line 10: Line 61:
<br>
<br>


{{Block |Systems run a local MQTT broker to distribute data both internally and to enable external subscriptions. }}{{Block | The external network identifier, used for all data published to external MQTT brokers, is stored under '''''global.networkId''''' }}
{{Block |Systems run a local Mosquitto MQTT broker to distribute data both internally and to enable external subscriptions. }}{{Block |Additional local MQTT brokers can be established through Docker Containers. }}{{Block | The external network identifier, used for all data published to external MQTT brokers, is stored under '''''global.networkId'''''  
{{Block | Data from within a node or from connected devices is assigned a local network identifier of "'''''local'''''" (stored under '''''global.localNetworkId''''') so that the node's external network identifier can be changed without affecting internal software.  Separate internal and external identifiers also allows for separate message rates, where local traffic can be high speed. Node-RED is used to apply '''''Reporting By Exception''''' rules, to limit traffic to significant values (e.g. 0.25C), and save bandwidth. }}
<br>This must be unique (long) and without spaces.}}
[[File:Mqtt6a1.png|center|frameless|685x685px]]
[[File:Handler0.png|center]]
{{Block | Data from within a node or from connected devices is assigned a local network identifier of "'''''local'''''" (stored under '''''global.localNetworkId''''') so that the node's external network identifier can be changed without affecting internal software.  Separate internal and external identifiers also allows for separate message rates, where local traffic can be high speed. Node-RED is used to apply '''''Reporting By Exception''''' rules, to limit traffic to significant values (e.g. 0.25C), and save bandwidth.   }}
[[File:Handler0.png|right]]
 
 
[[File:Mqtt6a1.png|640px]]
 
{{Block |In the real world, devices and networks are nested - a building may have a network ID, but this may be fed from a plantroom, also with its own identity.  To accommodate nested networks, a dash is used to prefix topics (and hence the network ID) and thereby maintain a five level topic structure - important for wildcard subscriptions to work..}}
myNetwork/plantroomNode/plantroomNode/settings/title = "Main Plantroom Controller"
 
block1/blk1node/blk1node/settings/title = "Block 1 Controller"  '''!!! DO NOT USE COMMON NETWORK IDs'''
Adding a prefix to sub-networks ensures networks remain unique on a higher level server. E.g. There may be two unconnected networks with sub-networks called "''block1"''.
myNetwork-block1/blk1node/blk1node/settings/title = "Block 1 Controller"
 
anotherNetwork-block1/blk1node/blk1node/settings/title = "Block 1 Controller"
 
{{Block |Where managing multiple networks, it is advised to use long and non-descriptive unique identities. When creating new configurations a random 8-16 character ID should be generated.
e.g.  '''''Ea5lQXfF2tmBlzYk'''''
 
<br>
 
Nodes should also be given unique identities. Nodes Id's can be shorter as they only need to be unique within a network, rather than globally (in the whole world).
e.g.  '''''jxt15Ewk'''''}}
 
The titles of networks, as well as nodes, can be saved and found under its device setting.
Ea5lQXfF2tmBlzYk/jxt15Ewk/'''network/settings/title''' = "My Heat Network"
 
Ea5lQXfF2tmBlzYk/jxt15Ewk/jxt15Ewk'''/settings/title''' = "Main Plantroom Controller"
And to simplify for sub-nodes it is possible to use a node's id as the node's network identifier. 
a5lQXfF2tmBlzYk-fg4jS8s7/fg4jS8s7/'''network/settings/title''' = "Block 1 Heat Network"
 
a5lQXfF2tmBlzYk-fg4jS8s7/fg4jS8s7/fg4jS8s7'''/settings/title''' = "Block 1 Controller"
 
a5lQXfF2tmBlzYk-fg4jS8s7-nnf555dE/nnf555dE/nnf555dE'''/settings/title''' = "Block 1, Flat 17 Controller"
 
 
== Data Groups ==
{{Block | The topic group (''vargroup'') (4th level) is used to define the type of data. Values include:
*'''''dat''''' (operational data)
*'''''stat''''' (statistics and status)
*'''''settings''''' (persistent settings)
*'''''cmd''''' (a command)
*'''''set''''' (command to change a setting)
*'''''system''''' (software and networking)
*'''''meter''''' (meter data)
*'''''alarm''''' (alarms and warnings)
*'''''ana''''' (analogue readings)
*'''''json''''' (JSON formatted data)
*'''''modbus''''' (Modbus serial data)
*'''''design''''' (preloaded design data) }}{{Block |Topic groups that are manufacturer or organisation specific,  should use an all CAPITAL group identifier. This should represent the organisation, be unique, and may include dashes to create multiple groups under a single organisation.
 
*'''''TIL''''' (Thermal Integration Ltd.)
*'''''PCDB''''' (SAP Product Characteristics Database)
*'''''BENCHMARK''''' (Benchmark information) }}
 
Manufacturer specific data groups can be used by systems to load a manufacturer's default data attributes, enabling the protocol to be extended as required.
 
They allow, for example, multiple organisations to publish the same data on a device (such as a heat network) without collisions.
 
== Handling Data ==
{{Block |Within Node-RED a [[Message Handler Node]] is used to handle data generated locally.   
{{Block |Within Node-RED a [[Message Handler Node]] is used to handle data generated locally.   
[[File:Handleroptions.png|right|frameless|461x461px]]
[[File:Handleroptions.png|right|frameless|461x461px]]
Line 20: Line 129:
* The Node formats topics to the five level standard, adding group and device if missing.
* The Node formats topics to the five level standard, adding group and device if missing.
*The Node stores data into '''''global.readings''''', along with any attributes within the incoming message, as well as timestamps.
*The Node stores data into '''''global.readings''''', along with any attributes within the incoming message, as well as timestamps.
* Additional routing can be performed within Node-RED, including selection of retained vs fire & forget routes.}}
*The Node stores historical data into '''''global.readingsHistory''''', along with timestamps, removing repeat values.
[[File:Handler1.png|center]]
* New attributes are read from incoming messages, and existing attributes added to outgoing traffic.
* Handles the '''''set''''' data group, altering settings and saving to disk.
* Handles the '''''json/sync''''' topic, updating stored device readings and attributes to incoming sync data.
* Handles the '''''cmd/sync''''' topic, sending stored device readings and attributes as JSON.
* Handles the '''''cmd/request''''' topic, sending stored data as per requests.
* Additional routing can be performed within Node-RED, including selection of retained vs unretained routes.
 
<br>
 
[[File:Handler1.png]]}}Handler Nodes use a configuration node to store setup information including network and node identities.
 
[[File:Handleroptions2.png|frameless|684x684px]]


== Routing Data ==
{{Block |Where a number of nodes sit on a Local Area Network (LAN) it is common to use a central local MQTT broker.  }}
{{Block |Where a number of nodes sit on a Local Area Network (LAN) it is common to use a central local MQTT broker.  }}
[[File:Mqtt6a.png|center|frameless|890x890px]]
[[File:Handler3.png|right]][[File:Mqtt6a.png|frameless|768x768px]]
[[File:Handler3.png|center]]
{{Block |Traffic can be routed to a Cloud MQTT broker by the use of MQTT Bridges. These run on an MQTT broker, and can re-publish messages filtered by topic (''networkId'') to another broker.  Bridges are managed outside of Node-RED.}}
{{Block |Traffic can be routed to a Cloud MQTT broker by the use of MQTT Bridges. These run on an MQTT broker, and can re-publish messages filtered by topic (''networkId'') to another broker.  Bridges are managed outside of Node-RED.}}
[[File:Handler7.png|center]]
[[File:Handler7.png|center]]
Line 31: Line 151:
[[File:Handler5.png|center]]
[[File:Handler5.png|center]]
{{Block |On larger networks where data is shared between local nodes, '''''Reporting By Exception''''' can be centrally managed using a Node-RED instance, along with any additional MQTT broker functions such as providing backup routes.}}
{{Block |On larger networks where data is shared between local nodes, '''''Reporting By Exception''''' can be centrally managed using a Node-RED instance, along with any additional MQTT broker functions such as providing backup routes.}}
[[File:Mqtt6a2.png|center|frameless|873x873px]]
[[File:Mqtt6a2.png|center|frameless|796x796px]]
[[File:Handler6.png|center]]
[[File:Handler6.png|center]]
[[File:Handler4.png|center]]
[[File:Handler4.png|center]]
{{Block |Cloud based instances of Node-RED are often used to pull together data from various MQTT brokers into one place.}}
{{Block |Cloud based instances of Node-RED, as used on this Wiki, are often used to pull together data from various MQTT brokers into one place.}}
[[File:Handlercloud.png|center]]
[[File:Handlercloud.png|center]]
{{Block | The topic group is used to define the type of data. Values include:
*'''''dat''''' (operational data)
*'''''stat''''' (statistics and status)
*'''''settings'''''
*'''''cmd''''' (a command)
*'''''set''''' (change a setting)
*'''''system''''' (software and networking) }}
{{Block | Attributes for data may be loaded from a central index (GitHub hosted), providing additional information such as units and descriptions.  This is to avoid the need to locally describe data, and to assist in compatibility. }}{{Block | Within Node-RED, data and attributes are stored within the '''''global.readings''''' object.


The current data can be viewed in the data explorer.
== Complex Architecture ==
{{Block |MQTT allows granular sharing of data and the scaling of complex network topologies.}}
[[File:Mqttsys2.png|center|frameless|1101x1101px]]
 
 
== Security and Access Control ==
{{Block |Each MQTT Broker runs its own security settings, with a list of users and associated topic permissions (read & write). Additional bridges enables data between MQTT brokers to be managed, and allows common user/password lists to be utilised.  Password lists are based on hashed passwords (one way encryption) so that original passwords are never known or shared.}}
{{Block |Devices within a local network (LAN) can be protected using standard firewall rules with port forwarding used to expose MQTT services as required.  Pulling all data and communications through MQTT allows all other external routes to be more easily locked down, with only secure MQTT ports to the LAN Broker exposed online.  In this way external access is completely ruled by the same MQTT users and password structure.}}
{{Block |User access rules are stored in an '''ACL File''', with the following powers:
 
* Access rules can be applied to read and write permissions separately.
* Wildcards can be applied to rules, on any of the topic levels.  This allows, for example, a particular user to be given access to '''''myNetwork/+/+/meter/#''''' providing access to meter data from ''myNetwork'', all nodes and devices. 
* General rules can be setup for all users, providing global data.
* Rules can include special fields, such as the MQTT client id or username. This allows general rules to be setup that, for example, '''''+/+/%u/cmd/#''''' provide nodes with read access to commands directed at them. }}{{Block |As MQTT can transport any form of data at high speed, including raw buffers, many insecure serial communications protocols, including Modbus and M-Bus can be piped via MQTT topics, rather than expose them directly. This pulls access to the data into the common rules.  }}
 
Separate read topic and write topic are used, for example:
'''''myNetwork/+/n5hsi72k/modbus/request'''''
'''''myNetwork/n5hsi72k/n5hsi72k/modbus/response'''''
Likewise, the transparent M-Bus port on an Elvaco CMe3000 could be piped over:
'''''myNetwork/+/cme3000/mbus/request'''''
'''''myNetwork/n5hsi72k/cme3000/mbus/response'''''
 
It would however be more normal to convert bus data such as this into individual topics for each register or field and expose these through MQTT to provide more  granular control over access, remove the need for remote handling, and add report by exception rules (rather than keep continuously fetching values to catch a change).
== Data Attributes ==
{{Block |Attributes (metadata) provide additional information about data, such as units and a description. They include:
 
* '''''units''''' (units for data)
* '''''title''''' (short description)
* '''''points''''' (maximum data points to store in history)
* '''''deadband''''' (the deadband used for external communications)
* '''''timestamp''''' (unix time data is generated or handled)
* '''''changed''''' (unix time data last changed)
* '''''attributes''''' (an object containing custom attributes)}}{{Block |Attributes are generally loaded from a central index (GitHub or LAN hosted), providing additional information such as units and descriptions.  This is to avoid the need to locally describe data, and to assist in compatibility. Custom  attributes may be added inline to messages and will override defaults.
 
See https://raw.githubusercontent.com/heatweb/heat-network/master/devices/default_topics.json}}{{Block |Loaded attributes are saved in a global Node-RED object,and will be added to messages as they are handled, and stored into readings alongside the value (payload). They are however not transmitted through MQTT - only topics and payloads are transmitted by default.
 
As such it is important to try and use standard topics where possible, selecting a topic by its standard attributes.}}The flow below shows a message object, with attributes, before and after going through an MQTT connector.
Note that only the topic and payload survive transit.
 
Note that '''''dat/tOut''''' is a standard topic, so the attributes (units and title) would be added back in by a Handler Node. 
 
[[File:Trafficvar.png]]{{Block |Attributes can be transmitted through MQTT in one of two ways:
 
* A special command '''''cmd/sync''''' can be sent to a nodes message handler asking it to publish a full JSON object for a device (or devices), including all data groups, values, and attributes.  The command payload is an MQTT topic including wildcards, e.g. '''''local/#''''' (all), or '''''+/+/boiler1/#'''''.  The reply for each device that matches is sent on the corresponding topic, e.g. '''''myNetwork/node123/boiler1/json/sync''''' and can be handled by a receiving system.
* Packaging a message as a JSON object, value and attributes, and send this instead of just the value. A receiving system can work out the payload is JSON and handle appropriately.}}{{Block |Attributes take up a lot more bandwidth in traffic, and as they are generally static or default values, only custom attributes need to be transmitted, and only at startup or on request.  }}
== Node-RED Global Objects ==
{{Block | Within Node-RED, data and attributes are stored within the '''''global.readings''''' object.
 
Data stored in global objects is held in processor memory and not on disk.
 
The current data can be viewed within Node-RED in the data explorer.


[[File:Readings1.png]]
}}
}}
{{Block |Historic data is saved into the '''''global.readingsHistory''''' object, in the same structure as '''''global.readings''''', but containing an array of timestamped values.}}
{{Block | Persistent settings for a node (or application) are held on disk and in the '''''global.settings''''' object. This is for local operational settings.


Settings have a type, may have maximum and minimum values, units and a title.  Certain types require additional fields such as select from a list settings.
[[File:Readings1.png]]


The snapshot below shows a variety of setting types including numeric/text values, html, or JSON objects and arrays.
{{Block | Data within the readings object is nested according to the topic (excluding the node as more than one node may publish data on a device).<br>
 
'''''network -> device -> group -> key'''''}}
[[File:Settings3.png]]}}
{{Block | Persistent settings for local devices are held on disk and in the '''''global.deviceSettings''''' object, and are specific to a device (or node).}}
{{Block | Data within the readings object is nested according to the topic (excluding the node as more than one node may publish data on a device).
  e.g. a message with a topic '''''myNetwork'''/'''node123'''/'''myDevice'''/'''dat'''/'''outputTemperature'''''  would be stored in (global).'''''readings'''.'''myNetwork'''.'''myDevice'''.'''dat'''.'''outputTemperature'''.'''value'''''
  e.g. a message with a topic '''''myNetwork'''/'''node123'''/'''myDevice'''/'''dat'''/'''outputTemperature'''''  would be stored in (global).'''''readings'''.'''myNetwork'''.'''myDevice'''.'''dat'''.'''outputTemperature'''.'''value'''''
Internally, message topics can be truncated and the network and node will be filled in. The data group will be assumed to be "'''''dat"''''' if not supplied, representing operational data.   
Internally, message topics can be truncated and the network and node will be filled in. The data group will be assumed to be "'''''dat"''''' if not supplied, representing operational data.   
Line 65: Line 221:


The following code could be used to read data and its attributes for output.
The following code could be used to read data and its attributes for output.
<pre>
<pre>
  var localNetworkId = global.get("localNetworkId");
  var localNetworkId = global.get("localNetworkId");
Line 75: Line 230:
  // "The value of Output Temperature is 35°C
  // "The value of Output Temperature is 35°C


</pre> }}
</pre>
 
{{Block |Historic data is saved into the '''''global.readingsHistory''''' object, in the same structure as '''''global.readings''''', but containing an array of timestamped values.}}
 
{{Block | Persistent settings for a node (or application) are held on disk and in the '''''global.settings''''' object. This is for local operational settings.
 
Settings have a type, may have maximum and minimum values, units and a title.  Certain types require additional fields such as select from a list settings.
 
Standard settings include:
 
* '''''title''''' (system title / name)
* '''''io''''' (system input/output configuration in JSON format)
* '''''postCode''''' (UK Postal Code)
* '''''latLong''''' (comma separated latitude and longitude)
* '''''email''''' (comma separated list of email addresses for alarms and reports)
 
 
The snapshot below shows a variety of setting types including numeric/text values, html, or JSON objects and arrays.
 
}}
 
[[File:Settings3.png]]{{Block | Persistent settings for local devices are held on disk and in the '''''global.deviceSettings''''' object, and are specific to a device (or node).}}
 
== Links ==
 
* https://github.com/mcci-catena/docker-iot-dashboard  A  GitHub project using similar architecture for monitoring LoRaWAN devices.

Latest revision as of 01:17, 29 November 2022

Basic Architecture

Features:
  • Real-time global commutation (<0.5s latency) of any payload type between millions of devices
  • Open source and licence free for life
  • Battle hardened, standard and secure technologies
  • Simple to use for plumbers and electricians
  • Can connect to anything, physical or web based, and make use of commercial services and APIs
  • Implement a standard dictionary structure to enable interoperability between systems
Controls software is written in Node-RED version 2+.
Communications between systems is performed using MQTT.

We have chosen to base the Open Controls Architecture on Node-RED for a number of reasons:

  • Open source and free to use at will
  • Cross platform, from PCs, to cloud servers to embedded devices, the Raspberry Pi, and many industrial PLCs
  • Very stable, having been actively developed for over 10 years with the likes of IBM
  • Simple to use with a visual interface that compares to electrical wiring
  • Software can be copied and pasted from one system to another, dropped in and wired up
  • Infinitely versatile with standard and custom components available from an online library to achieve almost any function or connect to any system
  • Complex software can be built in a hurry, dragging components in and wiring up, then refined and packaged into neat and updateable components
  • Built on Node.js and JavaScript, possible the world's most active software environment as used on all web pages
  • Used by almost everyone - from hobbyists through to mobile phone companies - with considerable community support
  • Provides a means to easily implement new and existing technologies and online services, including machine learning, peer-to-peer communications, databases, and encryption


Nr1.png

Node-RED version 2 (or higher) is required for the latest active MQTT management.



In addition to the standard Node-RED set of Nodes we make use of the following. These can be easily installed into any instance of Node-RED from the Palette Manager:
  • node-red-contrib-heatweb provides a set of nodes to implement the protocols used on this site
  • node-red-dashboard provides a live user interface
  • node-red-node-email provides email functions

Other Nodes are used, and can be installed as required.

Software works through payloads of data (messages) passing along virtual (and real) wires, from one node to another. Messages have both a payload and a topic.

A node can be:

  • a function block within Node-RED (a Node-RED Node)
  • an instance of Node-RED (a Controller Node)
  • any point in the communications network (e.g. an MQTT Broker)
Topology6a.png
Each instance of Node-RED has an identifier, stored under global.node
camelCase is used for variable names and topics, where the first letter of additional words are capitalised, and spaces removed.
  • Only letters and numbers should ever be used in naming.
  • Dashes (-) may be used to create hierarchy as described below
  • Underscores ( _ ) can be used at a software level, to add functionality, but not at an operational or user level.
  • Spaces, full stops, commas, apostrophes, or any special characters must NEVER be used in naming.

Communications

A standardised 5 level MQTT topic structure is used throughout. network / node / device / vargroup / varkey.
See https://github.com/heatweb/heat-network
Bmscoms1.png



Systems run a local Mosquitto MQTT broker to distribute data both internally and to enable external subscriptions.
Additional local MQTT brokers can be established through Docker Containers.
The external network identifier, used for all data published to external MQTT brokers, is stored under global.networkId
This must be unique (long) and without spaces.
Data from within a node or from connected devices is assigned a local network identifier of "local" (stored under global.localNetworkId) so that the node's external network identifier can be changed without affecting internal software. Separate internal and external identifiers also allows for separate message rates, where local traffic can be high speed. Node-RED is used to apply Reporting By Exception rules, to limit traffic to significant values (e.g. 0.25C), and save bandwidth.
Handler0.png


Mqtt6a1.png

In the real world, devices and networks are nested - a building may have a network ID, but this may be fed from a plantroom, also with its own identity. To accommodate nested networks, a dash is used to prefix topics (and hence the network ID) and thereby maintain a five level topic structure - important for wildcard subscriptions to work..
myNetwork/plantroomNode/plantroomNode/settings/title = "Main Plantroom Controller"
block1/blk1node/blk1node/settings/title = "Block 1 Controller"  !!! DO NOT USE COMMON NETWORK IDs

Adding a prefix to sub-networks ensures networks remain unique on a higher level server. E.g. There may be two unconnected networks with sub-networks called "block1".

myNetwork-block1/blk1node/blk1node/settings/title = "Block 1 Controller"
anotherNetwork-block1/blk1node/blk1node/settings/title = "Block 1 Controller"
Where managing multiple networks, it is advised to use long and non-descriptive unique identities. When creating new configurations a random 8-16 character ID should be generated.

e.g. Ea5lQXfF2tmBlzYk


Nodes should also be given unique identities. Nodes Id's can be shorter as they only need to be unique within a network, rather than globally (in the whole world).

e.g. jxt15Ewk

The titles of networks, as well as nodes, can be saved and found under its device setting.

Ea5lQXfF2tmBlzYk/jxt15Ewk/network/settings/title = "My Heat Network"
Ea5lQXfF2tmBlzYk/jxt15Ewk/jxt15Ewk/settings/title = "Main Plantroom Controller"

And to simplify for sub-nodes it is possible to use a node's id as the node's network identifier.

a5lQXfF2tmBlzYk-fg4jS8s7/fg4jS8s7/network/settings/title = "Block 1 Heat Network"
a5lQXfF2tmBlzYk-fg4jS8s7/fg4jS8s7/fg4jS8s7/settings/title = "Block 1 Controller"
a5lQXfF2tmBlzYk-fg4jS8s7-nnf555dE/nnf555dE/nnf555dE/settings/title = "Block 1, Flat 17 Controller"


Data Groups

The topic group (vargroup) (4th level) is used to define the type of data. Values include:
  • dat (operational data)
  • stat (statistics and status)
  • settings (persistent settings)
  • cmd (a command)
  • set (command to change a setting)
  • system (software and networking)
  • meter (meter data)
  • alarm (alarms and warnings)
  • ana (analogue readings)
  • json (JSON formatted data)
  • modbus (Modbus serial data)
  • design (preloaded design data)
Topic groups that are manufacturer or organisation specific, should use an all CAPITAL group identifier. This should represent the organisation, be unique, and may include dashes to create multiple groups under a single organisation.
  • TIL (Thermal Integration Ltd.)
  • PCDB (SAP Product Characteristics Database)
  • BENCHMARK (Benchmark information)

Manufacturer specific data groups can be used by systems to load a manufacturer's default data attributes, enabling the protocol to be extended as required.

They allow, for example, multiple organisations to publish the same data on a device (such as a heat network) without collisions.

Handling Data

Within Node-RED a Message Handler Node is used to handle data generated locally.
Handleroptions.png
  • The Node has two outputs - one for local traffic, and one for external traffic.
  • Report by exception rules are applied to external traffic.
  • The Node formats topics to the five level standard, adding group and device if missing.
  • The Node stores data into global.readings, along with any attributes within the incoming message, as well as timestamps.
  • The Node stores historical data into global.readingsHistory, along with timestamps, removing repeat values.
  • New attributes are read from incoming messages, and existing attributes added to outgoing traffic.
  • Handles the set data group, altering settings and saving to disk.
  • Handles the json/sync topic, updating stored device readings and attributes to incoming sync data.
  • Handles the cmd/sync topic, sending stored device readings and attributes as JSON.
  • Handles the cmd/request topic, sending stored data as per requests.
  • Additional routing can be performed within Node-RED, including selection of retained vs unretained routes.


Handler1.png

Handler Nodes use a configuration node to store setup information including network and node identities.

Handleroptions2.png

Routing Data

Where a number of nodes sit on a Local Area Network (LAN) it is common to use a central local MQTT broker.
Handler3.png

Mqtt6a.png

Traffic can be routed to a Cloud MQTT broker by the use of MQTT Bridges. These run on an MQTT broker, and can re-publish messages filtered by topic (networkId) to another broker. Bridges are managed outside of Node-RED.
Handler7.png
Additional Report By Exception rules can be applied inline.
Handler5.png
On larger networks where data is shared between local nodes, Reporting By Exception can be centrally managed using a Node-RED instance, along with any additional MQTT broker functions such as providing backup routes.
Mqtt6a2.png
Handler6.png
Handler4.png
Cloud based instances of Node-RED, as used on this Wiki, are often used to pull together data from various MQTT brokers into one place.
Handlercloud.png

Complex Architecture

MQTT allows granular sharing of data and the scaling of complex network topologies.
Mqttsys2.png


Security and Access Control

Each MQTT Broker runs its own security settings, with a list of users and associated topic permissions (read & write). Additional bridges enables data between MQTT brokers to be managed, and allows common user/password lists to be utilised. Password lists are based on hashed passwords (one way encryption) so that original passwords are never known or shared.
Devices within a local network (LAN) can be protected using standard firewall rules with port forwarding used to expose MQTT services as required. Pulling all data and communications through MQTT allows all other external routes to be more easily locked down, with only secure MQTT ports to the LAN Broker exposed online. In this way external access is completely ruled by the same MQTT users and password structure.
User access rules are stored in an ACL File, with the following powers:
  • Access rules can be applied to read and write permissions separately.
  • Wildcards can be applied to rules, on any of the topic levels. This allows, for example, a particular user to be given access to myNetwork/+/+/meter/# providing access to meter data from myNetwork, all nodes and devices.
  • General rules can be setup for all users, providing global data.
  • Rules can include special fields, such as the MQTT client id or username. This allows general rules to be setup that, for example, +/+/%u/cmd/# provide nodes with read access to commands directed at them.
As MQTT can transport any form of data at high speed, including raw buffers, many insecure serial communications protocols, including Modbus and M-Bus can be piped via MQTT topics, rather than expose them directly. This pulls access to the data into the common rules.

Separate read topic and write topic are used, for example:

myNetwork/+/n5hsi72k/modbus/request
myNetwork/n5hsi72k/n5hsi72k/modbus/response

Likewise, the transparent M-Bus port on an Elvaco CMe3000 could be piped over:

myNetwork/+/cme3000/mbus/request
myNetwork/n5hsi72k/cme3000/mbus/response

It would however be more normal to convert bus data such as this into individual topics for each register or field and expose these through MQTT to provide more granular control over access, remove the need for remote handling, and add report by exception rules (rather than keep continuously fetching values to catch a change).

Data Attributes

Attributes (metadata) provide additional information about data, such as units and a description. They include:
  • units (units for data)
  • title (short description)
  • points (maximum data points to store in history)
  • deadband (the deadband used for external communications)
  • timestamp (unix time data is generated or handled)
  • changed (unix time data last changed)
  • attributes (an object containing custom attributes)
Attributes are generally loaded from a central index (GitHub or LAN hosted), providing additional information such as units and descriptions. This is to avoid the need to locally describe data, and to assist in compatibility. Custom attributes may be added inline to messages and will override defaults. See https://raw.githubusercontent.com/heatweb/heat-network/master/devices/default_topics.json
Loaded attributes are saved in a global Node-RED object,and will be added to messages as they are handled, and stored into readings alongside the value (payload). They are however not transmitted through MQTT - only topics and payloads are transmitted by default. As such it is important to try and use standard topics where possible, selecting a topic by its standard attributes.

The flow below shows a message object, with attributes, before and after going through an MQTT connector.

Note that only the topic and payload survive transit.

Note that dat/tOut is a standard topic, so the attributes (units and title) would be added back in by a Handler Node.

Trafficvar.png

Attributes can be transmitted through MQTT in one of two ways:
  • A special command cmd/sync can be sent to a nodes message handler asking it to publish a full JSON object for a device (or devices), including all data groups, values, and attributes. The command payload is an MQTT topic including wildcards, e.g. local/# (all), or +/+/boiler1/#. The reply for each device that matches is sent on the corresponding topic, e.g. myNetwork/node123/boiler1/json/sync and can be handled by a receiving system.
  • Packaging a message as a JSON object, value and attributes, and send this instead of just the value. A receiving system can work out the payload is JSON and handle appropriately.
Attributes take up a lot more bandwidth in traffic, and as they are generally static or default values, only custom attributes need to be transmitted, and only at startup or on request.

Node-RED Global Objects

Within Node-RED, data and attributes are stored within the global.readings object.

Data stored in global objects is held in processor memory and not on disk.

The current data can be viewed within Node-RED in the data explorer.

Readings1.png

Data within the readings object is nested according to the topic (excluding the node as more than one node may publish data on a device).
network -> device -> group -> key
e.g. a message with a topic myNetwork/node123/myDevice/dat/outputTemperature  would be stored in (global).readings.myNetwork.myDevice.dat.outputTemperature.value

Internally, message topics can be truncated and the network and node will be filled in. The data group will be assumed to be "dat" if not supplied, representing operational data.

e.g. a message with a topic setpoint  would be stored in (global).readings.local.myNode.dat.setpoint.value


The following code could be used to read data and its attributes for output.

 var localNetworkId = global.get("localNetworkId");
 var node = global.get("node");

 var reading = global.get("readings." + localNetworkId + "." + node + ".dat.outputTemperature");

 var output = "The value of " + reading.title + " is " + reading.value + reading.units;  
 // "The value of Output Temperature is 35°C

Historic data is saved into the global.readingsHistory object, in the same structure as global.readings, but containing an array of timestamped values.
Persistent settings for a node (or application) are held on disk and in the global.settings object. This is for local operational settings.

Settings have a type, may have maximum and minimum values, units and a title. Certain types require additional fields such as select from a list settings.

Standard settings include:

  • title (system title / name)
  • io (system input/output configuration in JSON format)
  • postCode (UK Postal Code)
  • latLong (comma separated latitude and longitude)
  • email (comma separated list of email addresses for alarms and reports)


The snapshot below shows a variety of setting types including numeric/text values, html, or JSON objects and arrays.

Settings3.png

Persistent settings for local devices are held on disk and in the global.deviceSettings object, and are specific to a device (or node).

Links