ESP8266 – Sming I2C

This brief post is about how to use the I2C bus/protocol with the Sming framework running on the ESP8266.
Since one of the Sming framework objectives is to be as close as possible to Arduino compatibility, it comes as no surprise, that I2C usage on the Sming framework is almost, if not identical, to the Wire Library on the Arduino.

Starting up:
Before using the I2C functions we need to initialize the I2C bus, otherwise the ESP8266 will crash when using it.
There is no need to include any .h file to access the global Wire object, so just initialize it with the Wire.begin() function. By default the bus will be on the pins GPIO0 and GPIO2:

  1. GPIO0 – SCL (Clock)
  2. GPIO2 – SDA (Data)

But those default pins can be changed before initializing the I2C bus with the function Wire.pins( SCL , SDA).

So a possible initialization sequence could be something like:

void startMain()  {  // Called from the Wifi connected callback
 ...
 ...
 Wire.pins ( 0 , 2 ); // SCL, SCA -> 0 and 2 are the defaults. This is optional.
 Wire.begin();        // Initialize the bus.  This is mandatory.
 ...
 ...

And now we can use the Wire object to access the I2C bus.

Reading and writing on the I2C bus:
After the bus is initialized we can read and write from/to I2C connected devices:

  Wire.beginTransmission(I2C_addr);       // An I2C transaction always starts with this.
  Wire.requestFrom( I2C_addr, length);    // Request for reading.

  while(Wire.available())                 // Loop as data is available
  {
	  for(uint8_t i = 0; i < length; i++)
	  {
		  buffer[i] = Wire.read();// Collect data.
	  }
  }
  Wire.endTransmission();                 // I2C transaction always ends with endTransmission()
}

On the above case the code will read lenght bytes from the I2C I2C_addr address. This will work for example for an I2C device that has no command register, so no need to define what we want to read. An example of that is the PCF7485 I2C expander.

 // The PCF7485 only reads one byte:
 byte readPCF7485( int I2C_addr ) {
     byte b;

     Wire.beginTransmission(I2C_addr);
     Wire.requestFrom( I2C_addr, 1);
     b = Wire.read();
     Wire.endTransmission();

     return b;
 }

But for devices that have a command register and return several bytes, like the BMP180, something like this is what is used:

// Taken from the BMP180 lib and adapted for use as an example.
void readBMP180(int BMP180_Address, int sub_address, int length, uint8_t buffer[])
{
  Wire.beginTransmission(BMP180_Address);
  Wire.write(sub_address);
  Wire.endTransmission();
  
  Wire.beginTransmission(BMP180_Address);
  Wire.requestFrom(BMP180_Address, length);

  while(Wire.available())
  {
	  for(uint8_t i = 0; i < length; i++)
	  {
		  buffer[i] = Wire.read();
	  }
  }
  Wire.endTransmission();
}

So the above code samples show how to read and write data to the I2C bus. A simple I2C write code looks like:

 void writePCF8574( int I2C_addr , byte data ) {
    Wire.beginTransmission(BMP180_Address);
    Wire.write( data );
    Wire.endTransmission();
 }

I2C bus scanner:
Available on the Sming code base there is an I2C bus scanner. This function will scan all possible I2C address to see if any I2C connected device is available. For reference the code is as follows:

void scanI2CBus()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
	// The i2c_scanner uses the return value of
	// the Write.endTransmisstion to see if
	// a device did acknowledge to the address.
	Wire.beginTransmission(address);
	error = Wire.endTransmission();

	WDT.alive(); // Second option: notify Watch Dog what you are alive (feed it)

	if (error == 0)
	{
	  Serial.print("I2C device found at address 0x");
	  if (address<16)
		Serial.print("0");
	  Serial.print(address,HEX);
	  Serial.println("  !");

	  nDevices++;
	}
	else if (error==4)
	{
	  Serial.print("Unknow error at address 0x");
	  if (address<16)
		Serial.print("0");
	  Serial.println(address,HEX);
	}
  }
  if (nDevices == 0)
	Serial.println("No I2C devices found\n");
  else
	Serial.println("done\n");
}

So when we are prototyping we can at startup call the scanI2cBus() to get a list of available devices on the terminal console.

Final thoughts:
The Wire object is global and it is compatible with the Arduino code and the many libraries that are available, for example the BM180 library that is available on the Sming framework.

But Sming framework also offers a TwoWire class for I2C communication, that possibly allows to have multiple I2C buses, if that makes sense, to be available. But if we use this class instead of the Wire global object, most of the libraries don’t work because of the Wire object dependency.

Sigfox BackEnd – Receiving and processing data

The Sigfox network provides a backend service where all Sigfox network devices messages are received and where the client/customer can pick up data from it’s own devices through using a REST API. But using the REST API means that we need to  pool for messages, which is not very efficient.

Another alternative provided by the SigFox backend is a callback mechanism. The callback mechanism can be done through email, where the data is sent by email to the destination, or through an HTTP call to a client/customer owned server. In my case I’ve used a open access IBM Node-Red Server available on the Internet as my own callback server, to process the call backs.

With IBM Node-Red we can easily  bridge the HTTP callback call to a MQTT topic publish. With this HTTP-MQTT bridge it means that every HTTP callback generates an MQTT publishing event, and any subscriber listening to the associated topic receives the Sigfox message. From here we can do whatever we want, and still using Node-Red, we can process the data, or store the data on databases, like InfluxDB where we can then use Grafana to graph the data.

Callbacks to the client/customer private server can be of type Uplink or Bidirectional. In the first case the private server just receives the data. On the second case the backend server, receives the data and responds with something meaningful that is sent to the device, if the device asked for a downlink response.
The response of the private backend server to the Sigfox backend server must be under 10s, otherwise the Sigfox servers will call one more time before raising an error. Also the downlink responses to the devices are, as far as I’m aware, not sure on this, limited to 12 messages per day.

For the callback configuration we have the following screen:

SigFox Callbacks

So an email callback definition for processing incoming data (uplink) from the device by receiving data and sending an email can be as follow:

Sigfox email uplink callback

Or we can call a backend server and return a response to the device if requested. The call can be made through a GET request where the message parameters are sent on the query string, or through the POST or PUT method where the body can be a JSON body with the data:

SigFox HTTP Callback

To let the above callback to define the return data to the device, when a downlink message is requested, we must change the device configuration:

Device Configuration

Otherwise, when direct mode is defined, the access point ID and RSSI is returned.

Also for the HTTP callback, there is the possibility of a HTTP batch callback, where several device messages that arrive in one second at the Sigfox backend, are grouped in a single callback call. This avoids heavy load on the call back private server.

Sigfox Callback to MQTT bridge:
This is rather simple to build with Node-Red:
Node-Red MQTT bridge

[{"id":"2a552b3c.de8d2c","type":"mqtt-broker","broker":"192.168.1.17","port":"1883","clientid":"node-red"},{"id":"46ac4f4b.659e48","type":"http in","z":"fdd8cabf.2bfe1","name":"","url":"/cback","method":"post","swaggerDoc":"","x":254.1666717529297,"y":113,"wires":[["f6d8300b.c1777","9c710907.61bd5","7f610b6a.5f6aac"]]},{"id":"f6d8300b.c1777","type":"http response","z":"fdd8cabf.2bfe1","name":"response","x":507.1666717529297,"y":113,"wires":[]},{"id":"9c710907.61bd5","type":"debug","z":"fdd8cabf.2bfe1","name":"","active":true,"console":"false","complete":"true","x":515.1666717529297,"y":205,"wires":[]},{"id":"7f610b6a.5f6aac","type":"mqtt out","z":"fdd8cabf.2bfe1","name":"MQTT Out","topic":"/sigfox/messages","qos":"","retain":"","broker":"2a552b3c.de8d2c","x":517.1666717529297,"y":289,"wires":[]}]

So we now define the callback as a POST call with a JSON object to the /cback path as defined on the HTTP input node as it can be seen on one of the above screenshots. The URL to be defined on the callback definition should be something like: http://node-red-ip:1880/cback

So now every Sigfox message activates a callback to the Node-Red HTTP Post node, and the message is routed to a MQTT out node for the /sigfox/messages topic.

An example of a received message by Node-Red is:

msg.payload : Object{ "device": "12345", "data": "12345566", "time": 1455758443, "rssi": "-124.80", "station": "0111", "snr": "20.68", "avgSnr": "23.34" }

So all is needed now is to process the data field from the JSON object and do something with the data.

For more information regarding callbacks, check out: SigFox Callback Documentation

Some Sigfox tests

So I’m doing some tests with the SigFox enabled Akeru board. This board has an ATMega 328, with bootloader, that makes it compatible with Arduino, and also has a SigFox TD1208 modem connected through serial to pins 4 and 5.
From every aspect that we can think this board, excluding the reserved 4 and 5 pins, works as a standard Arduino Uno R3 board, or clone.

The TD1208 chip, that enables communication with the SigFox network also has some other features available. One of them is the capacity to form some kind of a short range wireless based network with a maximum of 15 devices. This capability allows communications with, probably, other TD1208 chips and family (TD12XX), for a local wireless sensor network where one of the TD1208 devices act as a centralized gateway.. Since I don’t have any other TD1208 chips or boards with that chip or with compatibility for this network, I’m unable to try it. But it is worth a mention.

Also the TD1208 chip has an embedded ARM processor, which means that the TD1208 can be used by itself without the Arduino part. Still the Arduino way to use a serial port to communicate to the TD1208 chip is way easier that develop a native program for the TD1208. Check out this link for further information: TD1208.

Send data to SigFox
With this board there is nothing special to be done to send a message to the SigFox netowrk, and receive it at the backend. Still there are some things worth mention.

The simplest program:

#include <SoftwareSerial.h>
// To communicate with the embedded TD1208 Sigfox module, we use
// serial communications. The pins 5 and 4 are reserved on the
// SnootLab Akeru board.
// Pin 5 is RX
// PIN 4 is TX

const int SigFox_TD1208_RX = 5;
const int SigFox_TD1208_TX = 4;

SoftwareSerial sigfox( SigFox_TD1208_RX , SigFox_TD1208_TX );  

void setup() {
  Serial.begin(9600);
 
  Serial.println("Starting Sigfox Serial");  
  sigfox.begin(9600);
  delay(5000);   // (*1)

  Serial.println("Sending to sigfox");

  // The frames are a maximum of 12 hexadecimal bytes.
  sigfox.write("AT$SF=656667,2,1\n");   // (*2)

  Serial.println("Data sent...");
}

void loop() {
  // put your main code here, to run repeatedly:
  while(sigfox.available() ) {
    Serial.write(sigfox.read() );
    
  }
}

The code above looks and is simple enough, but needs some mentions:

We can see that (*1) there is a delay. I’ve found out that without the delay, at powering up the board (Not Reset!) the command to send data to the SigFox network fails. So this means that at power up, the TD1208 isn’t ready right away, and need some time to boot up. This makes sense since it has an ARM processor inside. Resetting the Arduino board, seems not to reset the TD1208, so without the delay, the above code doesn’t work at power up, but works fine after reset.

Sending data is also worth some mentions. Data can only be in Hexadecimal numbers, so bytes are from 0x00 to 0xFF.
So to transmit the word ‘Hello’ we need to send 0x48 0x65 0x6c 0x6c 0x6f:

   sigfox.write("AT$SF=48 65 6c 6c 6f\n");

The data is accumulated until the final new-line character: \n. Spaces are ignored.

This according to the TD1208 data sheet, will send the message twice to the network in probably two different frequencies.

If we want to receive a downlink message, we should pass two parameters to the AT command, first the number of transmissions (2 is the default and maximum value), and one for enable the request for the downlink. I didn’t found any information in how to set the downlink message, so it remains how to do that from the backend point. (Edit: it is callback controlled. See post: Sigfox – Processing Data )

   sigfox.write("AT$SF=48 65 6c 6c 6f, 2 , 1\n");

The results
Since I live in a dense urban area, results are excellent, but I’m not aware of how many gateway/base stations that I have at my area. I’ve only missed messages sent from underground (parking space), and even on of this cases, one of the messages did arrive, very weak, but it did.

What remains to be done?
Three things need to be done: A backend for processing the messages, but that is very easy to do with Node-Red, how to define, if possible, the downlink message, and how to enable and process events from the TD1208.
The TD1208 supports events for monitoring battery voltage, RSSI, temperature, but it seems it is for a TD1208 LAN based topology, not for the Sigfox network.

Low Power and Long Range Communications for IoT devices – SigFox

I was able to attend the SigFox Maker tour in Lisbon: SigFox Makers Tour, where Sigfox explained what it offers, and allowed a hands on approach to long range/low power communications by using a evaluation board from SnootLabs, the Akeru Beta 3.3. As we can see from the previous link, this is an expensive way of entering the long range/low power communications field, so it came (more or less) as a surprise that the board could be kept by the attendees.

SigFox is not alone on this market of M2M (machine to machine communication) where low power and long range is needed. Other contenders are the LoraWan alliance (Lora Alliance) with one open source, crowed sourced network in the making: The Things Network, the more closed Weightless M2M, and many others, like future 5G and LTE-M. Anyway, this is not the main topic of this post, let’s see the what SigFox is all about.

The problem:
Why long range and low power is needed for IoT? IoT is a greater set of a smaller subset of machine to machine communications (M2M from now on). IoT implements the structure, the applications over the devices that communicate and generate data. Think of Google or NetFlix as the IoT part, and TCP/IP, cables, fiber, as the M2M part. IoT can’t exist if devices can’t communicate. But most of the communication forms existing today requires power and vicinity to a communication gateway. Wifi devices need to be near a Wifi access point, Bluetooth, the same, other forms of communication, like Zigbee also need this. They also need large quantities of power, connected to mains, or need to have batteries to be recharged frequently.

So a solution for long range: distance between the device and the gateway can be Kms/Miles, and low power, batteries last years, is needed. Just set a device with what sensors is needed, and it communicates for years using batteries and without any more intervention.

These are the issues where SigFox and all the contenders come to solve. The drawback? Well devices can only transmit small amounts of data at low bit rates and sparsely, but this is for Internet of things, not for Internet of Talking things…

Sigfox Solution:
A great explanation of the SigFox solution is on these slides: SigFox Basics.
In short, SigFox protocol uses the ISM (Instrumental,Scientific,Medical) radio band ( 868MHz in EU, 902Mhz in USA), with a Ultra Narrow band 100Hz signal across a set of 200Khz frequency, where it transmits a 12 byte message (maximum) at a duty cycle of 1% per day. This gives around 140 messages/day. This is enough for transmitting sensor data each 10 minutes.
The signal can be received by any base station on the vicinity, and is delivered to the SigFox backend, where is deduplicated, if necessary.
At the back end the message can be delivered to the final destination either by email (not very useful) or by an HTTP callback.
The HTTP Callback is the process where the SigFox backend servers call your web server, available on the internet, either by http:// ou https:// with a specific set of configured parameters on the http request.

At least with the provided board (the Akeru) the power consumption when transmitting is around 25mA and the it drops when idle to very low values, almost negligible. And this is not the most efficient platform. Also, I’m sure that I’m several Kms away from the gateway. Compare this with the ESP8266, where it uses around 150/300mA when communicating and needs to be around the access point in meters!. The tests that I’ve done so far where always successful in dense urban areas, and inside buildings.

Starting up:
After receiving the board, there is a chip/device id set on top of the Sigfox module. With this id and a PAC (key?) we need to register at the SigFox backend: http://backend.sigfox.com.
At the Makers event, things didn’t went well at first with this registration, but after some fiddling from Sigfox part, it went OK. Still I see a major issue here on the provisioning process of new devices, if this process is needed to be done one by one… There is probably another way of connecting/registering devices on the Sigfox backend.
After the device is registered, with just one command, we can send data to the network.

Hands on
So a quick hands on: The Akeru board is an Arduino Uno compatible board and behaves as one. So we use the Arduino IDE. The only difference is the TD1208 SigFox modem (if we can call it that) on board, and with the serial lines connected to pins 5 and 4.
The TD1208 AT command set is available at this page: Documentation
The following Arduino program, loops over the serial ports, and allows to use the computer to communicate with the TD1208 module across the Arduino board.
I used the command picocom -b 9600 /dev/ttyUSB0 on my computer to communicate to the board:

#include <SoftwareSerial.h>
// To communicate with the embedded TD1208 Sigfox module, we use
// serial communications. The pins 5 and 4 are reserved on the
// SnootLab Akeru board.
// Pin 5 is RX
// PIN 4 is TX

const int SigFox_TD1208_RX = 5;
const int SigFox_TD1208_TX = 4;

SoftwareSerial sigfox( SigFox_TD1208_RX , SigFox_TD1208_TX );  

void setup() {
  // put your setup code here, to run once:
    Serial.begin(9600);   // For Computer communication
    sigfox.begin(9600);   // For talking with the embedded TD1208 module
}

void loop() {
  char c;
  if (sigfox.available() ) {
    Serial.write(sigfox.read());
  }
  if (Serial.available() ) {
    sigfox.write(Serial.read());
  }   
}

The command ATI shows the board information:

ATI
Telecom Design TD1208

OK

The command AT&V shows more information, like the firmware version, and device serial:

AT&V
Telecom Design TD1208
Hardware Version: 0F
Software Version: SOFT1451
S/N: 0007xxxx
TDID: 0xxxxxxxxx
ACTIVE PROFILE
E1 V1 Q0 X1 S200:0 S300:24 S301:2 S302:14 S303:1 S304:20 S305:25 S350:0 S351:32768 S352:1 S353:10 S400:000000 S401:FFFFFF S402:0 S403:869412500 S404:14 S405:32 S406:1

The ATI command can have some parameters, like 26, the current environment temperature, 27, the current voltage level, and 28, the voltage level when transmitting, when it’s drawing power from the power source. After reboot and without any transmission made, the ATI28 command returns zero.

To transmit a message, 12 bytes maximum!, we use the command AT$SS. The transmission data is Hexadecimal numbers, not ASCII. So AT$SS=Hello is invalid…

So to transmit data we will need to build our data by bit masking and bit concatenation to have data packed as efficiently as possible. For example the temperature for a room can be packed in 4/5 bits. Let’s see the Sigfox TD1208 module in action:

ATI28     <- Voltage when transmiting. Is zero after restart.
0.00

OK
ATI27
3.31

OK
AT$SS=10203040  <- Send message 0x10 0x20 0x30 x040 to the network.
OK
ATI28
3.31      <- Voltage when transmitting the previous frame. No drop due to be power up by USB...

OK

After the transmission, I’ve defined at the backend a email call back with all the possible data to be sent to my address. This is the result:

Device: 7xxxx
Time: 1455432456
Dup: false
SNR: 15.64
Station: 01A4
Data: 10203040
AvgSnr: 21.65
Lat: 49
Lng: -19
RSSI: -134.20
Seq: 22

As we can see the received signal strength (RSSI) at the receiving gateway was at an amazing -134.20 DBm!! This is an extremely low power signal. Wifi stops working around -80DBm, and that is at distances around meters.

Conclusion:
The Akeru board works fine and it’s easy to program. Still navigating the backend side is a bit of an hit or miss (topic for other post), but its functional.
Due to the network coverage on all Western Europe, free roaming for the devices, low power and long range, SigFox offer can make a dent on solutions that depend on GPRS or other competing solutions. This means that Sigfox is a readily available solution for some Enterprise/Startup uses/solutions that need low power, long range and free roaming with an established network.
Still the pricing for access the network is opaque (1€ to 20€/year, but per device, number of devices, company,startup?).

Also the maker community that is not able to access these Maker tours, where the hardware is free and can be kept, has a steep entry price. The entry kit is expensive and only offers a one year free fee to access the network. This can hinder the investment on the SigFox solution from individual Makers, and that, in my opinion, is the major issue.

ODroid C2

As an owner of an Odroid C1+ that is a great little device, it came to my knowledge it it might now be obsolete:)

This is because the Odroid C2 has came out: Odroid C2, and if I think that the C1+ is great, what to tell about the C2, that is around the same price point?

The specifications:

64bit S905 ARM quad-core 2GHz processor
2GB of RAM !
HDMI 2.0 with 4K support (not that it matters for me… )
Gigabit Ethernet, as the C1+
eMMC support.
Several other tid bits very similar to C1+.
Missing RTC.

So a major leap forward from the C1+ and from the RPi.

The 40$ price in Europe is no near that value, but probably around 50/55€ mark, my guess ( + P/P). Also the eMMC prices are still very high, almost, or even higher, than the price of the board itself.

Still I’m a bit wary of buying one since HardKernel (the Odroid manufacturer) only provides a 4 week warranty !? I bought mine in Europe, so I suppose it has a 2 year warranty by law.

I had no problems with my C1+, but I wonder, if something goes wrong…

MQTT Dashboards

The freeboard.io dashboard is one of the most popular dashboards to build an interface for displaying data. Still, for supporting the MQTT protocol some configuration is needed that is not exactly straight forward. Also if don’t want to use MQTT but web sockets, a similar not straight forward configuration is also needed. After that configuration (MQTT support for freeboard.io and WebSocket support for freeboard.io) we can add MQTT and Web Sockets datasources to our dashboards, and we get a nice customable dashboard framework.

Anyway there are some nice alternatives available that are worth some attention for someone that wants a simpler way of doing things:

CroutonCrouton MQTT Dashboard
Node Red UINode-Red-ui

Crouton
This dashboard is really nice since it has something that we might call as dashboard auto-configuration. We only need to configure the MQTT broker (with web sockets enabled, off course) and add device names to the configuration list. The device name is very important because it will be used in MQTT topic subscriptions (see below).

The Crouton dashboard configuration is stored on the browser local storage, so it’s not central. This means, that if you change browser or machine the configuration needs to be done again for that specific instance of browser and/or machine. Also, based on my experience, this is rather fidly, sometime it saves, other times it won’t, and need to reconfigure everything again after closing and opening the browser again.

The Crouton MQTT configuration is simple:

Crouton MQTT Configuration

MQTT Configuration

After the dashboard is connected to the MQTT broker, it searchs for specific topics based on the names configured on the Devices list. For each device it publishes to topic /inbox/devicename and subscribes to /outbox/devicename. At the initialization phase the Dashboard sends a get message to /inbox/devicename/deviceInfo. We can see that the device name is used to “find” a MQTT subscriber that answers to this topic. The subscriber that “owns” the topic /inbox/devicename answers to the get message with a JSON description of the device parameters to be shown at the dashboard on the /outbox/devicename/deviceInfo topic.

For example, on the following configuration:

Device Configuration

Device Configuration

The Crouton Dashboard sends to /inbox/Odroid/deviceInfo (Case Sensitive!!) and to /inbox/DiskStation/deviceInfo the message get and waits for a specific JSON response on /outbox/Odroid/deviceInfo and /outbox/DiskStation/deviceInfo to know how to automatically create the dashboard. With another words, the JSON response defines the dashboard. This means that to add a new metric, for example, we just need to add on the device the new metric and report it, no need to mess again with the dashboard configuration.

Auto Generated MQTT Dashboard

We can now use the mouse to move around the tiles, but the it seems also that this configuration isn’t stored.

This is the neat part of Crouton Dashboard, this auto-configuration.

The configuration is defined on the JSON response to /outbox/deviceName/deviceInfo MQTT topic. The JSON object defines the number of metrics and display format that device publishes and automatically associated to the metric name there is the MQTT topic /outbox/deviceName/Metric that the dashboard listens to.

On the Crouton GitHub there are two examples of this, one in Python and other in Lua for the ESP8266 NodeMCU based firmware.

I have a simpler one in Python, derived from the original Python example, for retrieving and send metrics from my Odroid SBC. The code is available here.

On the example note two things:

At the all.py file line 9, the clientName variable is set to Odroid. This is the device name to set on the Crouton dashboard.

Then for example, I publish my root disk space with the following JSON object segment:

        ....
        ....
        "endPoints": {
            "RootDisk": {
                "values": {
                    "labels": [],
                    "series": [0]
                },
                "total": 100,
                "centerSum": true,
                "units": "%",
                "card-type": "crouton-chart-donut",
                "title": "Root Disk"
            },....
            .....

The above configuration means that the end point /outbox/Odroid/RootDisk will have some value published that should be shown as a doughnut chart with % units.

A bit below on the code, there is an infinite loop, that each 30 seconds publishes to the topic the available disk space in percentage:

   client.publish("/outbox/"+clientName+"/RootDisk" , '{"series":['+str(disk_usage(rootPath))+']}')

As a conclusion, this Dashboard is rather interesting and worth a look, even with it’s, for now, issues with saving the configuration.

Node-Red-UI
While the Crouton Dashboard is an standalone Node.JS based application, the Node-Red-UI is an extension the Node-Red itself. It adds a new range of UI nodes to the Node-Red available nodes that allows to also build a Dashboard, but this time, not limited to MQTT. In fact any node that can inject data into a node-red-ui works.

The UI is available on the same address as Node-Red, but at the path /ui: Example:http://localhost:1880/ui/

For example, the following flow:

Node-Red-UI Flow

Node-Red-UI Flow

Generates the following UI:

Node-Red-UI

Node-Red-UI

The UI is based on the same MQTT topics and data published by my Crouton Python Client. The only thing needed is to extract the data from the MQTT message:

var space = msg.payload.series[0];
var msg ={"value":space , "payload":space};
return msg;

And the data feed from the “agents” work on both dashboards.

Anyway, regarding Node-Red-UI, it is an all other world, and I recommend to join and/or read the discussion group for this project.