Skip to content

Node-RED Module

Configuration Example

Example section from configuration file:

<node-red>
  <executable>node-red</executable>
  <settings-path>/etc/node-red.js</settings-path>
  <theme>dark</theme>
  <flow-path>/etc/node-red.json</flow-path>
  <authentiation>
    <editor username="admin" password="admin"></editor>
    <ui username="admin" password="admin"></ui>
  </authentication>
  <endpoint host="0.0.0.0" port="1880"></endpoint>
</node-red>

In this example, we run a Node-RED server listening on port 1880 on all interfaces with authentication enabled and loading the existing flow described in the JSON file located at /etc/node-red.json. Except for flow-path and authentication, all of the settings in this example are the defaults. The default value for flow-path is an empty string, causing Node-RED to load an empty flow when it starts up. The authentication setting is empty by default, causing the editor and UI to be accessible without credentials.

To use all the default settings, just add <node-red></node-red> to the OT-sim configuration file.

Node-RED Module Overview

OT-sim is capable of integrating with Node-RED using custom Node-RED nodes distributed as part of the OT-sim source code. The Node-RED integration is enabled and configured using the OT-sim node-red module as described above, which runs a Node-RED server alongside OT-sim for users to access.

Two custom OT-sim Node-RED nodes are available, ot-sim in and ot-sim out. Each node is automatically configured with the correct OT-sim message bus endpoints to connect to via the Node-RED settings file that is generated by the OT-sim module.

There are at least two ways the Node-RED integration can prove useful:

  1. Using Node-RED flows to provide an HMI
  2. Using Node-RED flows as a replacement for the logic module

Demo Video

This video demonstrates the use of Node-RED with OT-sim as a simple Human Machine Interface (HMI) that monitors the per-unit voltage of Bus 692 and controls the breaker status of Line 650632.

The Procfile.single process file is used in the video, which starts a HELICS broker, an OpenDSS federate running a simulation of the IEEE 13 bus system, and an OT-sim device using the config/single-device/device.xml configuration file. This configuration file starts, among other things, the I/O module (a HELICS federate) and the Node-RED module.

To recreate the environment in the video, execute the following steps:

  1. Build the ot-sim Docker image: docker build -t ot-sim .
  2. Run an ot-sim Docker container: docker run -it --rm --net host ot-sim bash
  3. Execute the process file in the container: hivemind Procfile.single
  4. Browse to Node-RED: http://localhost:1880
  5. Press ctrl-i in the Node-RED editor and import the following flow
[
    {
        "id": "172c64bad7a4e035",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "42fb9f9b2e9aae42",
        "type": "ot-sim in",
        "z": "172c64bad7a4e035",
        "tag": "bus-692.voltage",
        "updates": false,
        "x": 200,
        "y": 320,
        "wires": [
            [
                "2ea9878d91da5797"
            ]
        ]
    },
    {
        "id": "2ea9878d91da5797",
        "type": "ui_gauge",
        "z": "172c64bad7a4e035",
        "name": "",
        "group": "cd530edaea3a5672",
        "order": 1,
        "width": 0,
        "height": 0,
        "gtype": "gage",
        "title": "Bus 692 Voltage",
        "label": "p.u.",
        "format": "{{value | number:3}}",
        "min": "0.9",
        "max": "1.35",
        "colors": [
            "#ca3838",
            "#00b500",
            "#ca3838"
        ],
        "seg1": "0.96",
        "seg2": "1.1",
        "diff": false,
        "className": "",
        "x": 860,
        "y": 320,
        "wires": []
    },
    {
        "id": "1b2b2a5122909a56",
        "type": "ot-sim out",
        "z": "172c64bad7a4e035",
        "tag": "line-650632.closed",
        "x": 870,
        "y": 480,
        "wires": []
    },
    {
        "id": "0abc55bd5a667739",
        "type": "ui_button",
        "z": "172c64bad7a4e035",
        "name": "",
        "group": "cd530edaea3a5672",
        "order": 2,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Trip",
        "tooltip": "",
        "color": "",
        "bgcolor": "green",
        "className": "",
        "icon": "",
        "payload": "0",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 570,
        "y": 400,
        "wires": [
            [
                "1b2b2a5122909a56"
            ]
        ]
    },
    {
        "id": "3bea0bd21f09d964",
        "type": "ui_button",
        "z": "172c64bad7a4e035",
        "name": "",
        "group": "cd530edaea3a5672",
        "order": 3,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Close",
        "tooltip": "",
        "color": "",
        "bgcolor": "red",
        "className": "",
        "icon": "",
        "payload": "1",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 570,
        "y": 540,
        "wires": [
            [
                "1b2b2a5122909a56"
            ]
        ]
    },
    {
        "id": "9c5eaebffe2ff15e",
        "type": "ot-sim in",
        "z": "172c64bad7a4e035",
        "tag": "line-650632.closed",
        "updates": false,
        "x": 130,
        "y": 480,
        "wires": [
            [
                "5350b0834d821a9d",
                "104a4cdbed5f1039"
            ]
        ]
    },
    {
        "id": "5350b0834d821a9d",
        "type": "change",
        "z": "172c64bad7a4e035",
        "name": "Trip Enabled",
        "rules": [
            {
                "t": "set",
                "p": "enabled",
                "pt": "msg",
                "to": "msg.payload = 1",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 350,
        "y": 440,
        "wires": [
            [
                "0abc55bd5a667739"
            ]
        ]
    },
    {
        "id": "104a4cdbed5f1039",
        "type": "change",
        "z": "172c64bad7a4e035",
        "name": "Close Enabled",
        "rules": [
            {
                "t": "set",
                "p": "enabled",
                "pt": "msg",
                "to": "msg.payload = 0",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 360,
        "y": 520,
        "wires": [
            [
                "3bea0bd21f09d964"
            ]
        ]
    },
    {
        "id": "cd530edaea3a5672",
        "type": "ui_group",
        "name": "Default",
        "tab": "893465dd7a980296",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "893465dd7a980296",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

ot-sim in

The ot-sim in node subscribes to the RUNTIME topic on the OT-sim message bus and processes Status messages published by OT-sim devices. The node is configured with a tag, and outputs the tag name as the message topic and the tag value as the message payload to other nodes it's connected to in the flow. This node can be configured to also process Update messages via the Include Updates checkbox in the node editor.

ot-sim out

The ot-sim out node pushes Update messages to the RUNTIME topic on the OT-sim message bus. The node is configured with a tag, and pushes incoming values from nodes connected to it in the flow as updates for the tag.