Note to self (must be the third time I re-write this, so I better save it somewhere google will help me find again the next time I need it)
I have recently added to my home monitoring/automation system a bunch of smart plugs from LocalBytes who have the following features:
- ESP8266 based
- Tasmota firmware installed by default, no need to open/hack them to reflash them
- no data is sent to any cloud server in China or anywhere else
- they are reasonably priced
- they can be remotely controlled, and provide power consumption data
The plugs can be remotely controlled via MQTT publish/subscribe, and they also provide telemetry data through MQTT, in the form of a json encoded Object:
07:18:52.404 MQT: sonoff/tele/starlink/SENSOR = {"Time":"2022-11-04T07:18:52","ENERGY":{"TotalStartTime":"2022-11-03T15:32:39","Total":1.038,"Yesterday":0.594,"Today":0.444,"Period":0,"Power":39,"ApparentPower":44,"ReactivePower":22,"Factor":0.87,"Voltage":227,"Current":0.196}}
My home monitoring system, based on (https://emoncms.org/) is able to retrieve sensor data from a MQTT host, but it expects the data to be a in
single metric per topic e.g.:
In order to transform the single topic-json encoded object into multiple topics I am using a Node-RED flow:
The flow:
-
subscribes to an MQTT tree (in my case: sonoff/tele/# )
-
uses a Switch node to filter only SENSOR messages
-
uses a function node to retrieve the sonoff plug name from the topic, and splits the Json object into multiple key/value pairs, and sets them to the appropriate topic
var mytopic = msg.topic.replace(/sonoff\/tele\//g,"").replace(/\/SENSOR/g,"");
for (const [key, value] of Object.entries(msg.payload.ENERGY)) {
const el = {
"topic": "emon/" + mytopic + "/" + key,
"payload": value
}
node.send(el)
}
return null;
- publishes all single metrics to the target topic
The end result is that a single MQTT message of the form:
{
"topic": "sonoff/tele/brocade-sottotetto/SENSOR",
"payload": {
"Time": "2022-11-04T09:17:27",
"ENERGY": {
"TotalStartTime": "2022-11-03T15:23:32",
"Total": 1.232,
"Yesterday": 0.572,
"Today": 0.66,
"Period": 0,
"Power": 71,
"ApparentPower": 91,
"ReactivePower": 57,
"Factor": 0.78,
"Voltage": 226,
"Current": 0.402
}
},
"qos": 0,
"retain": false,
"_msgid": "1eca7e840d7e5188"
}
is split into multiple messages:
{
"topic": "emon/brocade-sottotetto/TotalStartTime",
"payload": "2022-11-03T15:23:32",
"_msgid": "1eca7e840d7e5188"
}
{
"topic": "emon/brocade-sottotetto/Yesterday",
"payload": 0.572,
"_msgid": "1eca7e840d7e5188"
}
{
"topic": "emon/brocade-sottotetto/Today",
"payload": 0.66,
"_msgid": "1eca7e840d7e5188"
}
{
"topic": "emon/brocade-sottotetto/Power",
"payload": 71,
"_msgid": "1eca7e840d7e5188"
}
and is picked up by my energy monitoring system where I can then store the values in appropriate time series …