Where is JSON flows is stored exactly in an application fullstack?

Hello everyone, i'm newbie with Node-red. I'm developping an app mobile with Node-Red for backend and Flutter for frontend. So the frontend team have almost finished their job with Flutter, i'm bulding the back-end with Node-red but I have a lot of confusion. So my questions are:

  • Where is JSON flow is stored in an apllication? Is it in the server? Could you guys tell me exactly where it supposed to be?

  • How can I embed Node-red into the front-end (Flutter) which have been done?

This is very impotant to me. Thank you so much!

Tom

when you start node-red, the location of the flow file is displayed...

23 Apr 08:24:38 - [info] Flows file     : xxxxxx.json

And may be worth reading this there where there is some great work on flutter - Uibuilder: to subscribe or not to subscribe? - #15 by chrisn-au

1 Like

Thank you for your answer, I know these flows are stored in computer when i type commande "node-red" in my PowerShell.
But in a project with many others codes, in my case is for mobile app with a part of front-end (flutter) and a server, it can not be stored in my computer obviously so where my flow supposed to be?

As i know this is just a JSON file, it’s not executable. Do i need to install Node-red app in my SERVER with my flow inside of it? Could you explain me how it works?

@tom123

Happy to help if I can.

To be clear, I am just looking at this as proof of technology to see what an integration could look like. I am going to take it to the implantation of core dashboard nodes for my own use. I am getting reasonably close to having the flutter infrastructure bits done, so the extension to additional nodes should be pretty straight forward. Clearly happy for you to take any ideas.

So the architecture is as follows.

Core driver

  • I am very keen (for this implementation to keep the zero-config dashboard). That is use drag and drop to define the dashboard using existing UI widgets

Tointerface with the flows.json file I use the node red Admin API

To achieve this. In Node-Red

There is a flow that using the Admin API extracts UI elements and adds them to a structure that can be sent to the FE. This is executed on flow deploy

[{"id":"a1c66b31.1cb3b8","type":"http request","z":"232a5ba8.40f134","name":"flows","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://localhost:1880/flows","tls":"","persist":false,"proxy":"","authType":"","x":270,"y":740,"wires":[["a09ca52c.0afd78"]]},{"id":"45ecf60b.962e1","type":"inject","z":"232a5ba8.40f134","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":740,"wires":[["a1c66b31.1cb3b8"]]},{"id":"c4143161.475b58","type":"change","z":"232a5ba8.40f134","name":"","rules":[{"t":"set","p":"flows","pt":"global","to":"payload","tot":"msg"},{"t":"set","p":"control","pt":"flow","to":"control","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":740,"wires":[[]]},{"id":"a09ca52c.0afd78","type":"function","z":"232a5ba8.40f134","name":"Extract UI ftrom flow","func":"let flows = msg.payload\n\nlet tabs = flows.filter(elm => elm.type == \"ui_tab\" )\nlet uigroups = flows.filter(elm => elm.type.substring(0,8) == \"ui_group\" )\n\nlet uiTabs = []\n\nfor (let i =0; i < tabs.length; i++){\n    tab = tabs[i]\n    let elms = uigroups.filter(elm => elm.tab == tab.id)\n    elms = elms.sort((a, b) => a.order - b.order)\n    console.log(`elms ${elms.length}`)\n    let groups = []\n   \n    for (let j = 0; j < elms.length; j++){\n        group = elms[j];\n        let groupElms = flows.filter(elm => elm.group == group.id)\n        let cleansedElms = []\n      //  cleansedElms.push(groupElms);\n        for (let k =0; k < groupElms.length; k++){\n            elm = groupElms[k]\n            elm.width = parseInt(elm.width)\n            elm.height = parseInt(elm.height)\n            if (elm.height == 0) elm.height = 1;\n            if (elm.width == 0) elm.width = 1;\n         //   elm.height = elm.height == 0 ? 1 : elm.height\n            \n            delete elm.wires\n            cleansedElms.push(elm)\n        }\n        cleansedElms = cleansedElms.sort((a, b) => a.order - b.order)\n        groups.push({id : group.id, group_details : group , elements : cleansedElms})\n    }\n    uiTabs.push({id : tab.id, tab_details: tab, groups : groups})\n}\n\n\nlet control = {\n    type : \"control\",\n    scope : \"tab_build\",\n    tabs : uiTabs\n    \n} \n\nmsg.payload = flows\nmsg.control = control\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":740,"wires":[["c4143161.475b58"]]}]

This really just a filter reorganisation of the existing flows. It will over time confirm to an as of now unwritten specification that defines how a thirds party dashboard would talk to node red.

The Flutter app connects to NR via WS and on connect it is sent the flows

[{"id":"2d8ca97.efe01d6","type":"websocket in","z":"232a5ba8.40f134","name":"","server":"d39d1f66.9fff8","client":"","x":100,"y":600,"wires":[["fd863f08.2d7448"]]},{"id":"fd863f08.2d7448","type":"function","z":"232a5ba8.40f134","name":"Received","func":"let count = flow.get(\"count\") ? flow.get(\"count\")  : 0 ;\ncount +=1;\nnode.status({fill:\"green\",shape:\"ring\",text:count});\n\nflow.set(\"count\",count)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":260,"y":600,"wires":[["213e1f13.15c3c"]]},{"id":"2f53ef40.b1bda8","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":600,"wires":[]},{"id":"213e1f13.15c3c","type":"json","z":"232a5ba8.40f134","name":"","property":"payload","action":"","pretty":false,"x":410,"y":600,"wires":[["a281864.3f99978"]]},{"id":"a281864.3f99978","type":"switch","z":"232a5ba8.40f134","name":"Is it a connection","property":"payload.type","propertyType":"msg","rules":[{"t":"eq","v":"connected","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":590,"y":600,"wires":[["2f53ef40.b1bda8","168c20a.22557df"],["f9d5537e.f31498"]]},{"id":"f9d5537e.f31498","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":740,"y":660,"wires":[]},{"id":"d39d1f66.9fff8","type":"websocket-listener","z":"232a5ba8.40f134","path":"/ws/simple","wholemsg":"false"}]
[{"id":"c69f9376.aa5c58","type":"function","z":"232a5ba8.40f134","name":"Set up UI for client","func":"let flows = global.get(\"flows\")\nlet tabs = flows.filter(elm => elm.type == \"ui_tab\" )\nlet uigroups = flows.filter(elm => elm.type.substring(0,8) == \"ui_group\" )\n\nlet uiTabs = []\n\nfor (let i =0; i < tabs.length; i++){\n    tab = tabs[i]\n    let elms = uigroups.filter(elm => elm.tab == tab.id)\n    elms = elms.sort((a, b) => a.order - b.order)\n    console.log(`elms ${elms.length}`)\n    let groups = []\n   \n    for (let j = 0; j < elms.length; j++){\n        group = elms[j];\n        let groupElms = flows.filter(elm => elm.group == group.id)\n        let cleansedElms = []\n      //  cleansedElms.push(groupElms);\n        for (let k =0; k < groupElms.length; k++){\n            elm = groupElms[k]\n            elm.width = parseInt(elm.width)\n            elm.height = parseInt(elm.height)\n            if (elm.height == 0) elm.height = 1;\n            if (elm.width == 0) elm.width = 1;\n         //   elm.height = elm.height == 0 ? 1 : elm.height\n            \n            delete elm.wires\n            cleansedElms.push(elm)\n        }\n        cleansedElms = cleansedElms.sort((a, b) => a.order - b.order)\n        groups.push({id : group.id, group_details : group , elements : cleansedElms})\n    }\n    uiTabs.push({id : tab.id, tab_details: tab, groups : groups})\n}\n\n\nlet control = {\n    type : \"control\",\n    scope : \"tab_build\",\n    tabs : uiTabs\n    \n} \nmsg.payload = control\n\nmsg.control = control\n\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":180,"wires":[["fa062c22.e54ef8"]]},{"id":"c5bc2cd5.ab24f","type":"http response","z":"232a5ba8.40f134","name":"","x":550,"y":140,"wires":[]},{"id":"8dc46d35.335858","type":"http in","z":"232a5ba8.40f134","name":"","url":"/simple","method":"get","upload":false,"swaggerDoc":"","x":170,"y":140,"wires":[["70c4db30.6572f4"]]},{"id":"70c4db30.6572f4","type":"template","z":"232a5ba8.40f134","name":"Simple Web Page","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n    <head>\n    <title>Simple Live Display</title>\n    <script type=\"text/javascript\">\n        var ws;\n        var wsUri = \"ws:\";\n        var loc = window.location;\n        console.log(loc);\n        if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n        // This needs to point to the web socket in the Node-RED flow\n        // ... in this case it's ws/simple\n        wsUri += \"//\" + loc.host + loc.pathname.replace(\"simple\",\"ws/simple\");\n\n        function wsConnect() {\n            console.log(\"connect\",wsUri);\n            ws = new WebSocket(wsUri);\n            //var line = \"\";    // either uncomment this for a building list of messages\n            ws.onmessage = function(msg) {\n                var line = \"\";  // or uncomment this to overwrite the existing message\n                // parse the incoming message as a JSON object\n                var data = msg.data;\n                //console.log(data);\n                // build the output from the topic and payload parts of the object\n                line += \"<p>\"+data+\"</p>\";\n                // replace the messages div with the new \"line\"\n                document.getElementById('messages').innerHTML = line;\n                //ws.send(JSON.stringify({data:data}));\n            }\n            ws.onopen = function() {\n                // update the status div with the connection status\n                document.getElementById('status').innerHTML = \"connected\";\n                //ws.send(\"Open for data\");\n                console.log(\"connected\");\n            }\n            ws.onclose = function() {\n                // update the status div with the connection status\n                document.getElementById('status').innerHTML = \"not connected\";\n                // in case of lost connection tries to reconnect every 3 secs\n                setTimeout(wsConnect,3000);\n            }\n        }\n        \n        function doit(m) {\n            if (ws) { ws.send(m); }\n        }\n    </script>\n    </head>\n    <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n        <font face=\"Arial\">\n        <h1>Simple Live Display</h1>\n        <div id=\"messages\"></div>\n        <button type=\"button\" onclick='doit(\"click\");'>Click to send message</button>\n        <hr/>\n        <div id=\"status\">unknown</div>\n        </font>\n    </body>\n</html>\n","output":"str","x":370,"y":140,"wires":[["c5bc2cd5.ab24f"]]},{"id":"fa062c22.e54ef8","type":"json","z":"232a5ba8.40f134","name":"Convert to a string","property":"payload","action":"","pretty":true,"x":590,"y":180,"wires":[["980c8bc3.e5ef3","af6f7581.3c5ee8"]]},{"id":"6706233.268e8dc","type":"change","z":"232a5ba8.40f134","name":"Set flows","rules":[{"t":"set","p":"payload","pt":"msg","to":"flows","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":220,"y":180,"wires":[["c69f9376.aa5c58"]]},{"id":"eb00ba02.4ff2c","type":"websocket out","z":"232a5ba8.40f134","name":"","server":"d39d1f66.9fff8","client":"","x":720,"y":280,"wires":[]},{"id":"a2091d00.24d178","type":"link in","z":"232a5ba8.40f134","name":"Ws send ","links":["980c8bc3.e5ef3","1a69f297.2dee65"],"x":595,"y":280,"wires":[["eb00ba02.4ff2c"]]},{"id":"980c8bc3.e5ef3","type":"link out","z":"232a5ba8.40f134","name":"","links":["a2091d00.24d178"],"x":715,"y":180,"wires":[]},{"id":"de664f22.dc9c6","type":"link in","z":"232a5ba8.40f134","name":"","links":["168c20a.22557df"],"x":115,"y":180,"wires":[["6706233.268e8dc"]]},{"id":"af6f7581.3c5ee8","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":730,"y":80,"wires":[]},{"id":"d39d1f66.9fff8","type":"websocket-listener","z":"232a5ba8.40f134","path":"/ws/simple","wholemsg":"false"}]

If you deploy. the full flow and have an instance of node-red running on 2880 (not 1880)
and the gods are looking upon you kindly, and you visit from a chrome browser from a machine where you can http://localhost:2880 to get to node-red it may just work. But there are absolutely promises. This is a POT exercise very much in evolution

https://chrisn-au.github.io/#/
[{"id":"9fdc928d.df1278","type":"subflow","name":"UIBuilder","info":"# The name of this subflow must be UNIQUE.\n\ne.g\n\nTEXT_FIELD_1","category":"","in":[{"x":50,"y":30,"wires":[{"id":"a7e2bc7b.9ddc78"}]}],"out":[{"x":440,"y":40,"wires":[{"id":"a7e2bc7b.9ddc78","port":0}]},{"x":660,"y":140,"wires":[{"id":"ba91f5c2.fdfa9","port":0}]},{"x":440,"y":200,"wires":[{"id":"a7e2bc7b.9ddc78","port":1}]}],"env":[{"name":"TYPE","type":"str","value":"TestBuilder"}],"color":"#DDAA99","inputLabels":["Up stream flow and Testbuilder"],"outputLabels":["To UI Element","To Testbuilder","To UI Element out"]},{"id":"a7e2bc7b.9ddc78","type":"switch","z":"9fdc928d.df1278","name":"FINDME","property":"testbuilder","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":130,"y":160,"wires":[["4d6a222b.9ee56c"],[]]},{"id":"ba91f5c2.fdfa9","type":"function","z":"9fdc928d.df1278","name":"","func":"id = node.id\n\nlet name = flow.get(\"NAME\")\nif (!name) name = env.get(\"NAME\");\nif (name) flow.set(\"NAME\",name)\n\nelse (name = \"GENERIC\")\n\nlet flows = global.get(\"flows\")\nlet local = flows.filter(elm => elm.id == id )\nlet targets = flows.filter(elm => elm.type.substring(0,8) == \"subflow:\")\nlet current = null\nfor(let i = 0; i < targets.length; i++){\n    env = targets[i].env\n    c = flows.filter(elm => elm.value == name)\n    if (c) { current = targets[i]; break}\n}\nif (current.wires[0][0])\n    msg.destination = current.wires[0][0]\nmsg.payload = targets\nmsg.local = local\nmsg.id = id\nmsg.name = name\n\nmsg.payload = Math.random(5)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":500,"y":140,"wires":[[]]},{"id":"4d6a222b.9ee56c","type":"change","z":"9fdc928d.df1278","name":"","rules":[{"t":"set","p":"NAME","pt":"flow","to":"NAME","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":140,"wires":[["ba91f5c2.fdfa9"]]},{"id":"a1c66b31.1cb3b8","type":"http request","z":"232a5ba8.40f134","name":"flows","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://localhost:1880/flows","tls":"","persist":false,"proxy":"","authType":"","x":270,"y":740,"wires":[["c4143161.475b58"]]},{"id":"c69f9376.aa5c58","type":"function","z":"232a5ba8.40f134","name":"Set up UI for client","func":"let flows = global.get(\"flows\")\nlet tabs = flows.filter(elm => elm.type == \"ui_tab\" )\nlet uigroups = flows.filter(elm => elm.type.substring(0,8) == \"ui_group\" )\n\nlet uiTabs = []\n\nfor (let i =0; i < tabs.length; i++){\n    tab = tabs[i]\n    let elms = uigroups.filter(elm => elm.tab == tab.id)\n    elms = elms.sort((a, b) => a.order - b.order)\n    console.log(`elms ${elms.length}`)\n    let groups = []\n   \n    for (let j = 0; j < elms.length; j++){\n        group = elms[j];\n        let groupElms = flows.filter(elm => elm.group == group.id)\n        let cleansedElms = []\n      //  cleansedElms.push(groupElms);\n        for (let k =0; k < groupElms.length; k++){\n            elm = groupElms[k]\n            elm.width = parseInt(elm.width)\n            elm.height = parseInt(elm.height)\n            if (elm.height == 0) elm.height = 1;\n            if (elm.width == 0) elm.width = 1;\n         //   elm.height = elm.height == 0 ? 1 : elm.height\n            \n            delete elm.wires\n            cleansedElms.push(elm)\n        }\n        cleansedElms = cleansedElms.sort((a, b) => a.order - b.order)\n        groups.push({id : group.id, group_details : group , elements : cleansedElms})\n    }\n    uiTabs.push({id : tab.id, tab_details: tab, groups : groups})\n}\n\n\nlet control = {\n    type : \"control\",\n    scope : \"tab_build\",\n    tabs : uiTabs\n    \n} \nmsg.payload = control\n\nmsg.control = control\n\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":180,"wires":[["fa062c22.e54ef8"]]},{"id":"c5bc2cd5.ab24f","type":"http response","z":"232a5ba8.40f134","name":"","x":550,"y":140,"wires":[]},{"id":"8dc46d35.335858","type":"http in","z":"232a5ba8.40f134","name":"","url":"/simple","method":"get","upload":false,"swaggerDoc":"","x":170,"y":140,"wires":[["70c4db30.6572f4"]]},{"id":"70c4db30.6572f4","type":"template","z":"232a5ba8.40f134","name":"Simple Web Page","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n    <head>\n    <title>Simple Live Display</title>\n    <script type=\"text/javascript\">\n        var ws;\n        var wsUri = \"ws:\";\n        var loc = window.location;\n        console.log(loc);\n        if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n        // This needs to point to the web socket in the Node-RED flow\n        // ... in this case it's ws/simple\n        wsUri += \"//\" + loc.host + loc.pathname.replace(\"simple\",\"ws/simple\");\n\n        function wsConnect() {\n            console.log(\"connect\",wsUri);\n            ws = new WebSocket(wsUri);\n            //var line = \"\";    // either uncomment this for a building list of messages\n            ws.onmessage = function(msg) {\n                var line = \"\";  // or uncomment this to overwrite the existing message\n                // parse the incoming message as a JSON object\n                var data = msg.data;\n                //console.log(data);\n                // build the output from the topic and payload parts of the object\n                line += \"<p>\"+data+\"</p>\";\n                // replace the messages div with the new \"line\"\n                document.getElementById('messages').innerHTML = line;\n                //ws.send(JSON.stringify({data:data}));\n            }\n            ws.onopen = function() {\n                // update the status div with the connection status\n                document.getElementById('status').innerHTML = \"connected\";\n                //ws.send(\"Open for data\");\n                console.log(\"connected\");\n            }\n            ws.onclose = function() {\n                // update the status div with the connection status\n                document.getElementById('status').innerHTML = \"not connected\";\n                // in case of lost connection tries to reconnect every 3 secs\n                setTimeout(wsConnect,3000);\n            }\n        }\n        \n        function doit(m) {\n            if (ws) { ws.send(m); }\n        }\n    </script>\n    </head>\n    <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n        <font face=\"Arial\">\n        <h1>Simple Live Display</h1>\n        <div id=\"messages\"></div>\n        <button type=\"button\" onclick='doit(\"click\");'>Click to send message</button>\n        <hr/>\n        <div id=\"status\">unknown</div>\n        </font>\n    </body>\n</html>\n","output":"str","x":370,"y":140,"wires":[["c5bc2cd5.ab24f"]]},{"id":"fa062c22.e54ef8","type":"json","z":"232a5ba8.40f134","name":"Convert to a string","property":"payload","action":"","pretty":true,"x":590,"y":180,"wires":[["980c8bc3.e5ef3","af6f7581.3c5ee8"]]},{"id":"45ecf60b.962e1","type":"inject","z":"232a5ba8.40f134","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":740,"wires":[["a1c66b31.1cb3b8"]]},{"id":"504938b6.95778","type":"ui_text","z":"232a5ba8.40f134","group":"2b0407f5.237138","order":2,"width":0,"height":0,"name":"A text value","label":"A new value","format":"{{msg.payload}}","layout":"row-spread","x":1130,"y":220,"wires":[]},{"id":"d8701e43.d457a8","type":"ui_button","z":"232a5ba8.40f134","name":"","group":"9e27eb4c.1219e8","order":0,"width":"2","height":"2","passthru":false,"label":"Button third group","tooltip":"","color":"","bgcolor":"blue","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":1310,"y":140,"wires":[[]]},{"id":"74e0a720.618a18","type":"ui_text","z":"232a5ba8.40f134","group":"6973e9a4.e091b8","order":1,"width":0,"height":0,"name":"","label":"Text 2 fourth group","format":"{{msg.payload}}","layout":"row-spread","x":1310,"y":260,"wires":[]},{"id":"74b78832.4a4888","type":"ui_text","z":"232a5ba8.40f134","group":"6973e9a4.e091b8","order":0,"width":0,"height":0,"name":"","label":"Text 1 fourth group","format":"{{msg.payload}}","layout":"row-spread","x":1310,"y":200,"wires":[]},{"id":"ff4ba8eb.7de138","type":"ui_button","z":"232a5ba8.40f134","name":"","group":"98092a36.c0eef","order":1,"width":0,"height":0,"passthru":false,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":1120,"y":140,"wires":[[]]},{"id":"7ff6d2c2.abe8c4","type":"ui_button","z":"232a5ba8.40f134","name":"","group":"2b0407f5.237138","order":1,"width":"6","height":"3","passthru":false,"label":"button","tooltip":"","color":"","bgcolor":"blue","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":910,"y":160,"wires":[[]]},{"id":"e8b9afd8.2cef28","type":"ui_button","z":"232a5ba8.40f134","name":"","group":"2b0407f5.237138","order":3,"width":"1","height":"1","passthru":false,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":910,"y":220,"wires":[[]]},{"id":"dc45a8c6.8b89c8","type":"ui_switch","z":"232a5ba8.40f134","name":"","label":"test switch","tooltip":"","group":"2b0407f5.237138","order":5,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"x":930,"y":260,"wires":[[]]},{"id":"2ef3111c.a068d6","type":"ui_text","z":"232a5ba8.40f134","group":"98092a36.c0eef","order":3,"width":0,"height":0,"name":"","label":"A ID","format":"{{msg.payload}}","layout":"row-spread","x":470,"y":400,"wires":[]},{"id":"197f6da1.4d0b9a","type":"inject","z":"232a5ba8.40f134","name":"FINDME","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":460,"wires":[["edee399c.7d0c9"]]},{"id":"76daedd0.91978c","type":"function","z":"232a5ba8.40f134","name":"No subflow","func":"id = node.id\n\nlet flows = global.get(\"flows\")\nlet local = flows.filter(elm => elm.id == id )\nlet targets = flows.filter(elm => elm.type.substring(0,8) == \"subflow:\")\n\nmsg.payload = targets\nmsg.local = local\nmsg.id = id\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":290,"y":820,"wires":[["89b53ca.799bdc"]]},{"id":"89b53ca.799bdc","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":450,"y":820,"wires":[]},{"id":"441f6a5f.20d80c","type":"inject","z":"232a5ba8.40f134","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":820,"wires":[["76daedd0.91978c"]]},{"id":"6c9f154b.9b4854","type":"ui_button","z":"232a5ba8.40f134","name":"FINDME","group":"2b0407f5.237138","order":4,"width":"4","height":"2","passthru":false,"label":"First group","tooltip":"","color":"","bgcolor":"green","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":1000,"y":900,"wires":[["be956e6c.50c498"]]},{"id":"293285e1.79d962","type":"inject","z":"232a5ba8.40f134","name":"FINDME","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":620,"y":940,"wires":[["3316959a.c4c74a"]]},{"id":"3316959a.c4c74a","type":"subflow:9fdc928d.df1278","z":"232a5ba8.40f134","name":"FINDME","env":[{"name":"NAME","value":"TEST","type":"str"}],"x":800,"y":940,"wires":[["6c9f154b.9b4854"],["a5ea1d83.5a03d8"],[]]},{"id":"be956e6c.50c498","type":"debug","z":"232a5ba8.40f134","name":"FINDME","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1190,"y":940,"wires":[]},{"id":"a5ea1d83.5a03d8","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":990,"y":960,"wires":[]},{"id":"edee399c.7d0c9","type":"function","z":"232a5ba8.40f134","name":"Next","func":"let id = node.id\n\nlet flows = global.get(\"flows\")\nlet [local] = flows.filter(elm => elm.id == id)\n\nif (!local){\n    return [msg,null,null]\n}\n\ndownstream = local.wires[0]\n\nuis = flows.filter(elm => elm.type.substring(0,3) == \"ui_\")\nif (!uis){\n    return [msg,null,null]\n}\n\nuisOut  = []\nfor (let i =0; i < downstream.length; i++){\n    exists = uis.filter(elm => elm.id == downstream[i])\n    \n    if (!exists || exists.length == 0) continue\n    let out =  {\n    \"type\": \"data\",\n    \"id\": exists[0].id,\n    \"data\": Math.random(5).toFixed(5)}\n    let msgOut = {\n        payload : out\n    }\n    uisOut.push(msgOut)\n}\n\nreturn [msg,uisOut];\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":270,"y":460,"wires":[["2ef3111c.a068d6","dbc90153.284d48","df77fa36.1d142"],["1a69f297.2dee65"]]},{"id":"dbc90153.284d48","type":"ui_text","z":"232a5ba8.40f134","group":"9e27eb4c.1219e8","order":1,"width":0,"height":0,"name":"","label":"A second test on three ","format":"{{msg.payload}}","layout":"row-spread","x":520,"y":440,"wires":[]},{"id":"df77fa36.1d142","type":"ui_gauge","z":"232a5ba8.40f134","name":"","group":"98092a36.c0eef","order":4,"width":0,"height":0,"gtype":"gage","title":"gauge","label":"units","format":"{{value}}","min":0,"max":10,"colors":["#00b500","#e6e600","#ca3838"],"seg1":"6","seg2":"8","x":470,"y":500,"wires":[]},{"id":"a85e4105.470f9","type":"ui_date_picker","z":"232a5ba8.40f134","name":"","label":"date","group":"2b0407f5.237138","order":6,"width":0,"height":0,"passthru":true,"topic":"topic","topicType":"msg","x":910,"y":320,"wires":[[]]},{"id":"68a7e660.22a6b8","type":"ui_colour_picker","z":"232a5ba8.40f134","name":"","label":"","group":"98092a36.c0eef","format":"hex","outformat":"string","showSwatch":true,"showPicker":false,"showValue":false,"showHue":false,"showAlpha":false,"showLightness":true,"square":"false","dynOutput":"false","order":2,"width":0,"height":0,"passthru":true,"topic":"topic","topicType":"msg","x":1130,"y":280,"wires":[[]]},{"id":"6706233.268e8dc","type":"change","z":"232a5ba8.40f134","name":"Set flows","rules":[{"t":"set","p":"payload","pt":"msg","to":"flows","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":220,"y":180,"wires":[["c69f9376.aa5c58"]]},{"id":"c4143161.475b58","type":"change","z":"232a5ba8.40f134","name":"","rules":[{"t":"set","p":"flows","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":740,"wires":[[]]},{"id":"eb00ba02.4ff2c","type":"websocket out","z":"232a5ba8.40f134","name":"","server":"d39d1f66.9fff8","client":"","x":720,"y":280,"wires":[]},{"id":"a2091d00.24d178","type":"link in","z":"232a5ba8.40f134","name":"Ws send ","links":["980c8bc3.e5ef3","1a69f297.2dee65"],"x":595,"y":280,"wires":[["eb00ba02.4ff2c"]]},{"id":"980c8bc3.e5ef3","type":"link out","z":"232a5ba8.40f134","name":"","links":["a2091d00.24d178"],"x":715,"y":180,"wires":[]},{"id":"2d8ca97.efe01d6","type":"websocket in","z":"232a5ba8.40f134","name":"","server":"d39d1f66.9fff8","client":"","x":100,"y":600,"wires":[["fd863f08.2d7448"]]},{"id":"fd863f08.2d7448","type":"function","z":"232a5ba8.40f134","name":"Received","func":"let count = flow.get(\"count\") ? flow.get(\"count\")  : 0 ;\ncount +=1;\nnode.status({fill:\"green\",shape:\"ring\",text:count});\n\nflow.set(\"count\",count)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":260,"y":600,"wires":[["213e1f13.15c3c"]]},{"id":"2f53ef40.b1bda8","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":600,"wires":[]},{"id":"1a69f297.2dee65","type":"link out","z":"232a5ba8.40f134","name":"","links":["a2091d00.24d178"],"x":445,"y":560,"wires":[]},{"id":"227cbbbf.a490a4","type":"ui_text","z":"232a5ba8.40f134","group":"98092a36.c0eef","order":4,"width":0,"height":0,"name":"","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":1120,"y":340,"wires":[]},{"id":"168c20a.22557df","type":"link out","z":"232a5ba8.40f134","name":"Connected event","links":["de664f22.dc9c6"],"x":715,"y":540,"wires":[]},{"id":"de664f22.dc9c6","type":"link in","z":"232a5ba8.40f134","name":"","links":["168c20a.22557df"],"x":115,"y":180,"wires":[["6706233.268e8dc"]]},{"id":"213e1f13.15c3c","type":"json","z":"232a5ba8.40f134","name":"","property":"payload","action":"","pretty":false,"x":410,"y":600,"wires":[["a281864.3f99978"]]},{"id":"a281864.3f99978","type":"switch","z":"232a5ba8.40f134","name":"Is it a connection","property":"payload.type","propertyType":"msg","rules":[{"t":"eq","v":"connected","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":590,"y":600,"wires":[["2f53ef40.b1bda8","168c20a.22557df"],["f9d5537e.f31498"]]},{"id":"f9d5537e.f31498","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":740,"y":660,"wires":[]},{"id":"af6f7581.3c5ee8","type":"debug","z":"232a5ba8.40f134","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":730,"y":80,"wires":[]},{"id":"2b0407f5.237138","type":"ui_group","name":"First group","tab":"1e24552a.a5441b","order":1,"disp":true,"width":"6","collapse":false},{"id":"9e27eb4c.1219e8","type":"ui_group","name":"Third group","tab":"1e24552a.a5441b","order":3,"disp":true,"width":"6","collapse":false},{"id":"6973e9a4.e091b8","type":"ui_group","name":"Fourth group","tab":"1e24552a.a5441b","order":4,"disp":true,"width":"6","collapse":false},{"id":"98092a36.c0eef","type":"ui_group","name":"Second group","tab":"1e24552a.a5441b","order":2,"disp":true,"width":"6","collapse":false},{"id":"d39d1f66.9fff8","type":"websocket-listener","z":"232a5ba8.40f134","path":"/ws/simple","wholemsg":"false"},{"id":"1e24552a.a5441b","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

I am sorry I can give very little support on this if it does not work. I will be over the next week or so uploading the flutter POT to Github. I will send you the link.

BTW here is a copy of the wip dart file which implements that JSON format sent from node-red

node-red-control.dart.txt (11.5 KB)

Hope this helps

1 Like

thank you, just 1 node that i do not understand is [ws] /ws/simple what is /ws/simple? Is it the local file in your computer where you keep all of your flows?

Tom /ws/simple is the web sock node. The flutter app connects on ws://127.0.0.1:2880/ws/simple to the node red instance to communicated

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