# Many Tasmota Devices OR how to update many UI-Switches

**URL:** <https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025>\
**Category:** General\
**Created:** [28 March 2023 16:10 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025 "2023-03-28T16:10:01Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![dondario](https://avatars.discourse-cdn.com/v4/letter/d/2acd7d/32.png) [@dondario](https://discourse.nodered.org/u/dondario)\
**Post date:** [28 March 2023 16:10 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/1 "2023-03-28T16:10:01Z")

</div>

Hi together,  
due to the fact, that my first question [here](https://discourse.nodered.org/t/unset-property-overwrites-text-node/74473) got a so satisfying answer, I will try to explain my new Problem.

I have many Tasmota Devices (Switched-Power Outlets) and I switch them with UI Switches.  
To have the UI-Switch displaying the correct state I subscribe to the corresponding MQTT Topic  
**stat/$DEVICE/POWER** which is Updated on every switching cycle.  
A second topic **tele/$DEVICE/STATE** is published in regularly intervals, which I also want to subscribe to in case NodeRed was started, it can also get the actual state.

My Problem now: I have 30+ Devices and my Idea was to subscribe to all Devices at once:  
**stat/+/POWER** and **tele/+/STATE** which works great.  
I have a function node parsing the Payload and storing the state to a global context.  
A am also able to know which individual states changed since the last message (There are Tasmota Devices which have two or more outputs).  
But how do I route the state to the corresponding UI-Switch Nodes?  
My (not so elegant) approach is to add many Outputs to the function nodes and return the data like this:

```auto
var myMsg = {};
var v;
var myTopic = {};
var myState = {};

// Topic from tele/[$TOPIC]/STATE
myTopic = msg.topic.split("/")[1];
myMsg.topic = myTopic;
myState = global.get("tasmota_state") || {}; // retreive stored payload

// Decode Payload
// either from msg.payload.POWER or msg.payload.POWER1
// and if there are more POWER, change also the topic to $topic + "#"
if (msg.payload.hasOwnProperty("POWER")) {
    // POWER
    myMsg.payload = msg.payload.POWER;    
} else if (msg.payload.hasOwnProperty("POWER1")){
    // POWER1
    myMsg.payload = msg.payload.POWER1;    
}

// Store all Status Data in one Object "tasmota_state"
myState[myTopic] = myMsg.payload;
global.set("tasmota_state", myState); // store payload

// Return to according exit
if (myTopic === "hifi") {
    return [myMsg,v,v,v,v,v,v,v,v,v]
}
if (myTopic === "balkon") {
    return [v,myMsg,v,v,v,v,v,v,v,v]
}
if (myTopic === "bedlicht") {
    return [v,v,myMsg,v,v,v,v,v,v,v]
}
if (myTopic === "voegel") {
    return [v,v,v,myMsg,v,v,v,v,v,v]
}
if (myTopic === "bezzera") {
    return [v,v,v,v,myMsg,v,v,v,v,v]
}

```

**It works for me. But what is the elegant way?**

[source.json](https://discourse.nodered.org/uploads/short-url/p2cJV0is5tNSNftnP5GZNdbbwmT.json) (3.7 KB)

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [28 March 2023 16:29 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/2 "2023-03-28T16:29:01Z")

</div>

> [@dondario](#):
>
> stat/$DEVICE/POWER

First, I suggest making `stat/$DEVICE/POWER` persistent, then you won't need to subscribe to the tele state topic as well.  
Then I would adopt the simple solution of having an MQTT node next to each Switch node and feed them straight in. By using one MQTT node subscribed to them all you are just making life complicated.

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [28 March 2023 17:02 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/3 "2023-03-28T17:02:48Z")

</div>

> [@dondario](#):
>
> But how do I route the state to the corresponding UI-Switch Nodes?

There isn't too many ways to make such routing. One is the way you are doing it now.  
To make your function node more easy to read you can send out just one message with correct topic and wire it up to all switches but having filter before each ui\_switch which then passes message only if the topic is correct for that switch

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/6/b/6b77398eb9083918ee6a651079458054be3405bf.png)

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/f/af55864ed45195ff345df3d22c3e5123c6286e90.png)

Colin's advise is also valid but that is if you don't care the states of your devices inside node-red. If you make some decisions based on diferent states of devices, then it is absolutely correct to store them as you do.

---

<div class="post-metadata">

**Author:** ![dondario](https://avatars.discourse-cdn.com/v4/letter/d/2acd7d/32.png) [@dondario](https://discourse.nodered.org/u/dondario)\
**Post date:** [28 March 2023 17:57 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/4 "2023-03-28T17:57:45Z")

</div>

> having an MQTT node next to each Switch node  
> I thought that this is from the performance side not elegant, as the MQTT-Broker has to handle a huge list of topics, where i am subscribed to. BTW: Does anyone know if NodeRed opens a new connection to the MQTT-Broker for each node, or are all subscriptions processed in one TCP-Session.

One of the main reasons I'm reworking everything in NodeRed and tweaking the structure, which has grown to 24 flows over the last 5+ years, is that the UI took about 30 seconds to load on my iPhone.

I think the biggest factor was that i had some charts in the UI that probably all needed to be loaded.

But while I'm at it, I now have the ambition to make my configuration beautiful.

---

<div class="post-metadata">

**Author:** ![dondario](https://avatars.discourse-cdn.com/v4/letter/d/2acd7d/32.png) [@dondario](https://discourse.nodered.org/u/dondario)\
**Post date:** [28 March 2023 17:58 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/5 "2023-03-28T17:58:56Z")

</div>

Yes, that is a good idea, that will then probably be the solution how I will implement it

THANK YOU

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [28 March 2023 18:19 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/6 "2023-03-28T18:19:16Z")

</div>

Charts are best tools to help us make educated decisions to make any next move smarter. And that will be quite of step backwards if you have to get rid of them.

Yes, the dashboard can't handle charts too well. Of course the data optimization can help quite of bit but even then, the you never get adequate performance out of dashboard.

I have 10 charts on my custom made dashboard and it loads on mobile with 0.6 seconds.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/a/dad7bad128fad7e8af1d1f3b1eec2130478117d2.jpeg)

I do recommend to go with the DIY. As long you have and idea how it should look and what it should do, the community will help you get going and achieve your goal. It just takes you to get started. 🙂

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [28 March 2023 20:24 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/7 "2023-03-28T20:24:35Z")

</div>

> [@dondario](#):
>
> I thought that this is from the performance side not elegant, as the MQTT-Broker has to handle a huge list of topics, where i am subscribed to. BTW: Does anyone know if NodeRed opens a new connection to the MQTT-Broker for each node, or are all subscriptions processed in one TCP-Session.

It will make no significant difference to the overheads. It is all handled by one connection (assuming all the nodes use the same config node). In fact overall it will be more efficient as you will avoid all that testing and routing.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [28 March 2023 20:27 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/8 "2023-03-28T20:27:17Z")

</div>

> [@hotNipi](#):
>
> Colin's advise is also valid but that is if you don't care the states of your devices inside node-red. If you make some decisions based on diferent states of devices, then it is absolutely correct to store them as you do.

I don't understand what you mean by that. All you have to do is to route the mqtt messages to wherever you need them. I don't store any real world state in global context, I use persistent topics to store them all, with the big advantage that on restart all internal states get automatically aligned to the outside world by the initial messages from MQTT.

---

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [28 March 2023 21:06 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/9 "2023-03-28T21:06:27Z")

</div>

I am not sure this will be helpful but there again, it also may.

I wrote a `subflow` to make it modular and show the status of such devices.

```auto
[{"id":"94cf2ea396e5b6f6","type":"subflow","name":"MQTT Button Toggle","info":"# 2023 02 08\nAdded status text to icon to \nshow status of device.\n\n# 2023 01 25\nControl MQTT devices (power points)\nwith this node.\n\n`Button` node MUST have `topic` set to include\nthe device's name. eg: `A1/button`\nand the payload MUST be `X`\n\nSet the `Device Name` to (eg) `A1` to\ncontrol `A1` device.\n","category":"","in":[{"x":70,"y":160,"wires":[{"id":"7207fbe19cc07923"}]}],"out":[{"x":990,"y":200,"wires":[{"id":"66fb54e88f4acb8d","port":0}]},{"x":1190,"y":160,"wires":[{"id":"27d2dd9a875ab1a5","port":0}]}],"env":[{"name":"DN","type":"str","value":"","ui":{"label":{"en-US":"Device Name"},"type":"input","opts":{"types":["str"]}}}],"meta":{},"color":"#DDAA99","inputLabels":["MQTT (tele and LWT) and button input"],"outputLabels":["Back to `button` input","MQTT output"],"status":{"x":1070,"y":270,"wires":[{"id":"45a85f7621f5c28f","port":0}]}},{"id":"541720ad73579447","type":"switch","z":"94cf2ea396e5b6f6","name":"what message?","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"/stat/POWER","vt":"str"},{"t":"cont","v":"/tele/LWT","vt":"str"},{"t":"cont","v":"button","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":195,"y":160,"wires":[["61843ca1684f9f9d"],["4788b5265af1d45a"],["5b8cd9fe254ea8d1"]],"l":false},{"id":"61843ca1684f9f9d","type":"delay","z":"94cf2ea396e5b6f6","name":"Delay","pauseType":"delay","timeout":"200","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":340,"y":80,"wires":[["bdb2c46daf62b36f"]]},{"id":"6d4704f6fc9b98be","type":"change","z":"94cf2ea396e5b6f6","name":"RESET","rules":[{"t":"set","p":"payload","pt":"msg","to":"RESET","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":120,"wires":[["bdb2c46daf62b36f"]]},{"id":"4788b5265af1d45a","type":"switch","z":"94cf2ea396e5b6f6","name":"LWT","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"Online","vt":"str"},{"t":"eq","v":"Offline","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":340,"y":160,"wires":[["6d4704f6fc9b98be","bc2aabd04561d534"],["6a82c12953657965"]]},{"id":"6a82c12953657965","type":"function","z":"94cf2ea396e5b6f6","name":"BAN","func":"msg = {icon: '<font color = \"red\"><i class=\"fa fa-ban fa-3x\"></i></font>'};\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":200,"wires":[["8dc8a0dd2b669ae3","704ae850657c9724"]]},{"id":"bc2aabd04561d534","type":"change","z":"94cf2ea396e5b6f6","name":"Enable","rules":[{"t":"set","p":"enabled","pt":"msg","to":"true","tot":"bool"},{"t":"set","p":"ARLEC-1","pt":"flow","to":"ONLINE","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":160,"wires":[["66fb54e88f4acb8d"]]},{"id":"bdb2c46daf62b36f","type":"function","z":"94cf2ea396e5b6f6","name":"Set state","func":"let device = msg.topic.split(\"/\");\n//node.warn(\"Device \" + device[0]);\n//node.warn(\"Payload \" + msg.payload);\n\nif (msg.payload == \"RESET\")\n{\n let state = context.get(device[0]);\n if (state === 0)\n {\n //\n msg= {\"icon\": '<font color = \"red\"><i class=\"fa fa-toggle-on fa-rotate-270 fa-3x\"></i></font>',\"background\":\"black\"};\n return msg;\n }\n //\n}\nif (msg.payload == \"ON\")\n{\n msg = { \"icon\": '<font color = \"lime\"><i class=\"fa fa-toggle-on fa-rotate-90 fa-3x\"></i></font>', \"background\": \"black\" };\n context.set(\"STATE\",1);\n context.set(device[0],1);\n} else\n{\n msg = { \"icon\": '<font color = \"red\"><i class=\"fa fa-toggle-on fa-rotate-270 fa-3x\"></i></font>', \"background\": \"black\" };\n context.set(\"STATE\",0);\n context.set(device[0], 1);\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":120,"wires":[["66fb54e88f4acb8d"]]},{"id":"8dc8a0dd2b669ae3","type":"change","z":"94cf2ea396e5b6f6","name":"Disable","rules":[{"t":"set","p":"enabled","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"ARLEC-1","pt":"flow","to":"OFFLINE","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":200,"wires":[["66fb54e88f4acb8d"]]},{"id":"5b8cd9fe254ea8d1","type":"function","z":"94cf2ea396e5b6f6","name":"Button control","func":"let msg1 = {};\n\nlet x = msg.payload;\nlet counter = context.get(\"counter\") || 0;\nif (x == \"X\")\n{\n counter = (counter + 1) % 2;\n context.set(\"counter\",counter);\n if (counter === 0)\n {\n //\n msg.payload = \"OFF\";\n msg1 = {\"icon\": '<font color = \"orangered\"><i class=\"fa fa-toggle-on fa-rotate-270 fa-3x\"></i></font>',\"background\":\"black\"};\n\n } else\n {\n //\n msg.payload = \"ON\";\n msg1 = {\"icon\": '<font color = \"orangered\"><i class=\"fa fa-toggle-on fa-rotate-90 fa-3x\"></i></font>',\"backgound\":\"black\"};\n }\n}\nif (x == \"ON\")\n{\n // Force power ON\n msg.payload = \"ON\";\n msg1 = { \"icon\": '<font color = \"orangered\"><i class=\"fa fa-toggle-on fa-rotate-90 fa-3x\"></i></font>', \"backgound\": \"black\" };\n context.set(\"counter\",1);\n}\nif (x == \"OFF\")\n{\n // Force power OFF\n msg.payload = \"OFF\";\n msg1 = { \"icon\": '<font color = \"orangered\"><i class=\"fa fa-toggle-on fa-rotate-90 fa-3x\"></i></font>', \"backgound\": \"black\" };\n context.set(\"counter\",0);\n}\n\nreturn [msg,msg1];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":120,"wires":[["4f29a481b6f0d0e3","0ae8f43ccf9a1016"],["66fb54e88f4acb8d"]]},{"id":"4f29a481b6f0d0e3","type":"delay","z":"94cf2ea396e5b6f6","name":"Delay","pauseType":"delay","timeout":"100","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":1040,"y":120,"wires":[["27d2dd9a875ab1a5"]]},{"id":"27d2dd9a875ab1a5","type":"change","z":"94cf2ea396e5b6f6","name":"#1","rules":[{"t":"set","p":"topic","pt":"msg","to":"DN","tot":"env"},{"t":"set","p":"topic","pt":"msg","to":"topic&'/cmnd/power1'","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1040,"y":160,"wires":[[]]},{"id":"7207fbe19cc07923","type":"switch","z":"94cf2ea396e5b6f6","name":"Only for this device","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"DN","vt":"env"},{"t":"eq","v":"MASTER","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":135,"y":160,"wires":[["541720ad73579447"],["6a82c12953657965"]],"l":false},{"id":"0ae8f43ccf9a1016","type":"function","z":"94cf2ea396e5b6f6","name":"Identify","func":"let dev = env.get(\"DN\");\nlet status = msg.payload;\n\nnode.status(dev + \" \" + status);","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nnode.status(env.get(\"DN\"));\n","finalize":"","libs":[],"x":540,"y":270,"wires":[[]]},{"id":"45a85f7621f5c28f","type":"status","z":"94cf2ea396e5b6f6","name":"","scope":["0ae8f43ccf9a1016","f9f07adecaa02241"],"x":770,"y":270,"wires":[[]]},{"id":"704ae850657c9724","type":"change","z":"94cf2ea396e5b6f6","name":"Wipe status when unplugged","rules":[{"t":"set","p":"payload","pt":"msg","to":" ","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":305,"y":270,"wires":[["0ae8f43ccf9a1016"]],"l":false},{"id":"66fb54e88f4acb8d","type":"junction","z":"94cf2ea396e5b6f6","x":680,"y":200,"wires":[[]]},{"id":"86852c080f02187b","type":"mqtt in","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"","topic":"A1/stat/POWER","qos":"2","datatype":"auto-detect","broker":"bbf26a6c.b7922","nl":false,"rap":true,"rh":0,"inputs":0,"x":3990,"y":3120,"wires":[["f29f3ae3ad90c065"]]},{"id":"1e39d8c837d7b2fb","type":"mqtt in","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"","topic":"A1/tele/LWT","qos":"2","datatype":"auto-detect","broker":"bbf26a6c.b7922","nl":false,"rap":true,"rh":0,"inputs":0,"x":4000,"y":3170,"wires":[["f29f3ae3ad90c065"]]},{"id":"61ee633777cbbe4d","type":"link in","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"Button","links":["c2f5a62f6628cf5f","9b45b54a54fd7017"],"x":4055,"y":3210,"wires":[["f29f3ae3ad90c065"]]},{"id":"f29f3ae3ad90c065","type":"subflow:94cf2ea396e5b6f6","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"","env":[{"name":"DN","value":"A1","type":"str"},{"name":"Device name","value":"A1","type":"str"}],"x":4200,"y":3170,"wires":[["9ba2764071e69ef2"],["a468b0cde187f892","4acfea6a575732bb"]]},{"id":"9ba2764071e69ef2","type":"ui_button","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"A1","group":"5dde4bf66eb38aa1","order":1,"width":"1","height":"1","passthru":false,"label":"{{msg.icon}}","tooltip":"","color":"","bgcolor":"{{msg.background}}","className":"","icon":"","payload":"X","payloadType":"str","topic":"A1/button","topicType":"str","x":4410,"y":3140,"wires":[["9b45b54a54fd7017"]]},{"id":"a468b0cde187f892","type":"mqtt out","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"bbf26a6c.b7922","x":4410,"y":3180,"wires":[]},{"id":"9b45b54a54fd7017","type":"link out","z":"6dd5ca4d.d1958c","g":"08979a5b752f5e66","name":"link out 3","mode":"link","links":["61ee633777cbbe4d"],"x":4505,"y":3140,"wires":[]},{"id":"bbf26a6c.b7922","type":"mqtt-broker","name":"TIMEPI MQTT","broker":"192.168.17.39","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"SOM","birthQos":"0","birthRetain":"false","birthPayload":"BedPi Comms UP","birthMsg":{},"closeTopic":"EOM","closeQos":"0","closeRetain":"false","closePayload":"BedPi Shutting DOWN","closeMsg":{},"willTopic":"EOM","willQos":"0","willRetain":"false","willPayload":"BedPi COMMS FAILURE","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"5dde4bf66eb38aa1","type":"ui_group","name":"A(1-4) Sockets","tab":"e92ac76d.c24e7","order":13,"disp":true,"width":"4","collapse":false,"className":""},{"id":"e92ac76d.c24e7","type":"ui_tab","name":"Real_World_Control","icon":"dashboard","order":5,"disabled":false,"hidden":false}]

```

This is an entire flow for this `subflow` to show you how to use it.  
The `subflow` is the item of interest.

Yes, it probably does have some short comings mentioned above.  
But it may be of some use.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [27 May 2023 21:06 UTC](https://discourse.nodered.org/t/many-tasmota-devices-or-how-to-update-many-ui-switches/77025/10 "2023-05-27T21:06:49Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
