Yes, I just didnt mention it because it only makes sense in seclusion - typically a function node makes use node context
- which is accessible only to its self. But a function node can also read/write (own)flow & global context
Node context, not path context.
Yes, I will be using node context, probably.
One of the steps will be "compare previous value to current" and for that I wanted to use node context, because the comparison of that value will always only be in that function node.
EDIT:
Small side question: must a msg always have a msg.payload? Or can I remove that and use custom msg properties only (like msg.Temperature)?
Small side question: must a msg always have a msg.payload? Or can I remove that and use custom msg properties only (like msg.Temperature)?
Yes, you can delete msg.payload
- but TBH, it is not necessary - just ignore it.
Yes you can add msg.anythingYouWant
PS: it is good practice to use camelCase in JS for your variable names (then you never forget if it starts with a capital letter etc)
One of the steps will be "compare previous value to current" and for that I wanted to use node context, because the comparison of that value will always only be in that function node.
Why are you doing this? Is it to only release a msg
if it has changed since the last time? Or something else?
Yes, you can
delete msg.payload
- but TBH, it is not necessary - just ignore it.
Right now the payload contains the value I want and I created a msg.Parameter which holds the information of which parameter that value belongs to, e.g. msg. Temperature.
I was thinking of renaming msg.payload to msg.Temperature. That way I have one less msg component and directly see the parameter.
Why are you doing this? Is it to only release a
msg
if it has changed since the last time? Or something else?
I do not want to publish on every change. I want to only publish if the value changes by a relevant amount.
I do not want to know if a value changes from 1500 W to 1503 W. But I do want to know if a value changes from 1 W to 3 W. So I want to use thresholds and power deltas.
Values below 10 W should report 3 W ichanges Values above 1000 W should report only 50 W changes. Always compared to the last value that cause a publish, of course.
in which case, you should really use the built in nodes. e.g. the filter (RBE) node.
There are lots of core nodes designed to do all the things you are attempting to do in functions.
Oh, I will definitely try that node first!
I am currently cutting down nodes and was wondering:
When do I need to use ;
and when do I not?
It does not seem to matter whether I use one after DewPoint of not. But in other languages you have to end each command/statement with one.
msg.DewPoint = msg.payload.DewPoint
return msg;
It is mostly optional and a stylistic choice in JavaScript. I chose not to use them. Like i adhere to camelCase and other style options like 'single quotes'
and space after comma etc. Once you have a style
, it helps you find things and spot typos etc.
P.S.: The return msg also seems superfluous.
No, it is necessary. If there is no return, no msg
is transmitted to the next node. That can be useful.
e.g.
if (everything is ok) {
return msg // send to next node
} else {
// do nothing - dont send msg to next node
}
Is there a function that can delete a msg property? Of coure the change node could, but in a function. A command like set()
Is there a function that can delete a msg property
Yes, you can
delete msg.payload
delete msg.payload
duh, I did not read it as a command
As Steve said you can use whatever property names you like, but we tend to use payload as the convention for where the āinterestingā part of the data is, as that is where most core nodes expect it to be. So things like the filter/rbe node should ājust workā without needing extra configuration if the data is in msg.payload
The problem with payload is that it no longer holds the information on the entity (Energy Power, Energy Total, Humidity, Temperature etc.). So I would need to store that information elsewhere.
The cleaner approach is to use a msg property named after the entity. I then know precisely at all times what that value belongs to.
Since the payload is then no longer interesting to me, I would delete it (just like "_msgid").
in which case, you should really use the built in nodes. e.g. the filter (RBE) node.
I just took a look at it and I do not think it is capable of handling what I need. I am not using a fixed threshold.
Here is what I once used in a simple tasmota approach (different but easily understandable syntax).
IF ((%value%>=var1) AND (var11!=var2)) powerdelta1 %var2%
ELSEIF ((%value%>=var3) AND (var11!=var4)) powerdelta1 %var4%
ELSEIF ((%value%>=var5) AND (var11!=var6)) powerdelta1 %var6%
ELSEIF ((%value%>=var7) AND (var11!=var8)) powerdelta1 %var8%
ELSEIF ((%value%<var7) AND (var11!=var10)) powerdelta1 %var10% ENDIF;
IF ((%value%>=var7) AND (var14!=600)) teleperiod 600
ELSEIF ((%value%<var7) AND (var14!=3600)) teleperiod 3600 ENDIF ENDON
%value% is the current sensor value, var11 is the previous value of the last reading, uneven numbered vars are the thresholds (e.g. if value > 100 W) and even numbered vars are the power delta (if value change > 3 W).
So the delta is dependent on the absolute value. I do not see this supported in the filter (RBE) node.
EDIT:
Just tried deleting
const matchingKeys = Object.keys(msg.payload).filter((element) => element.startsWith("ATC"))
matchingKeys.forEach((element) => node.send({
topic: "tele/xiaomi/" + element,
payload: msg.payload[element],
Time: msg.payload.Time,
delete msg._msgid
}))
but I get an error notification.
Here is an example msg object
{"topic":"tele/xiaomi/ATC4e211d","payload":{"mac":"a4c1384e211d","Temperature":33.6,"Humidity":31.9,"DewPoint":14.6,"Btn":1,"Battery":80,"RSSI":-67},"Time":"2023-09-05T18:04:02","_msgid":"33304bf813b225db","Temperature":33.6}
Since the payload is then no longer interesting to me, I would delete it (just like "_msgid").
Sure not a problem. Whatever works for you.
Though you canāt remove _msgid as if a node finds it missing it will recreate one on the next send.
Ah, _msgid was added by Node-RED? I thought it was something tasmota added and I never noticed
Yes, itās there for msg tracing. Usually it gets added at the start of a flow (first node) and can then be tracked through to its exit. There are times when thatās not possible , eg if a function node creates a new sequence of msgs, and they also get added whenever they are missing
relayed through an ESP32 dev kit board
If this board only deals with the Bluetooth devices you can change the topic for just this device.
eg ATC instead of tele - in Tasmota cmd window just type Prefix3 ATC
See topic-definition
A new MQTT in node can then subscribe to the Xiaomi Mijia / eq3 messages only. Then there is no processing required in NR to separate out these message types.
And to extract the information more easily "per" device just split and use a switch node to remove any parts without a mac address property. Based on the example message you posted earlier, here is a simple flow to show how.
[{"id":"4edc0ded06967bce","type":"inject","z":"be14baae.1728","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"Time\":\"2023-09-03T14:48:50\",\"ATC0d5c0c\":{\"mac\":\"a4c1380d5c0c\",\"Temperature\":21.6,\"Humidity\":66.2,\"DewPoint\":15,\"Btn\":0,\"Battery\":37,\"RSSI\":-68},\"ATC8f1b4f\":{\"mac\":\"a4c1388f1b4f\",\"Temperature\":21.9,\"Humidity\":62.9,\"DewPoint\":14.5,\"Btn\":0,\"Battery\":69,\"RSSI\":-62},\"TempUnit\":\"C\"}","payloadType":"json","x":245,"y":3660,"wires":[["49aeb16edeb19263"]]},{"id":"8f93c04cbdd9d362","type":"debug","z":"be14baae.1728","name":"debug 330","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":715,"y":3660,"wires":[]},{"id":"49aeb16edeb19263","type":"split","z":"be14baae.1728","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"topic","x":385,"y":3660,"wires":[["188759e44de3ee9e"]]},{"id":"188759e44de3ee9e","type":"switch","z":"be14baae.1728","name":"","property":"payload","propertyType":"msg","rules":[{"t":"hask","v":"mac","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":545,"y":3660,"wires":[["8f93c04cbdd9d362"]]}]
Each message contains all the relevant information with a topic unique to the device, you can then direct this as required based on the topic.
Color me impressed. You either use tasmota or really did your homework
The device deals with all bluetooth devices and a card reader. So using the prefix would only result in being able to distinguish between that particular ESP32 board and the other (tasmota) devices. For that I would not need to change the prefix because the esp32 board has its own topic anyway (based on mac).
There is a feature called GroupTopic
that should group devices into a dedicated GroupTopic
. I used it once but then did not re-enable it because group topics are limited to 4 group topics of which one is for tasmota and the other three can be customized.
To prevent running out of group topics, I decided to add the extra step in Node-RED rather than on the tasmota devices.
In case someone is wondering: using more ESP32 boards is not the solution either. They will all receive the BLE data form all broadcasting BLE devices and then process in parallel. I would need to filter the BLE devices on each ESP32 board. Again, more work than one node in Node-RED
There is a solution that I have been using in the past for the actual filtering on the ESP32 board: Berry.
The scripting language Berry lets me perform these filtering/powerdelta tasks on the board in tasmota. I then published the processed data on a dedicated topic per device.
However, Berry is well documented but hardly used. So despite the support by the tasmota team being excellent, it is difficullt to learn and read up on.
Plus, again, Berry far more work than Node-RED.
So, right now, idea is to keep 99 % of all work in Node-RED and do as little as possible on the tasmota devices
So, following some of the suggestions in this thread, I have now cut down my nodes (no, still using some functions where I could use normal nodes ) and named a bit cleaner. Square barckets are changes to the msg).
EDIT:
Is there a way I can connect a debug node to any of the outputs just to check if the flow variables were initialized? Or would I need to write a function that creates a msg containing the variable and hook that up to a debug node?
EDIT2:
Is it possible to sort the properties in a msg? This is not so vital, but nicer and I am curious