My Dashboard (some impressions)











image


4 Likes

Wow that's a lot of dashboard widgets! Do you see performance issues?
What platform are you running Node-Red on?
What is the browser memory usage like?

See dashboard 12 :wink:

My Dashboard (some impressions)

"Just like that"

"Nice to see you, to see you nice"

"Hasta la vista, baby"

"I love it when a plan comes together"

I couldnt resist :slight_smile:


@WhiteLion that is a fair amount of integration going on. Well done getting it all dashboarded - looks good.

2 Likes

There is a good tool to get pretty adequate measurements of page performance (and many other measures) everybody can see (and share) if the one can use Crome browser.

1 Like

running it on an raspberry pi 4 / 4GB / 64bit Raspberry Pi OS (Desktop)

  • wireguard
  • tensorflow (because auf coqui speech recognition)
  • mqtt with about 40 IoT devices
  • some ffmpeg instances
  • MariaDB
    initial loading of the dashboard really sucks (up to 10 seconds)

If someone need my flows or parts of it. feel free to ask. I will share. Its not just to show / fish for compliments.

Most switches (flows) work with Tasmota / WLED ...some are custom coded.
The flows can be copied over until your system blows up. Just need to change very minor things like mac address and rename of gui stuff.

very tiny and clear stuff (just 355 nodes per switch!) @Steve-Mcl like that:

Excellent work.

Did you remove the multiple debug nodes in the end? It may help speed up loading and reduce system resource consumption.

1 Like

Thx!
No I did not remove them. just disabled them. Are you sure that helps ? Can someone tell about that in detail ... just du make sure. @Steve-Mcl perhaps ?

For the flow you show there, removing the debug nodes would have minimal benefits. Even more so as they are mostly turned off.

Where this becomes an issue is where large payloads (like images/audio etc) are passed out of the node and because there is more than one wire, the msg is cloned (there is a blog post you can read up on the whys and hows). This cloning of large msgs can cause significant overheads. I dont see this from your screenshot.

2 Likes

I would use much more tabs. That makes your system more structured and easier to read.

3 Likes

@Steve-Mcl answered the question.

Not sure if lots of debug nodes will slow down the "deploy" each time.

For me, I would prefer to removing the debug node once the function is confirmed working.

Nope.

Personal preferences I think. Disabling them is good enough I think unless you have a truly humungous flow. It can be helpful to keep them in some cases for future rapid analysis and support.

2 Likes

Impressive. How were the green / red indicators developed?

1 Like

I dont know. I just use them :wink:
just search for node-red-contrib-ui-led

Very nice. How did you implement your scheduler (Zeitpläne)? Would you share your code?

thanks in advance
Bernhard

sure ...I used:
node-red-contrib-ui-time-scheduler

  1. install it (just search for it in User Settings -> Palette)
  2. import my part of the flow.
  3. edit / create the file path if needed (I used "logs" in Pi user file system)
[{"id":"4dfd6da534705b64","type":"debug","z":"db62c9336b830f8f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":490,"y":1300,"wires":[]},{"id":"d773732d4ebe8d46","type":"debug","z":"db62c9336b830f8f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":490,"y":1460,"wires":[]},{"id":"c4a49bb5e013ae0b","type":"file","z":"db62c9336b830f8f","name":"WriteFile","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":500,"y":1380,"wires":[[]]},{"id":"41e3aa63fdcf0adb","type":"inject","z":"db62c9336b830f8f","name":"FireAfterReboot","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"60","topic":"","payloadType":"date","x":240,"y":1280,"wires":[["6374458a6cf1c317"]]},{"id":"243c7efdac2c3338","type":"file in","z":"db62c9336b830f8f","name":"ReadFile","filename":"","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":260,"y":1420,"wires":[["9bed24a46bee371e"]]},{"id":"6374458a6cf1c317","type":"function","z":"db62c9336b830f8f","name":"setFilename","func":"let id = flow.get('SensorId')||\"empty\";\nid = replaceAll(id);\nmsg.filename = \"/home/pi/logs/\" + id + \"-Scheduler.txt\";\nmsg.name = msg.filename;\nreturn msg;\n\nfunction replaceAll(str)\n{\n    var i;\n    for (i = 0; i < 10; i++) \n    {\n      str = str.replace(':','');\n    }\n    return str;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":250,"y":1320,"wires":[["9bf335d095f7bd2a"]]},{"id":"78da14c4dbab171d","type":"function","z":"db62c9336b830f8f","name":"setFilename","func":"let id = flow.get('SensorId')||\"empty\";\nid = replaceAll(id);\nmsg.filename = \"/home/pi/logs/\" + id + \"-Scheduler.txt\";\nreturn msg;\n\nfunction replaceAll(str)\n{\n    var i;\n    for (i = 0; i < 10; i++) \n    {\n      str = str.replace(':','');\n    }\n    return str;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":1340,"wires":[["c4a49bb5e013ae0b"]]},{"id":"9bed24a46bee371e","type":"ui_time_scheduler","z":"db62c9336b830f8f","group":"d6e29734b58c22a6","name":"Feste Schaltzeiten","startDay":"1","refresh":60,"devices":["Außenstrahler - Licht"],"onlySendChange":false,"customPayload":false,"eventMode":true,"eventOptions":[{"label":"On","event":"true"},{"label":"Off","event":"false"}],"sendTopic":true,"lat":"","lon":"","outputs":2,"order":1,"width":0,"height":0,"x":230,"y":1460,"wires":[["78da14c4dbab171d","4dfd6da534705b64"],["d773732d4ebe8d46","2b0de87cf3bde7a4"]]},{"id":"9bf335d095f7bd2a","type":"fs-ops-access","z":"db62c9336b830f8f","name":"","path":"","pathType":"str","filename":"filename","filenameType":"msg","read":true,"write":true,"throwerror":false,"x":250,"y":1360,"wires":[["243c7efdac2c3338"],[]]},{"id":"2b0de87cf3bde7a4","type":"function","z":"db62c9336b830f8f","name":"setTriggerPriority","func":"let flowX = flow.get('SensorId')||\"empty\";\nif (flowX == \"empty\") return null;\nlet keyX = \"PrioritySchedulerTimer\";\nlet conf =  global.get('globalConfig');\nlet prio = conf[flowX][keyX];\nmsg.priority = prio;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":530,"y":1420,"wires":[["b341194dc043ef95"]]},{"id":"d6e29734b58c22a6","type":"ui_group","name":"Schreibtisch","tab":"88777a2f.801b68","order":24,"disp":true,"width":"6","collapse":true,"className":""},{"id":"88777a2f.801b68","type":"ui_tab","name":"Zeitschaltpläne","icon":"dashboard","order":9,"disabled":false,"hidden":false}]
2 Likes

Is it possible to download your complete code?
At the moment i use domoticz (free-ware home-automation) but want to change everything to nodered.
I didn't find complete flow example, that combines all, until i saw yours.

  • Do you use a database to store data (MariaDB), or write everything in .txt files, like the flow in message 16?
  • What do you store in a database table(id, status, time?)
  • What does you administation page, with the update mode?
  • Anwesenheitsemulation, that is a simulator, or are the sensors active between those time which are written there?
  • Do you have 1 flow with all nodes? Or multi flows to get to this design? When you use multi flows, how do you get the data from one to another? By MariaDB, by mqtt message or with context?

for the switch ? yes. but you will have to install missing some nodes the flow. I attach the tasmota version.
its a good starting point. moste of the screenshots come from this flow. you will have to make changes at about 5-6 points. mostly to set up the tasmota device / to the mqtt server.

because of performance reasons I dont store stuff which is not needed. MariaDB is only used for custom made rain catcher and solar. The .txt files does only store scheduler node stuff.

nothing but energy harvesting and rain fall.

the modes are for my self programmed ESP devices you can not use them if you dont build or steal mine :wink:

It simulates switch activity if no nobody is home. its like someone switches random the light between different times to prevent thieves from breaking into my house

I ve flows for every task and copy them over if e.g. I create a new switch. I ve about 50 flows many double or for custom hardware I made. so it does not make sense to copy everything to you. I think you should get the switch flow working. and then lets see how you can handle that before adding more.
Some flows are linked PIR sensor linked to trigger the switch flow. you have to link a PiR sensor you own. everything works with an MQTT broker what you should install at first time. Dont expect to get fast everything to work especially if you are at beginner level. Its work of many month to build my system like it is.

import the flows in the listed order:

Gateways to MQTT (not needed if you replace them / enable mqtt nodes in the switch flow & remove the link nodes)

[{"id":"19825338.f4685d","type":"tab","label":"MQTT & EspNow Gatewaymessages","disabled":false,"info":""},{"id":"3f3d3cd3.91e31c","type":"mqtt in","z":"19825338.f4685d","name":"/EspNowPub","topic":"/EspNowPub","qos":"1","datatype":"auto","broker":"f55c6c0d.194bb","nl":false,"rap":false,"inputs":0,"x":210,"y":240,"wires":[["aec4001e.d68ae8","6f56b2a5.f434ac"]]},{"id":"67b28272.45c37c","type":"mqtt out","z":"19825338.f4685d","name":"/EspNowSub","topic":"/EspNowSub","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f55c6c0d.194bb","x":810,"y":240,"wires":[]},{"id":"10892616.3a966a","type":"trigger","z":"19825338.f4685d","name":"DelayUpdateCommand","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"50","extend":false,"units":"ms","reset":"","bytopic":"all","outputs":1,"x":850,"y":200,"wires":[["e61a7c5c.92bcb8","67b28272.45c37c"]]},{"id":"e61a7c5c.92bcb8","type":"debug","z":"19825338.f4685d","name":"This is going to EspNow","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1150,"y":200,"wires":[]},{"id":"7020d5ac.219a0c","type":"inject","z":"19825338.f4685d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"/EspNowCmd","payload":"{\"Hello\":\"FromMqTT\"}","payloadType":"str","x":880,"y":160,"wires":[["10892616.3a966a"]]},{"id":"aec4001e.d68ae8","type":"debug","z":"19825338.f4685d","name":"This is incomming from EspNow","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":270,"y":200,"wires":[]},{"id":"6f56b2a5.f434ac","type":"link out","z":"19825338.f4685d","name":"/EspNowPub IN","mode":"link","links":["28585553867951f3","6212fb011298bd2d","a4491ca5.80b0f"],"x":345,"y":240,"wires":[]},{"id":"de320438422b0742","type":"comment","z":"19825338.f4685d","name":"ESP NOW","info":"","x":200,"y":140,"wires":[]},{"id":"43acd6231fec1229","type":"comment","z":"19825338.f4685d","name":"SensorTypA","info":"","x":210,"y":320,"wires":[]},{"id":"d60f1fc72013fa9d","type":"mqtt in","z":"19825338.f4685d","name":"","topic":"/SensorTypA","qos":"1","datatype":"utf8","broker":"f55c6c0d.194bb","nl":false,"rap":false,"inputs":0,"x":210,"y":380,"wires":[["1e7ae26a32af6a2f","eb4f5cae2d66128d"]]},{"id":"1e7ae26a32af6a2f","type":"link out","z":"19825338.f4685d","name":"MQTT /SensorTypA OUT","mode":"link","links":["26e249d7a55cead0","2f25f2dd07474b6a","68952b114cdc4b9f","8a63079245cd762f"],"x":345,"y":380,"wires":[]},{"id":"7b2521eaf7e4e48d","type":"mqtt out","z":"19825338.f4685d","name":"","topic":"/SensorCommandsA","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f55c6c0d.194bb","x":840,"y":380,"wires":[]},{"id":"dd1173f0c27c2001","type":"link in","z":"19825338.f4685d","name":"MQTT /SensorCommandsA IN","links":["2615977d3a3db859","4c92fdcd08910a5f","767b0558b2d60df9","af81d0be8f0c98ed"],"x":675,"y":380,"wires":[["7b2521eaf7e4e48d","9159b6dae4369bdd"]]},{"id":"15dfacdbbf61e91f","type":"mqtt in","z":"19825338.f4685d","name":"","topic":"/SensorTypB","qos":"1","datatype":"auto","broker":"f55c6c0d.194bb","nl":false,"rap":false,"inputs":0,"x":210,"y":520,"wires":[["09071b149514256e","9c243af1bcb36e79"]]},{"id":"b3edc97934078ed9","type":"comment","z":"19825338.f4685d","name":"SensorTypA","info":"","x":210,"y":460,"wires":[]},{"id":"09071b149514256e","type":"link out","z":"19825338.f4685d","name":"MQTT /SensorTypB OUT","mode":"link","links":["5d99bbab9dd5b04a","6f02831912da6b8e","9f76cec0e144435a","a48d7c7913b98db6","afdccfb62e9972a3","bd67feeab6cc826c","e1d1fc64b66a0221","e2e88a603f42eea9"],"x":345,"y":520,"wires":[]},{"id":"35ccfdecd4e6d9d5","type":"link in","z":"19825338.f4685d","name":"MQTT /SensorCommandsB IN","links":["bf2d328f39a3754d","8d0e1ec3fb82d33d","725b7074e6985f3f","ab7f112f1cfd46c4","29452717b68c8fe4","e47acc8b18cb17c5","dd64041000206e11","350ad266ff89caf2"],"x":675,"y":520,"wires":[["f5b12bee2b481169","19f9602e9323dedb"]]},{"id":"f5b12bee2b481169","type":"mqtt out","z":"19825338.f4685d","name":"SensorCommandsB","topic":"/SensorCommandsB","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f55c6c0d.194bb","x":840,"y":520,"wires":[]},{"id":"edf8b8fa1a4e5f89","type":"mqtt in","z":"19825338.f4685d","name":"","topic":"/SwitchTypA","qos":"1","datatype":"auto","broker":"f55c6c0d.194bb","nl":false,"rap":false,"inputs":0,"x":210,"y":660,"wires":[["84bf4175b4624266","c1dadd511e2d7bda"]]},{"id":"84bf4175b4624266","type":"link out","z":"19825338.f4685d","name":"MQTT /SwitchTypA OUT","mode":"link","links":["6c94703da56892bf","c80eaf44b8bd4370","7c06eacfc7ecb4b2","fbb38929800754f7","bf3585e7e01e0caf","15e815a5f4255e2a","e272de901414019b","1c3a989e7c18def1","47bd7679a571e9a9","6ce34eed321e99c4","f0b3d6cd0ae00271","b38c0b025e96df6a"],"x":345,"y":660,"wires":[]},{"id":"04301f44f10f4f01","type":"mqtt out","z":"19825338.f4685d","name":"SwitchCommandsA","topic":"/SwitchCommandsA","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f55c6c0d.194bb","x":830,"y":660,"wires":[]},{"id":"2f6b6b88d7b31720","type":"comment","z":"19825338.f4685d","name":"SwitchTypA","info":"","x":210,"y":600,"wires":[]},{"id":"3a449e718d4f8774","type":"link in","z":"19825338.f4685d","name":"MQTT /SwitchCommandsA IN","links":["2b28bc48f120a16f","be44ea4dea5f2ed7","f9a0d51f70071df0","2ac2f7ec4e7e7711","ed8132ae5271234c","4483d9c373a1dbd9","94f7e2839bbb3642","e17f99021bcb3939","64e1a9bd9389ae55","73b999cb89a8cf67","e75407e1de1baf13","6c6d83e0533225f0","ecc8e603fc487ce3","6f12ca0a7aa40985","b11ad815583eb91b","c0c313f60a3b3890","004662eea9598c80","895b798da0c6d64b","1cfc790244ac0be8","6daecb19207823b1","ded150e311704d7f","ef38630c778337ba"],"x":675,"y":660,"wires":[["04301f44f10f4f01","deead7144d0a9900"]]},{"id":"e7adf81be2b2da9f","type":"link in","z":"19825338.f4685d","name":"/EspNowSub OUT","links":["5687fbf8a142d29b","823ee9023dbdd8ee","2861ba3cff0f0f09"],"x":675,"y":240,"wires":[["67b28272.45c37c"]]},{"id":"87d8e9f42e6ffe17","type":"comment","z":"19825338.f4685d","name":"Tasmota","info":"","x":200,"y":760,"wires":[]},{"id":"78db6da18b9eccd7","type":"mqtt out","z":"19825338.f4685d","name":"mqtt (topic set by msg.topic)","topic":"","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f55c6c0d.194bb","x":860,"y":1040,"wires":[]},{"id":"1e7232f937d90dd4","type":"mqtt in","z":"19825338.f4685d","name":"","topic":"stat/#","qos":"1","datatype":"auto","broker":"f55c6c0d.194bb","nl":false,"rap":false,"inputs":0,"x":190,"y":820,"wires":[["eeb9cd8db5b77838","ce41e9d66218927c"]]},{"id":"6a4d70fd75d7da29","type":"mqtt in","z":"19825338.f4685d","name":"","topic":"tele/#","qos":"1","datatype":"auto","broker":"f55c6c0d.194bb","nl":false,"rap":false,"inputs":0,"x":190,"y":900,"wires":[["f4cc4a793584004d","9630d2ca5509b3f0"]]},{"id":"eeb9cd8db5b77838","type":"link out","z":"19825338.f4685d","name":"MQTT stat/# OUT","mode":"link","links":["998cf381e99ccb84","641f94f5b32b0347","e88197b53ff3293a","df6155317ebe1915","146c86b37455d6fd","bd936267aecb7f4a","400d632362f3fee3","b07e1c03b817961f","cd7ea6c184dafba7","3ab2bfdcd0b26291","fe7d59a378a61e3d"],"x":345,"y":820,"wires":[]},{"id":"f4cc4a793584004d","type":"link out","z":"19825338.f4685d","name":"MQTT /tele/# OUT","mode":"link","links":["998cf381e99ccb84","641f94f5b32b0347","e88197b53ff3293a","df6155317ebe1915","146c86b37455d6fd","bd936267aecb7f4a","400d632362f3fee3","b07e1c03b817961f","cd7ea6c184dafba7","3ab2bfdcd0b26291","fe7d59a378a61e3d"],"x":345,"y":900,"wires":[]},{"id":"c04638883a9e607b","type":"comment","z":"19825338.f4685d","name":"Custom","info":"","x":190,"y":980,"wires":[]},{"id":"d66d5825bc40516c","type":"link in","z":"19825338.f4685d","name":"MQTT NoTopic IN","links":["7215ba84374fb68f","89d12b5b5e22bb15","43372dcdc85e09e2","1ac0bb8478ea43d5","31e2966cdcd152ca","8a162a8ca77ebd08","76b7c8ddb36555d4","9f3859216530a395","a9575c492fc85ef2","606d970524fb33aa","86f16688a30fdd50","efe2e1393d4697e6","e5f756f44a28b9a2","1fc023fde578b661"],"x":675,"y":1040,"wires":[["78db6da18b9eccd7","ce1e6d160261f3e0"]]},{"id":"ce41e9d66218927c","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":860,"wires":[]},{"id":"9630d2ca5509b3f0","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":940,"wires":[]},{"id":"c1dadd511e2d7bda","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":720,"wires":[]},{"id":"9c243af1bcb36e79","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":580,"wires":[]},{"id":"eb4f5cae2d66128d","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":440,"wires":[]},{"id":"9159b6dae4369bdd","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":440,"wires":[]},{"id":"19f9602e9323dedb","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":580,"wires":[]},{"id":"deead7144d0a9900","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":720,"wires":[]},{"id":"ce1e6d160261f3e0","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":1100,"wires":[]},{"id":"189aa4a4d572cdd9","type":"inject","z":"19825338.f4685d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":1340,"wires":[["1d65cfb647cce860"]]},{"id":"703075d6505da00b","type":"debug","z":"19825338.f4685d","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":550,"y":1400,"wires":[]},{"id":"a2cd79334f6b8714","type":"mqtt in","z":"19825338.f4685d","name":"","topic":"test/qos","qos":"1","datatype":"auto","broker":"f55c6c0d.194bb","nl":false,"rap":true,"rh":0,"inputs":0,"x":390,"y":1400,"wires":[["703075d6505da00b"]]},{"id":"1d65cfb647cce860","type":"mqtt out","z":"19825338.f4685d","name":"","topic":"test/qos","qos":"1","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f55c6c0d.194bb","x":400,"y":1340,"wires":[]},{"id":"7edb41cbea9d11f9","type":"ui_spacer","z":"19825338.f4685d","name":"spacer","group":"62575f31e409f3f7","order":8,"width":"8","height":"1"},{"id":"f55c6c0d.194bb","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"3","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"Abbruch","willQos":"0","willRetain":"true","willPayload":"{\"Abbruch\":\"Abbruch\"}","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"62575f31e409f3f7","type":"ui_group","name":"Webcams Ansichten","tab":"9f7f7c23.5626d8","order":1,"disp":true,"width":"14","collapse":true,"className":""},{"id":"9f7f7c23.5626d8","type":"ui_tab","name":"Webcams","icon":"videocam","order":14,"disabled":false,"hidden":false}]

save & load config values:

[{"id":"66243691.8c8b","type":"tab","label":"SaveLoad globalConfig","disabled":false,"info":""},{"id":"db14c3b.19ae74","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":750,"y":400,"wires":[]},{"id":"1a9a1094.78c36f","type":"function","z":"66243691.8c8b","name":"setValueToGlobalConfig","func":"let flow = \"cleared_flow\";\nlet key = \"cleared_key\";\nlet value = \"â– â– â– â– \";\n\n//var myJSON2 = JSON.stringify(myObj2);\n\nvar config = global.get('globalConfig')||\"empty\";\nvar myJSON2 = JSON.stringify(config);\n\n//  console.log(myJSON2);\nlet ValueSetted = false;\nfor(var x in config)\n{\n  if (x == flow) \n  {\n    // flow gibts, also gucken obs key gibt:\n    let nestedObj = config[flow];\n    for(var y in nestedObj)\n    {\n        if(y == key)\n        {\n            // value updaten wenn vorhanden:\n            config[flow][key] = value;\n            ValueSetted = true;\n            break;\n        }\n    }\n    if(ValueSetted === false)\n    {\n        // key value einfĂĽgen, wenn nicht vorhanden:\n        config[flow][key] = value;\n        ValueSetted = true;\n        break;\n    }\n  } \n}\n// Value wurde nicht gesetzt / Flow nicht gefunden, also Flow neu einfĂĽgen:\nif(ValueSetted === false)\n{\n    let newNest = {[key]:value};\n    config[flow] = newNest;\n}\n\n//myJSON2 = JSON.stringify(config);\nglobal.set('globalConfig', config);\nconfig = global.get('globalConfig')||\"empty\";\nmsg.payload = config;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":400,"wires":[["db14c3b.19ae74"]]},{"id":"ec16a704.61fe18","type":"inject","z":"66243691.8c8b","name":"SetGlobalConfigEntry","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":260,"y":400,"wires":[["1a9a1094.78c36f"]]},{"id":"1866d3ce.c3a2c4","type":"inject","z":"66243691.8c8b","name":"LoadGlobalConfig","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payloadType":"date","x":250,"y":780,"wires":[["a847f085.add6c"]]},{"id":"ac3f6ad0.de133","type":"function","z":"66243691.8c8b","name":"setGlobalConfig","func":"let flow = \"cleared_flow\";\nlet key = \"cleared_key\";\nlet value = \"cleared_value\";\n\nlet myObj = {[key]:value};\nlet myObj2 = {[flow]:myObj};\n//var myJSON2 = JSON.stringify(myObj2);\n\n//let myObj2 = JSON.parse(myObj2);\n\n//msg.payload = myJSON2;\n\nglobal.set('globalConfig', myObj2);\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":820,"wires":[[]]},{"id":"8bae9434.930d2","type":"function","z":"66243691.8c8b","name":"setGlobalConfigToMem","func":"let file = msg.payload;\n\n// Wenns das config object nach laden immer noch nicht gibt neu erstellen:\nif (file === \"\" || file === null)\n{\n    // leer neu erstellen:\n    let flow = \"new_flow\";\n    let key = \"new_key\";\n    let value = \"new_value\";\n    \n    let myObj = {[key]:value};\n    let myObj2 = {[flow]:myObj};\n    let myJSON2 = JSON.stringify(myObj2);\n\n    global.set('globalConfig',myJSON2);\n    let config = global.get('globalConfig')||'{\"cleared_flow\":{\"cleared_key\":\"cleared_value\"}}';\n    let newPayload = {};    \n    newPayload.payload = config;\n    return newPayload;\n}\nelse\n{\n    // wenn nicht leer datei zu neuem json:\n    let myObj2 = JSON.parse(msg.payload);\n    global.set('globalConfig',myObj2);\n    let config = global.get('globalConfig')||'{\"cleared_flow\":{\"cleared_key\":\"cleared_value\"}}';\n    let newPayload = {};    \n    newPayload.payload = config;\n    return newPayload;\n}\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1170,"y":760,"wires":[["99265f7f.1b687"]]},{"id":"5730686e.36223","type":"file","z":"66243691.8c8b","name":"","filename":"/home/pi/logs/config.json","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"utf8","x":730,"y":620,"wires":[["fdc35a36.dc95d8"]]},{"id":"6585baac.43d5c4","type":"file in","z":"66243691.8c8b","name":"","filename":"/home/pi/logs/config.json","format":"utf8","chunk":false,"sendError":false,"encoding":"utf8","x":890,"y":760,"wires":[["d60147de.23c4a8","8bae9434.930d2"]]},{"id":"d60147de.23c4a8","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1110,"y":720,"wires":[]},{"id":"99265f7f.1b687","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1390,"y":760,"wires":[]},{"id":"f42d264c.c7e728","type":"inject","z":"66243691.8c8b","name":"SaveGlobalConfig","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":true,"onceDelay":"120","topic":"","payload":"","payloadType":"date","x":250,"y":620,"wires":[["9ab16515.579e6"]]},{"id":"9ab16515.579e6","type":"function","z":"66243691.8c8b","name":"setGlobalConfig","func":"//let config = global.get('globalConfig')||\"empty\";\n//let jsonGlobalConfig = JSON.stringify(config);\n//msg.payload = config;\n//return msg;\n\nlet config = global.get('globalConfig')||'{\"cleared_flow\":{\"cleared_key\":\"cleared_value\"}}';\nmsg.payload = config;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":620,"wires":[["5730686e.36223","d797c673.3ff428"]]},{"id":"fdc35a36.dc95d8","type":"debug","z":"66243691.8c8b","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":620,"wires":[]},{"id":"d797c673.3ff428","type":"debug","z":"66243691.8c8b","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":670,"y":660,"wires":[]},{"id":"ae012d7e.d3f6c","type":"inject","z":"66243691.8c8b","name":"ClearGlobalConfig","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":250,"y":940,"wires":[[]]},{"id":"1c4cca2f.0e1c46","type":"function","z":"66243691.8c8b","name":"clearGlobalConfig","func":"let flow = \"cleared_flow\";\nlet key = \"cleared_key\";\nlet value = \"cleared_value\";\n\nlet myObj = {[key]:value};\nlet myObj2 = {[flow]:myObj};\n//var myJSON2 = JSON.stringify(myObj2);\n\n//let myObj2 = JSON.parse(myObj2);\n\n//msg.payload = myJSON2;\n\nglobal.set('globalConfig', myObj2);\n\n//global.set('globalConfig', null);\nlet newPayload = {};    \nnewPayload.payload = myObj2;\nreturn newPayload;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":940,"wires":[["29486fb0.aa9d78"]]},{"id":"29486fb0.aa9d78","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":670,"y":940,"wires":[]},{"id":"3939d8fd.0d59d","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":750,"y":300,"wires":[]},{"id":"b6f21d61.be9bc","type":"function","z":"66243691.8c8b","name":"getValueFromGlobalConfig","func":"let flow = \"cleared_flo\";\nlet key = \"cleared_key\";\n\nlet value = \"\";\nvar config = global.get('globalConfig')||'{\"cleared_flow\":{\"cleared_key\":\"cleared_value\"}}';\nvar myJSON2 = JSON.stringify(config);\n\n//  console.log(myJSON2);\nfor(var x in config)\n{\n  if (x == flow) \n  {\n    // flow gibts, also gucken obs key gibt:\n    let nestedObj = config[flow];\n    for(var y in nestedObj)\n    {\n        if(y == key)\n        {\n            // value updaten wenn vorhanden:\n            value = config[flow][key];\n            break;\n        }\n    }\n    \n  } \n}\n// key gibts nicht:\n//if(value === null) return null\n\nlet newPayload = {};\nnewPayload.payload = value;\nmsg.payload = newPayload;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":300,"wires":[["3939d8fd.0d59d"]]},{"id":"fdb8e13f.031b3","type":"inject","z":"66243691.8c8b","name":"GetGlobalConfigEntry","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":260,"y":300,"wires":[["b6f21d61.be9bc"]]},{"id":"9771ec5a.5481c8","type":"comment","z":"66243691.8c8b","name":"Only for testing","info":"","x":230,"y":900,"wires":[]},{"id":"b9756029.50dad","type":"comment","z":"66243691.8c8b","name":"Once at system start","info":"","x":250,"y":740,"wires":[]},{"id":"6ff9efeb.542818","type":"comment","z":"66243691.8c8b","name":"Time based or event based saves:","info":"","x":300,"y":580,"wires":[]},{"id":"c1b09116.97d888","type":"comment","z":"66243691.8c8b","name":"Event if a setting has changed","info":"","x":280,"y":360,"wires":[]},{"id":"640b9f26.8cc7c","type":"comment","z":"66243691.8c8b","name":"Event if a setting is requested","info":"","x":280,"y":260,"wires":[]},{"id":"75953b81.dc5184","type":"inject","z":"66243691.8c8b","name":"ShowGlobalConfig","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":250,"y":980,"wires":[["e7e831af.60a0d"]]},{"id":"e7e831af.60a0d","type":"function","z":"66243691.8c8b","name":"showGlobalConfig","func":"let res = global.get('globalConfig');\nlet newPayload = {};  \nnewPayload = res;\nmsg.payload = newPayload;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":980,"wires":[["327e7a17.0d237e"]]},{"id":"327e7a17.0d237e","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":670,"y":980,"wires":[]},{"id":"a847f085.add6c","type":"fs-ops-access","z":"66243691.8c8b","name":"FileExists","path":"/home/pi/logs/","pathType":"str","filename":"config.json","filenameType":"str","read":true,"write":false,"throwerror":false,"x":660,"y":780,"wires":[["f35ebb1a.884e38","6585baac.43d5c4"],["9f1f4b88.ad8778","ac3f6ad0.de133"]]},{"id":"f35ebb1a.884e38","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":830,"y":720,"wires":[]},{"id":"9f1f4b88.ad8778","type":"debug","z":"66243691.8c8b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":830,"y":860,"wires":[]}]

sub-flow to save / restore values from config:

[{"id":"9df1c585.4b2b6","type":"subflow","name":"getValue from globalConfig","info":"","category":"","in":[{"x":380,"y":160,"wires":[{"id":"8c654eef.f6813"}]}],"out":[{"x":780,"y":160,"wires":[{"id":"8c654eef.f6813","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"6c357cd9.381074","type":"debug","z":"9df1c585.4b2b6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":810,"y":220,"wires":[]},{"id":"8c654eef.f6813","type":"function","z":"9df1c585.4b2b6","name":"getValueFromGlobalConfig","func":"let flow = msg.payload.flow;\nlet key = msg.payload.key;\nlet originalPayload = msg.payload;\n\nlet value = \"\";\nvar config = global.get('globalConfig')||'{\"cleared_flow\":{\"cleared_key\":\"cleared_value\"}}';\nvar myJSON2 = JSON.stringify(config);\n\n//  console.log(myJSON2);\nfor(var x in config)\n{\n  if (x == flow) \n  {\n    // flow gibts, also gucken obs key gibt:\n    let nestedObj = config[flow];\n    for(var y in nestedObj)\n    {\n        if(y == key)\n        {\n            // value updaten wenn vorhanden:\n            value = config[flow][key];\n            break;\n        }\n    }\n    \n  } \n}\n// key gibts nicht:\n//if(value === null) return null\n\nlet newPayload = {};\n//newPayload = value;\nnewPayload = originalPayload;\nnewPayload.value = value;\nmsg.payload = newPayload;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":160,"wires":[[]]},{"id":"c9d6e148.59e338","type":"inject","z":"9df1c585.4b2b6","name":"GetGlobalConfigEntry","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":220,"wires":[[]]},{"id":"67e94b20.88586c","type":"comment","z":"9df1c585.4b2b6","name":"Event if a setting is requested","info":"","x":340,"y":120,"wires":[]},{"id":"60481db9.c75664","type":"subflow","name":"storeValue to globalConfig","info":"","category":"","in":[{"x":380,"y":240,"wires":[{"id":"9c32755e.43e048"}]}],"out":[],"env":[]},{"id":"22f249bb.b029d6","type":"debug","z":"60481db9.c75664","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":790,"y":240,"wires":[]},{"id":"9c32755e.43e048","type":"function","z":"60481db9.c75664","name":"setValueToGlobalConfig","func":"let flow = msg.payload.flow;\nlet key = msg.payload.key;\nlet value = msg.payload.value;\n\n//var myJSON2 = JSON.stringify(myObj2);\n\nvar config = global.get('globalConfig')||\"empty\";\n//var myJSON2 = JSON.stringify(config);\n\n//  console.log(myJSON2);\nlet ValueSetted = false;\nfor(var x in config)\n{\n  if (x == flow) \n  {\n    // flow gibts, also gucken obs key gibt:\n    let nestedObj = config[flow];\n    for(var y in nestedObj)\n    {\n        if(y == key)\n        {\n            // value updaten wenn vorhanden:\n            config[flow][key] = value;\n            ValueSetted = true;\n            break;\n        }\n    }\n    if(ValueSetted === false)\n    {\n        // key value einfĂĽgen, wenn nicht vorhanden:\n        config[flow][key] = value;\n        ValueSetted = true;\n        break;\n    }\n  } \n}\n// Value wurde nicht gesetzt / Flow nicht gefunden, also Flow neu einfĂĽgen:\nif(ValueSetted === false)\n{\n    let newNest = {[key]:value};\n    config[flow] = newNest;\n}\n\n//myJSON2 = JSON.stringify(config);\nglobal.set('globalConfig', config);\nconfig = global.get('globalConfig')||\"empty\";\nmsg.payload = config;\nreturn msg;\n","outputs":1,"noerr":0,"x":550,"y":240,"wires":[[]]},{"id":"d9042393.b578d","type":"inject","z":"60481db9.c75664","name":"SetGlobalConfigEntry","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":300,"wires":[[]]},{"id":"b4b645a.aba9ab8","type":"comment","z":"60481db9.c75664","name":"Event if a setting has changed","info":"","x":320,"y":200,"wires":[]},{"id":"f54b48212b234935","type":"subflow:60481db9.c75664","z":"b4cbe90803d68a2d","name":"","x":1460,"y":1740,"wires":[]},{"id":"0d1d758de4e7b980","type":"subflow:9df1c585.4b2b6","z":"b4cbe90803d68a2d","name":"","env":[],"x":400,"y":1880,"wires":[["b55637a62a2ba4be"]]},{"id":"134c20a715754ea6","type":"subflow:60481db9.c75664","z":"b4cbe90803d68a2d","name":"","x":1460,"y":1880,"wires":[]}]

switch flow is to big to post .... link:
switch flow

The use of your code is for having a great starting point.
Your project is the first one i found which has everything in it.
Of course it needs to be modified, every house is different en everybody has different home-automation

You don't store switch states? (maybe this question is to early, still have to look at your flows, but will do that this evening).
If you deploy a nodered flow, then the states could be different, because they all switch off, but maybe the device is on. How to you keep everything in sync?

I don't know if i am a beginner or not. for sure i am not a expert, but have some experiance with nodered. To transfer everything to nodered, will for sure take a while. But your flows are a great start. My experiance: made a flow for tasmota sonoff zigbee to domoticz with a ui page. Made this to check my device and have a simple environment to set up the id's for the domoticz devices. This flow will be modified, to get the zigbee devices in your switch flow.
I don't use zigbee2mqtt which is also in nodered, because i need the sonoff zigbee wifi modules. I couldn't get the zigbee network working on different floors. Sometimes the devices on other floors got offline. The sonoff zigbee modules where the solution for me.

Sounds like a question for a separate thread in the Hardware category :slight_smile:

One of the nice things about Zigbee2MQTT is that it shows you a graph of all of your devices and how they interconnect across the Zigbee mesh. That lets you optimise where you put powered Zigbee devices which act as mesh hubs.