Ideas for a "database-like" structure in global context

So ... finally here you are.

  • the data structure is defined by the topics: nameInStore.object[s].property seperated by dots.
  • nameInStore will be used as global.get("nameInStore","file") You have to edit this in ALL function nodes if you have a different store provider.
  • object[s] the object in witch the list[] should be stored
  • property name of the property or keyword to trigger a function (uiDropdown, uiAdd, uiDelete). The property name must be provided to store the name of a configuration.
    image
  • make sure that image is unchecked for ALL ui_Nodes EXCEPT the dropdown list
  • all ui_Nodes must provide the topic described above. You can use the most resend ui_List , this should have the possibility to enter a topic.
  • edit the addNew function node and add your default values
  • edit the switch node to match your topics in the ui_Nodes
    image
  • all single msg.payload input / output can be wired directly between the switch node and the save Data function node
  • for other nodes you have to add special nodes like the save List function node in the second example
  • last but not least enter the initial topic in the inject node
    image
    And this is the result in your store:

Version with switches:

[{"id":"e73adecd.24ffa","type":"ui_text_input","z":"897fdb2a.109f68","name":"name","label":"","tooltip":"","group":"d11141a.b59afc","order":5,"width":6,"height":1,"passthru":false,"mode":"text","delay":"0","topic":"mySettings.heating.test.name","x":590,"y":280,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"74ea0435.e9838c","type":"ui_button","z":"897fdb2a.109f68","name":"uiDelete","group":"d11141a.b59afc","order":3,"width":1,"height":1,"passthru":false,"label":"","tooltip":"","color":"","bgcolor":"","icon":"delete","payload":"Do you really like to delete this entry?","payloadType":"str","topic":"mySettings.heating.test.uiDelete","x":600,"y":220,"wires":[["843a51.ab4095b"]]},{"id":"372cbb4a.c123c4","type":"function","z":"897fdb2a.109f68","name":"delete period","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getEntry(msg.topic);\nif (!currentProperty) {\n    node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not found\"});\n    return;\n}\nvar name=currentProperty.name;\n\ntry {\n    if (currentObject.deleteEntry(msg.topic)) {\n        node.status({fill:\"green\",shape:\"dot\",text:name+\" deleted\"});\n    } else {\n        node.status({fill:\"green\",shape:\"dot\",text:name+\" NOT deleted\"});\n    }\n    return msg;\n} catch (err) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"ups, something gone wrong.\"});\n    console.log(err);\n} ","outputs":1,"noerr":0,"x":890,"y":220,"wires":[["d3df79d6.ec2598"]]},{"id":"bd2033fe.103aa","type":"ui_date_picker","z":"897fdb2a.109f68","name":"start","label":"","group":"d11141a.b59afc","order":7,"width":6,"height":1,"passthru":false,"topic":"mySettings.heating.test.start","x":590,"y":320,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"4dbfe990.188838","type":"ui_date_picker","z":"897fdb2a.109f68","name":"end","label":"","group":"d11141a.b59afc","order":9,"width":6,"height":1,"passthru":false,"topic":"mySettings.heating.test.end","x":590,"y":360,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"3159de8.1169f22","type":"ui_text","z":"897fdb2a.109f68","group":"d11141a.b59afc","order":4,"width":2,"height":1,"name":"Name:","label":"Name:","format":"{{msg.payload}}","layout":"row-spread","x":110,"y":280,"wires":[]},{"id":"5073b43e.635a4c","type":"ui_text","z":"897fdb2a.109f68","group":"d11141a.b59afc","order":6,"width":2,"height":1,"name":"Start:","label":"Begin:","format":"{{msg.payload}}","layout":"row-spread","x":110,"y":340,"wires":[]},{"id":"fd9ab15d.fbc79","type":"ui_text","z":"897fdb2a.109f68","group":"d11141a.b59afc","order":8,"width":2,"height":1,"name":"End:","label":"End:","format":"{{msg.payload}}","layout":"row-spread","x":110,"y":400,"wires":[]},{"id":"d793942.135c968","type":"ui_dropdown","z":"897fdb2a.109f68","name":"uiDropdown","label":"","tooltip":"","place":"select period","group":"d11141a.b59afc","order":1,"width":6,"height":1,"passthru":true,"options":[],"payload":"","topic":"mySettings.heating.test.uiDropdown","x":610,"y":100,"wires":[["7dbcf8cd.631618"]]},{"id":"79445713.d60a98","type":"function","z":"897fdb2a.109f68","name":"update","func":"var msgDropdown={};\nvar msgName={};\nvar msgList={};\nvar msgParameter=[];\n\nvar topicParts=msg.topic.split('.');\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) return;\nvar keyword = topicParts.pop();\nvar propertyTopic = msg.topic.slice(0,msg.topic.lastIndexOf('.'));\nvar currentProperty=currentObject.getObject(msg.topic);\nif (!currentProperty) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n    return;\n}\n\nmsgDropdown.topic=msg.topic;\n\ntry {\n    // fill an array for all parameters in list if exiting\n    if (currentProperty.list) { \n        for (var item in currentProperty.list[currentProperty.uiPointer]) {\n            if (!item.startsWith('ui')) \n                msgParameter.push({\"payload\":currentProperty.list[currentProperty.uiPointer][item], \"topic\": propertyTopic+'.'+item});\n        }\n    }    \n    switch (keyword) {\n        case \"uiDropdown\":\n            node.status({fill:\"green\",shape:\"dot\",text:\"Dropdown updated!\"});\n            return [null,msgParameter]; // update all parameters\n        case \"uiAdd\":\n            msgDropdown.payload=currentProperty.uiPointer;\n            node.status({fill:\"green\",shape:\"dot\",text:\"new entry nr=\"+currentProperty.uiPointer});\n            return [msgDropdown,null]; // update only dropdown, parametes will follw next call\n        case \"uiDelete\":\n            msgDropdown.payload=\"init\";\n            node.status({fill:\"green\",shape:\"dot\",text:\"entry deleted\"});\n            return [msgDropdown,null]; // update only dropdown, parametes will follw next call\n        case \"name\":\n            msgDropdown.payload=currentProperty.uiPointer;\n            node.status({fill:\"green\",shape:\"dot\",text:\"entry renamed!\"});\n            return [msgDropdown,null]; // update only dropdown\n    }\n    \n    node.status({fill:\"gray\",shape:\"dot\",text:msg.topic+\"=\"+msg.payload});\n    return null;\n} catch (err) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong. (\"+keyword+\")\"});\n    console.log(err);\n} ","outputs":2,"noerr":0,"x":190,"y":200,"wires":[["f022e935.c6ab48"],["7c078fcf.9a8e9"]]},{"id":"b51dc782.8c09d8","type":"link out","z":"897fdb2a.109f68","name":"updatePeriod","links":["bc9c5ee1.ceb48"],"x":995,"y":280,"wires":[]},{"id":"bc9c5ee1.ceb48","type":"link in","z":"897fdb2a.109f68","name":"updatePeriod","links":["b51dc782.8c09d8","750a4ef9.a29c9","480be8a7.ca3858","d3df79d6.ec2598","54d64382.c8d62c"],"x":95,"y":200,"wires":[["79445713.d60a98"]]},{"id":"750a4ef9.a29c9","type":"link out","z":"897fdb2a.109f68","name":"updatePeriod","links":["bc9c5ee1.ceb48"],"x":995,"y":100,"wires":[]},{"id":"1ff3f5ad.ab0eca","type":"function","z":"897fdb2a.109f68","name":"save Data","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getEntry(msg.topic);\nif (!currentProperty) {\n    node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not found\"});\n    return;\n}\nvar propertyName=msg.topic.slice(msg.topic.lastIndexOf('.')+1);\n\ntry {\n    // make shure your topic is set correctly in your ui nodes(s): objectName.propertyName\n    currentProperty[propertyName]=msg.payload;\n\n    node.status({fill:\"green\",shape:\"dot\",text:propertyName+\"=\"+msg.payload+\"!\"});\n    return msg;\n} catch (err) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong.\"});\n    console.log(err);\n} ","outputs":1,"noerr":0,"x":880,"y":280,"wires":[["b51dc782.8c09d8"]],"icon":"font-awesome/fa-database"},{"id":"f022e935.c6ab48","type":"function","z":"897fdb2a.109f68","name":"fill dropdown","func":"var topicParts=msg.topic.split('.');\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) return;\nvar keyword = topicParts.pop();\nvar currentProperty=currentObject.getObject(msg.topic);\nif (!currentProperty) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n    return;\n}\n\n//try {\n    console.log(currentProperty.list!==undefined)\n    if (currentProperty.list!==undefined) {\n        msg.options=[];\n        var listEntry={};\n        currentProperty.list.forEach(function(item,index){\n            listEntry={};\n            listEntry[item.name]=String(index);\n            msg.options.push(listEntry);\n        })\n        msg.options.sort();\n     \n        if (!currentProperty.list[currentProperty.uiPointer]) {\n            if (currentProperty.list.length>0){\n                currentProperty.uiPointer=0; // reset to first\n                msg.payload=currentProperty.uiPointer;\n            } else { // no list existing\n                delete msg.payload;\n            }\n        } else msg.payload=currentProperty.uiPointer;\n            \n        node.status({fill:\"green\",shape:\"dot\",text:\"done!\"});\n    } else {\n        node.status({fill:\"yellow\",shape:\"dot\",text:\"object.list empty\"});\n    }\n    return msg;\n\n/*} catch (err) {\n    node.status({fill:\"yellow\",shape:\"dot\",text:\"No list entry\"});\n    return msg;\n} */","outputs":1,"noerr":0,"x":410,"y":100,"wires":[["d793942.135c968"]]},{"id":"5ecf0362.de014c","type":"inject","z":"897fdb2a.109f68","name":"initalize","topic":"mySettings.heating.test.null","payload":"uiInit","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":100,"y":100,"wires":[["b984a3e8.bf33"]]},{"id":"7dbcf8cd.631618","type":"function","z":"897fdb2a.109f68","name":"set editPeriod","func":"var topicParts=msg.topic.split('.');\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getObject(msg.topic);\nif (!currentProperty) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n    return;\n}\n\ntry {\n    currentProperty.uiPointer=Number(msg.payload);\n    node.status({fill:\"green\",shape:\"dot\",text:msg.payload+\"!\"});\n    return msg;\n} catch (err) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong.\"});\n    console.log(err);\n} ","outputs":1,"noerr":0,"x":840,"y":100,"wires":[["750a4ef9.a29c9"]]},{"id":"d3df79d6.ec2598","type":"link out","z":"897fdb2a.109f68","name":"updatePeriod","links":["bc9c5ee1.ceb48"],"x":995,"y":220,"wires":[]},{"id":"5a8215ea.6905cc","type":"ui_button","z":"897fdb2a.109f68","name":"uiAdd","group":"d11141a.b59afc","order":2,"width":1,"height":1,"passthru":false,"label":"","tooltip":"","color":"","bgcolor":"","icon":"playlist_add","payload":"unnamed","payloadType":"str","topic":"mySettings.heating.test.uiAdd","x":590,"y":160,"wires":[["cf5aca8c.406948"]]},{"id":"cf5aca8c.406948","type":"function","z":"897fdb2a.109f68","name":"add new","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.newObject(msg.topic);\nif (!currentProperty) {\n    node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not created\"});\n    return;\n}\n\n// move Pointer to new entry\ncurrentProperty.uiPointer=currentProperty.list.length-1\nvar newItem = currentProperty.list[currentProperty.uiPointer];\n\n// initialize property object\nnewItem.name=msg.payload;\n\n//---------------------------------------------------------------\n// fill in defaults here! \n//---------------------------------------------------------------\nnewItem.start=new Date();\nnewItem.end=new Date();\nnewItem.monday=false;\nnewItem.tuesday=false;\nnewItem.wednesday=false;\nnewItem.thursday=false;\nnewItem.friday=false;\nnewItem.saturday=false;\nnewItem.sunday=false;\n\n\n// send output\nnode.status({fill:\"green\",shape:\"dot\",text:msg.payload+\" saved\"});\nreturn msg;","outputs":1,"noerr":0,"x":880,"y":160,"wires":[["54d64382.c8d62c"]],"icon":"node-red/file.png"},{"id":"54d64382.c8d62c","type":"link out","z":"897fdb2a.109f68","name":"updatePeriod","links":["bc9c5ee1.ceb48"],"x":995,"y":160,"wires":[]},{"id":"7c078fcf.9a8e9","type":"switch","z":"897fdb2a.109f68","name":"topic","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"mySettings.heating.test.name","vt":"str"},{"t":"eq","v":"mySettings.heating.test.start","vt":"str"},{"t":"eq","v":"mySettings.heating.test.end","vt":"str"},{"t":"eq","v":"mySettings.heating.test.monday","vt":"str"},{"t":"eq","v":"mySettings.heating.test.tuesday","vt":"str"},{"t":"eq","v":"mySettings.heating.test.wednesday","vt":"str"},{"t":"eq","v":"mySettings.heating.test.thursday","vt":"str"},{"t":"eq","v":"mySettings.heating.test.friday","vt":"str"},{"t":"eq","v":"mySettings.heating.test.saturday","vt":"str"},{"t":"eq","v":"mySettings.heating.test.sunday","vt":"str"}],"checkall":"true","repair":false,"outputs":10,"x":370,"y":340,"wires":[["e73adecd.24ffa"],["bd2033fe.103aa"],["4dbfe990.188838"],["61878250.8fc43c"],["2148eae6.2c8076"],["9572f07e.81162"],["9b06565e.dd2798"],["515536be.f1d9c8"],["4d24d50f.a27ccc"],["4ba796b0.614ec8"]]},{"id":"843a51.ab4095b","type":"ui_toast","z":"897fdb2a.109f68","position":"dialog","displayTime":"3","highlight":"","sendall":false,"outputs":1,"ok":"OK","cancel":"","topic":"","name":"Delete?","x":740,"y":220,"wires":[["372cbb4a.c123c4"]]},{"id":"b984a3e8.bf33","type":"function","z":"897fdb2a.109f68","name":"initialize","func":"if (!msg.payload) return;\n\nvar topicParts=\"\";\n\ntry {\n    topicParts=msg.topic.split('.');\n} catch (err) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n}\nvar keyword = topicParts.pop();\n\nif (topicParts.length<3) {\n    node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n    return;\n}\n\n\n// get or initalize root for global store\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) {\n    currentObject={};\n    global.set(topicParts[0],currentObject,\"file\")\n}\n\n// function to create object for specific topic\ncurrentObject.newObject = function(topic) {\n    var topicParts = topic.split('.');\n    var keyword=topicParts.pop();\n    if (keyword!='uiAdd') return Null\n    if (topicParts.length<2) return null;\n    var objectPtr=global.get(topicParts[0],\"file\");\n    for (var i=1; i<topicParts.length; i++) {\n        if (!objectPtr[topicParts[i]]) return null; // object not found\n        objectPtr=objectPtr[topicParts[i]];\n    }\n    if (!objectPtr.list) objectPtr.list=[]; // initialize list if not existing\n    objectPtr.list.push({}); // add new object into list\n    return objectPtr;\n};\n\n// function to get object for specific topic\ncurrentObject.getObject = function(topic) {\n    var topicParts = topic.split('.');\n    if (topicParts.length<2) return null;\n    var objectPtr=global.get(topicParts[0],\"file\");\n    for (var i=1; i<topicParts.length-1; i++) { // ignore the last identifier\n        if (!objectPtr[topicParts[i]]) return null; // object not found\n        objectPtr=objectPtr[topicParts[i]];\n    }    \n    return objectPtr;\n};\n\n// function to get object for current entry out of list\ncurrentObject.getEntry = function(topic) {\n    objectPtr=this.getObject(topic);\n    if (objectPtr.uiPointer<objectPtr.list.length){\n        return objectPtr.list[objectPtr.uiPointer];\n    }\n    return null;\n};\n\n// function to delete current entry out of list\ncurrentObject.deleteEntry = function(topic) {\n    objectPtr=this.getObject(topic);\n    if (objectPtr.uiPointer<objectPtr.list.length){\n        var returnObj= objectPtr.list.splice(objectPtr.uiPointer,1);\n        if (returnObj) objectPtr.uiPointer=0;\n        return returnObj;\n    }\n    return null;\n};\n\n// (re)build Object Tree\nvar objectRoot= currentObject;\nfor (i=1; i<topicParts.length; i++) {\n  if (!currentObject[topicParts[i]]) currentObject[topicParts[i]]={};\n  currentObject=currentObject[topicParts[i]];\n}\nif (currentObject.uiPointer===undefined) currentObject.uiPointer=0;\nnode.status({fill:\"green\",shape:\"dot\",text:\"done!\"});\nreturn msg;\n","outputs":1,"noerr":0,"x":240,"y":100,"wires":[["f022e935.c6ab48"]]},{"id":"61878250.8fc43c","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Monday","tooltip":"","group":"d11141a.b59afc","order":10,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.monday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":600,"y":400,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"2148eae6.2c8076","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Tuesday","tooltip":"","group":"d11141a.b59afc","order":11,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.tuesday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":600,"y":460,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"9572f07e.81162","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Wednesday","tooltip":"","group":"d11141a.b59afc","order":12,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.wednesday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":610,"y":520,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"9b06565e.dd2798","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Thursday","tooltip":"","group":"d11141a.b59afc","order":13,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.thursday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":600,"y":580,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"515536be.f1d9c8","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Friday","tooltip":"","group":"d11141a.b59afc","order":14,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.friday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":590,"y":640,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"4d24d50f.a27ccc","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Saturday","tooltip":"","group":"d11141a.b59afc","order":15,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.saturday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":600,"y":700,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"4ba796b0.614ec8","type":"ui_switch","z":"897fdb2a.109f68","name":"","label":"Sunday","tooltip":"","group":"d11141a.b59afc","order":16,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"mySettings.heating.test.sunday","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":600,"y":760,"wires":[["1ff3f5ad.ab0eca"]]},{"id":"d11141a.b59afc","type":"ui_group","z":"","name":"Test Period","tab":"450f9708.9afe08","disp":true,"width":"8","collapse":false},{"id":"450f9708.9afe08","type":"ui_tab","z":"","name":"ui_Test","icon":"dashboard","disabled":false,"hidden":false}]

image

ui_list version in next post

3 Likes