Where does node red store flow.set data?

Trying to troubleshoot a problem and I can't find anything that tells me where in a Pi system that the file is that stores the data when you do a flow.set command. Someone please help.
Thanks

flow.set.data is another term for context.

Depending on the settings - don't ask me - they are either stored in memory or in a file.

Memory means it is volatile to reboots and won't survive.
File means it can survive reboots but is more I/O intensive.

I've set settings.js to
ContextStorage: {
default: {
module:"localfilesystem"
},
},
but I'm looking for where the file is stored

The default is a bunch of cryptically named json files below ~/.node-red/context.
eg

pi@ZeroTwoPink:~/.node-red $ find context -ls
   267160      4 drwxr-xr-x  10 pi       pi           4096 Aug 13 22:18 context
   272060      4 drwxr-xr-x   2 pi       pi           4096 Aug 23 23:27 context/aa0a868df2ab245a
   263452      4 -rw-r--r--   1 pi       pi             19 Aug 23 23:27 context/aa0a868df2ab245a/77eca9bb2b4b07a5.json
   263450      4 -rw-r--r--   1 pi       pi             19 Aug 23 23:27 context/aa0a868df2ab245a/8469a1aec341cbbe.json
   271927      4 drwxr-xr-x   2 pi       pi           4096 Aug 23 23:27 context/3fd2634d3eb8f47a
   263457      4 -rw-r--r--   1 pi       pi             22 Aug 23 23:27 context/3fd2634d3eb8f47a/flow.json
   272058      4 drwxr-xr-x   2 pi       pi           4096 Aug 23 23:23 context/52d3a9a7a5712824
   263447      4 -rw-r--r--   1 pi       pi            189 Aug 23 23:23 context/52d3a9a7a5712824/flow.json
   399809      4 drwxr-xr-x   2 pi       pi           4096 Aug 23 23:23 context/global
   399811      4 -rw-r--r--   1 pi       pi           1094 Aug 23 23:23 context/global/global.json
   272236      4 drwxr-xr-x   2 pi       pi           4096 Jul  3 13:47 context/f19ed86818b2c31d
   272057      4 drwxr-xr-x   2 pi       pi           4096 Aug 23 23:23 context/699e0a72d49c76f3
   263454      4 -rw-r--r--   1 pi       pi             80 Aug 23 23:23 context/699e0a72d49c76f3/02b7e893a6230852.json
   263455      4 -rw-r--r--   1 pi       pi             80 Aug 23 23:23 context/699e0a72d49c76f3/70ef4ccdaa6ac4b7.json
   263451      4 -rw-r--r--   1 pi       pi             86 Aug 23 23:23 context/699e0a72d49c76f3/432c6119c3e95d36.json
   268777      4 -rw-r--r--   1 pi       pi             22 Aug 13 22:01 context/699e0a72d49c76f3/fc552e50154e6e8b.json
   263453      4 -rw-r--r--   1 pi       pi             86 Aug 23 23:23 context/699e0a72d49c76f3/9c1a7a927b8af746.json
   263449      4 -rw-r--r--   1 pi       pi            639 Aug 23 23:23 context/699e0a72d49c76f3/flow.json
   272059      4 drwxr-xr-x   2 pi       pi           4096 Aug 23 23:23 context/43b59e5a75cfcb1b
   263448      4 -rw-r--r--   1 pi       pi           3748 Aug 23 23:23 context/43b59e5a75cfcb1b/flow.json
   269156      4 drwxr-xr-x   2 pi       pi           4096 Jun  9 17:27 context/a36444dbe01769cb
   272089     24 -rw-r--r--   1 pi       pi          20800 Jun  9 17:25 context/a36444dbe01769cb/flow.json

That's what I thought but I'd thought I'd ask. If my system doesn't have the /context sub-dir I assume that's why my flow.set is not working correctly.

1 Like

It creates the directory automatically, after a delay (30s)?

So if you don't have that directory there's something wrong.

What NR version do you have?

Pi4 running nodejs 18, node red 3.0..2, I have just reinstalled node red and down graded from nodejs 20 to 18 and it still doesn't work.
[edit]
no error messages and any install

If I make ~/.node-red/context root and read-only and up the logging level to debug I do see an error message:

23 Aug 23:48:16 - [info] Stopping flows
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : b946eb07.fa1b98
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : a2a74143.03d2d
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 820b503366768e45
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 3fd2634d3eb8f47a
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 40d22656b0e9256d
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 548bfd7e27826d88
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 880331c83e3989d5
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 1ff7a51a41da7b57
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 52d3a9a7a5712824
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 43b59e5a75cfcb1b
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 1ca0aa7a1aebf715
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : db04fd79f3a93d19
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 8a1997dbadd616a7
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 7c2531c9428b61e9
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : fb74b6954e19413f
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : aa0a868df2ab245a
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : ce2c31fd397862f4
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 950c560f3bd27e74
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : 699e0a72d49c76f3
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : a3c3807e16ca19c8
23 Aug 23:48:16 - [debug] red/nodes/flows.stop : stopping flow : global
23 Aug 23:48:16 - [info] Stopped flows
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope global
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope 3fd2634d3eb8f47a
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope 52d3a9a7a5712824
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope 43b59e5a75cfcb1b
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope 699e0a72d49c76f3
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope 8469a1aec341cbbe:aa0a868df2ab245a
23 Aug 23:48:16 - [debug] Flushing localfilesystem context scope 77eca9bb2b4b07a5:aa0a868df2ab245a
23 Aug 23:48:16 - [error] Error writing context: Error: EACCES: permission denied, mkdir '/home/pi/.node-red/context/global'


My guess is at some point you ran something as root and now have mixed permissions.

In short, don't run the install script, npm or node-red as root.

A clean solution is to delete the .node-red folder and install using the installer script - don't use root.

Not sure who you are talking to, haven't run anything as root

Ah, I mistook that log for yours. Apologies.

Can you show us an example of the code you are using?

Also post your start up log.

the flow

[{"id":"392c1bb3c1c96f96","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"5afda673dba62107","type":"ui_template","z":"392c1bb3c1c96f96","group":"9c90a075584ede2b","name":"GhostThermostat","order":1,"width":0,"height":0,"format":"<style>\n    @import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');\n    \n    svg {\n        transition: all .6s cubic-bezier(0.175, 0.885, 0.32, 1.2);\n    }\n\n    stop {\n        transition: all .5s;\n    }\n    \n\t{{'#GhostThermostat' + $id}} .led {\n    \t-webkit-transition: all 0.5s;\n    \ttransition: all 0.5s;\n    \tfill: url({{'#GhostThermostat' + $id + 'ledColor'}});\n    }\n    \n    {{'#GhostThermostat' + $id}} .fa-text {\n       font-family: FontAwesome !important; \n    }\n    {{'#GhostThermostat' + $id}} .dial {\n        -webkit-user-select: none;\n        -moz-user-select: none;\n        -ms-user-select: none;\n        user-select: none;\n    }\n    {{'#GhostThermostat' + $id}} .qGradient {\n       fill : url({{'#GhostThermostat' + $id + 'qGradient'}});\n    }\n    {{'#GhostThermostat' + $id}} .qGradientT {\n        fill : url({{'#GhostThermostat' + $id + 'qGradientT'}});\n    }\n    {{'#GhostThermostat' + $id}} .eGradient {\n        fill : url({{'#GhostThermostat' + $id + 'eGradient'}});\n    }\n    {{'#GhostThermostat' + $id}} .lbl {\n        font-family: 'Roboto', sans-serif;\n        text-anchor: middle;\n        fill : #ffffff;\n        clip-path: url({{'#GhostThermostat' + $id + 'qClip'}});\n    }\n    {{'#GhostThermostat' + $id}} .lblDial {\n        fill: #dddddd;\n    }\n    \n    {{'#GhostThermostat' + $id}} .lblAmbient {\n        font-weight: 400;\n        clip-path: url({{'#GhostThermostat' + $id + 'qClip'}});\n    }\n    \n    {{'#GhostThermostat' + $id}} .lblAmbient tspan {\n        font-weight: 400;\n    }\n    \n    {{'#GhostThermostat' + $id}} .lblTarget {\n        font-weight: 400;\n        fill: orange;\n    }\n    \n    {{'#GhostThermostat' + $id}} .lblTarget tspan {\n        font-weight: 400;\n        fill: orange;\n        clip-path: url({{'#GhostThermostat' + $id + 'qClip'}});\n    }    \n    \n    {{'#GhostThermostat' + $id}} .nodisplay {\n        display: none !important;\n    }\n    \n    {{'#GhostThermostat' + $id}} .icon {\n        font-family: FontAwesome !important;\n    }\n    \n    {{'#GhostThermostat' + $id}} .animate {\n        transition: all 0.5s;\n    }\n\n</style>\n<div id=\"{{'GhostThermostat' + $id}}\"></div> \n<script>\nvar mousedownID = -1;\nvar ghostThermostatDial = (function() {\n    console.log(\"START\");\n\n    function createSVGElement(tag, attributes, appendTo) {\n        var element = document.createElementNS('http://www.w3.org/2000/svg', tag);\n        attr(element, attributes);\n        if (appendTo) {\n            appendTo.appendChild(element);\n        }\n        return element;\n    }\n\n    function attr(element, attrs) {\n        for (var i in attrs) {\n            element.setAttribute(i, attrs[i]);\n        }\n    }\n\n    function setClass(el, className, state) {\n        el.classList[state ? 'add' : 'remove'](className);\n    }\n\n    return function(targetElement, options) {\n        console.log(\"RET FUN\");\n        var self = this;\n\n        /*\n         * Options\n         */\n        options = options || {};\n        options = {\n            diameter: options.diameter || 400,\n            mintemp: options.mintemp || 10, // Minimum value for target temperature\n            maxtemp: options.maxtemp || 30, // Maximum value for target temperature\n            ledColors: {\n                'off': 'rgb(143,141,141)',\n                'heating': 'rgb(255,128,0)',\n                'cooling': 'rgb(81,170,214)'\n            }, //Led Ring Colors\n            labels: {\n                ambient: \"AMBIENT\",\n                set: \"SET\",\n                mode: \"MODE\",\n                minus: \"-\",\n                plus: \"+\",\n                left: \"<\",\n                right: \">\"\n            },\n            onChangeState: options.onChangeState || function() {} // Function called when  switch state change\n        };\n\n        /*\n         * Properties\n         */\n        var properties = {\n            radius: options.diameter / 2,\n            modes: [{\n                    label: \"heating\",\n                    icon: \"\\uf06d\",\n                    color: \"orange\"\n                }, {\n                    label: 'cooling',\n                    icon: \"\\uf2dc\",\n                    color: \"rgb(81,170,214)\"\n                }, {\n                    label: \"off\",\n                    icon: \"\\uf011\",\n                    color: \"rgb(230,0,0)\"\n                }\n                /*, {\n\t\t\t\tlabel: 'away',\n\t\t\t\ticon: \"\\uf1ce\",\n\t\t\t\tcolor: \"gray\"\n\t\t\t} */\n            ],\n            modeNames: [\"heating\", \"cooling\", \"off\"],\n            swtitchStates: [\"heating\", \"cooling\", \"off\"]\n        };\n\n        /*\n         * Object state\n         */\n        var state = {\n            target_temperature: options.mintemp,\n            ambient_temperature: options.maxtemp,\n            mode: properties.modes.indexOf(properties.modes[0]),\n            switch_state: 'off',\n            away: false\n        };\n\n        /*\n         * Property getter / setters\n         */\n        Object.defineProperty(this, 'target_temperature', {\n            get: function() {\n                return state.target_temperature;\n            },\n            set: function(val) {\n                state.target_temperature = rangedTemperature(+val);\n                //render()\n            }\n        });\n\n        Object.defineProperty(this, 'ambient_temperature', {\n            get: function() {\n                return state.ambient_temperature;\n            },\n            set: function(val) {\n                state.ambient_temperature = +val;\n                render();\n            }\n        });\n\n        Object.defineProperty(this, 'mode_name', {\n            get: function() {\n                return properties.modeNames[state.mode];\n            },\n            set: function(val) {\n                if (properties.modeNames.indexOf(val) >= 0) {\n                    state.mode = properties.modeNames.indexOf(val);\n                    //render();\n                }\n            }\n        });\n\n        Object.defineProperty(this, 'switch_state', {\n            get: function() {\n                return state.switch_state;\n            },\n            set: function(val) {\n                if (properties.swtitchStates.indexOf(val) >= 0) {\n                    state.switch_state = val;\n                    //render();\n                }\n            }\n        });\n\n\n        function str2bool(strvalue) {\n            return (strvalue && typeof strvalue == 'string') ? (strvalue.toLowerCase() == 'true') : (strvalue == true);\n        }\n\n        Object.defineProperty(this, 'away', {\n            get: function() {\n                return state.away;\n            },\n            set: function(val) {\n                state.away = !!str2bool(val);\n                //render();\n            }\n        });\n\n\n        /*\n         * SVG\n         */\n        var svg = createSVGElement('svg', {\n            width: '100%', //options.diameter+'px',\n            height: '100%', //options.diameter+'px',\n            viewBox: '0 0 ' + options.diameter + ' ' + options.diameter,\n            class: 'dial'\n        }, targetElement);\n\n        // DEFS \n        var defs = createSVGElement('defs', null, svg);\n\n        var qgradient = createSVGElement('linearGradient', {\n            'id': targetElement.getAttribute('id') + 'qGradient',\n            gradientTransform: 'rotate(65)'\n        }, defs);\n        var stop = createSVGElement('stop', {\n            'offset': '50%',\n            'stop-color': 'rgb(86,89,94)'\n        }, qgradient);\n        var stop = createSVGElement('stop', {\n            'offset': '65%',\n            'stop-color': 'rgb(30,30,30)'\n        }, qgradient);\n\n        var qGradientT = createSVGElement('linearGradient', {\n            'id': targetElement.getAttribute('id') + 'qGradientT',\n            gradientTransform: 'rotate(65)'\n        }, defs);\n        var stop = createSVGElement('stop', {\n            'offset': '55%',\n            'stop-color': '#3b3e43',\n            'stop-opacity': '1'\n        }, qGradientT);\n        var stop = createSVGElement('stop', {\n            'offset': '90%',\n            'stop-color': 'rgb(0,0,0)',\n            'stop-opacity': '1'\n        }, qGradientT);\n\n        var clipPath = createSVGElement('clipPath', {\n            'id': targetElement.getAttribute('id') + 'qClip',\n        }, defs);\n        var circle = createSVGElement('circle', {\n            cx: properties.radius,\n            cy: properties.radius,\n            r: properties.radius - 25\n        }, clipPath);\n\n\n        var ledRingGradient = createSVGElement('radialGradient', {\n            'id': targetElement.getAttribute('id') + 'ledColor',\n            'cx': \"50%\",\n            'cy': \"50%\",\n            'r': \"95%\",\n            'fx': \"50%\",\n            'fy': \"50%\"\n        }, defs);\n        var ledRingGradientColorIn = createSVGElement('stop', {\n            'offset': '45%',\n            'stop-color': 'rgb(255,0,130)',\n            'stop-opacity': '1'\n        }, ledRingGradient);\n        var ledRingGradientColorOut = createSVGElement('stop', {\n            'offset': '65%',\n            'stop-color': 'rgb(0,0,0)',\n            'stop-opacity': '1'\n        }, ledRingGradient);\n\n        var egradient = createSVGElement('linearGradient', {\n            'id': targetElement.getAttribute('id') + 'eGradient',\n            gradientTransform: 'rotate(55)'\n        }, defs);\n        var stop = createSVGElement('stop', {\n            'offset': '55%',\n            'stop-color': '#888888',\n            'stop-opacity': '1'\n        }, egradient);\n        var stop = createSVGElement('stop', {\n            'offset': '95%',\n            'stop-color': '#333333',\n            'stop-opacity': '1'\n        }, egradient);\n\n        // DIAL\n        var circle = createSVGElement('circle', {\n            cx: properties.radius,\n            cy: properties.radius,\n            r: properties.radius,\n            class: 'eGradient'\n        }, svg);\n        var ledRing = createSVGElement('circle', {\n            cx: properties.radius,\n            cy: properties.radius,\n            r: properties.radius - 3,\n            'stroke': 'black',\n            'stroke-width': '1',\n            class: 'led'\n        }, svg);\n        var circle = createSVGElement('circle', {\n            cx: properties.radius,\n            cy: properties.radius,\n            r: properties.radius - 20,\n            class: 'qGradient'\n        }, svg);\n        var circle = createSVGElement('circle', {\n            cx: properties.radius,\n            cy: properties.radius,\n            r: properties.radius - 25,\n            class: 'qGradient'\n        }, svg);\n        var lblMain = createSVGElement('text', {\n            x: properties.radius,\n            y: 70,\n            class: 'lbl lblDial'\n        }, svg);\n        var lblMainText = document.createTextNode(options.labels.ambient);\n        lblMain.appendChild(lblMainText);\n\n        var lblAmbient = createSVGElement('text', {\n            x: properties.radius,\n            y: 210,\n            'font-size': '160',\n            class: 'lbl lblAmbient'\n        }, svg);\n        var lblAmbientText = document.createTextNode('21');\n        lblAmbient.appendChild(lblAmbientText);\n        var lblAmbientDec = createSVGElement('tspan', {\n            'font-size': '60',\n        }, lblAmbient);\n        var lblAmbientDecText = document.createTextNode('.5');\n        lblAmbientDec.appendChild(lblAmbientDecText);\n\n        var line = createSVGElement('line', {\n            x1: 55,\n            y1: properties.radius + 35,\n            x2: options.diameter - 55,\n            y2: properties.radius + 35,\n            'stroke': '#DDDDDD',\n            'stroke-width': '1',\n            'opacity': '0.8'\n        }, svg);\n\n        var lblLeft = createSVGElement('text', {\n            x: 125,\n            y: properties.radius + 75,\n            class: 'lbl lblDial'\n        }, svg);\n        var lblLeftText = document.createTextNode(options.labels.set);\n        lblLeft.appendChild(lblLeftText);\n\n        var lblTarget = createSVGElement('text', {\n            x: 125,\n            y: properties.radius + 115,\n            'font-size': '35',\n            class: 'lbl lblTarget',\n            'id': targetElement.getAttribute('id') + 'lblTarget'\n        }, svg);\n        var lblTargetText = document.createTextNode('20');\n        lblTarget.appendChild(lblTargetText);\n\n        var lblTargetDec = createSVGElement('tspan', {\n            'font-size': '20',\n        }, lblTarget);\n\n        var lblTargetDecText = document.createTextNode('.5');\n        lblTargetDec.appendChild(lblTargetDecText);\n\n        var lblRight = createSVGElement('text', {\n            x: options.diameter - 125,\n            y: properties.radius + 75,\n            class: 'lbl lblDial'\n        }, svg);\n        var lblRightText = document.createTextNode(options.labels.mode);\n        lblRight.appendChild(lblRightText);\n\n        var lblMode = createSVGElement('text', {\n            x: options.diameter - 125,\n            y: properties.radius + 115,\n            'font-size': '35',\n            class: 'lbl lblTarget icon',\n            'id' : targetElement.getAttribute('id') + 'lblMode'\n        }, svg);\n        var lblModeText = document.createTextNode(properties.modes[0].icon);\n        lblMode.appendChild(lblModeText);\n\n        var btnSet = createSVGElement('g', {\n            transform: 'translate(200,200)'\n        }, svg);\n        var btnLeft = createSVGElement('path', {\n            d: 'M0,40 L0,175   A175,175 0 0,1 -175,40    z',\n            fill: 'blue',\n            opacity: '0',\n            'id': targetElement.getAttribute('id') + 'btnLeft'\n        }, btnSet);\n        var btnRight = createSVGElement('path', {\n            d: 'M0,40 L175,40   A175,175 0 0,1    0,175  z',\n            fill: 'red',\n            opacity: '0',\n            'id': targetElement.getAttribute('id') + 'btnRight'\n        }, btnSet);\n\n\n\n        btnLeft.onclick = function() {\n            setTargetClick();\n        };\n\n        btnRight.onclick = function() {\n            setModeClick();\n        };\n\n        var targetPanel = false;\n        var modePanel = false;\n\n        var lblAmbientAttributes = {\n            x: lblAmbient.getAttribute('x'),\n            y: lblAmbient.getAttribute('y'),\n            size: lblAmbient.getAttribute('font-size')\n        };\n\n        var lblAmbientDecAttributes = {\n            x: lblAmbientDec.getAttribute('x'),\n            y: lblAmbientDec.getAttribute('y'),\n            size: lblAmbientDec.getAttribute('font-size')\n        };\n\n        var lblTargetAttributes = {\n            x: lblTarget.getAttribute('x'),\n            y: lblTarget.getAttribute('y'),\n            size: lblTarget.getAttribute('font-size')\n        };\n\n        var lblTargetDecAttributes = {\n            x: lblTargetDec.getAttribute('x'),\n            y: lblTargetDec.getAttribute('y'),\n            size: lblTargetDec.getAttribute('font-size')\n        };\n\n        var lblModeAttributes = {\n            x: lblMode.getAttribute('x'),\n            y: lblMode.getAttribute('y'),\n            size: lblMode.getAttribute('font-size')\n        };\n\n        var lblRightAttributes = {\n            x: lblRight.getAttribute('x'),\n            y: lblRight.getAttribute('y'),\n            size: lblRight.getAttribute('font-size')\n        };\n\n        var lblLeftAttributes = {\n            x: lblLeft.getAttribute('x'),\n            y: lblLeft.getAttribute('y'),\n            size: lblLeft.getAttribute('font-size')\n        };\n\n        render();\n\n        function setAmbientTemperature(ambientTemp) {\n            var splitValues = separateDecValue(ambientTemp);\n            lblAmbientText.textContent = splitValues.int;\n            lblAmbientDecText.textContent = splitValues.dec;\n        };\n\n\n        function calcTargetTemperature(operation) {\n            let currentTemp = Number(parseFloat(lblTargetText.textContent + lblTargetDecText.textContent)).toFixed(1);\n            let targetTemp = (operation == '-' ? Number(Number(currentTemp) - 0.5).toFixed(1) : Number(Number(currentTemp) + 0.5).toFixed(1));\n            targetTemp = rangedTemperature(targetTemp);\n            setTargetTemperature(targetTemp);\n            chkSwitchState();\n        };\n\n        function setTargetTemperature(targetTemp) {\n            var splitValues = separateDecValue(targetTemp);\n            lblTargetText.textContent = splitValues.int;\n            lblTargetDecText.textContent = splitValues.dec;\n            if (state.target_temperature != targetTemp) {\n                state.target_temperature = targetTemp\n                sendMsg();\n            };\n        };\n\n        function separateDecValue(floatFalue) {\n            var int = Math.floor(floatFalue);\n            var dec = Math.floor(((floatFalue % 1) * 10)) > 0 ? (\".\" + Math.floor(((floatFalue % 1) * 10))) : \"\";\n            return {\n                int,\n                dec\n            };\n        };\n\n        function rangedTemperature(temperature) {\n            temperature = temperature < options.mintemp ? options.maxtemp : temperature;\n            temperature = temperature > options.maxtemp ? options.mintemp : temperature;\n            return temperature;\n        };\n\n        function chkSwitchState() {\n            console.log(\"chkSwitchState\");\n            var switchState = state.switch_state;\n            switch (state.mode) {\n                case 0:\n                    switchState = state.ambient_temperature < state.target_temperature ? 'heating' : 'off';\n                    break;\n                case 1:\n                    switchState = state.ambient_temperature > state.target_temperature ? 'cooling' : 'off';\n                    break;\n                default:\n                    switchState = 'off';\n            };\n\n            ledRingGradientColorIn.setAttribute('stop-color', options.ledColors[state.switch_state]);\n\n            if (state.switch_state != switchState) {\n                state.switch_state = switchState;\n                sendMsg();\n            };\n        };\n\n\n        function resetButton() {\n            btnLeft.onmousedown = \"\";\n            btnLeft.onmouseup = \"\";\n            btnLeft.onclick = function() {\n                setTargetClick();\n            };\n            btnRight.onmousedown = \"\";\n            btnRight.onmouseup = \"\";\n            btnRight.onclick = function() {\n                setModeClick();\n            };\n        };\n\n        function switchMainView(element, originalAttributes, mainLabel, leftLabel, rightLabel, panelState) {\n            setClass(lblAmbient, \"nodisplay\", panelState);\n            setClass(lblMain, \"animate\", panelState);\n            setClass(lblLeft, \"animate\", panelState);\n            setClass(lblRight, \"animate\", panelState);\n            setClass(element, \"animate\", panelState);\n\n            lblMainText.textContent = panelState ? mainLabel : options.labels.ambient;\n            lblLeftText.textContent = panelState ? leftLabel : options.labels.set;\n\n            lblLeft.setAttribute('y', panelState ? Number(lblLeftAttributes.y) + 40 : lblLeftAttributes.y);\n            lblLeft.setAttribute('font-size', panelState ? \"3.5em\" : \"1em\");\n\n            lblRightText.textContent = panelState ? rightLabel : options.labels.mode;\n            lblRight.setAttribute('y', panelState ? Number(lblRightAttributes.y) + 40 : lblRightAttributes.y);\n            lblRight.setAttribute('font-size', panelState ? \"3.5em\" : \"1em\");\n\n            element.setAttribute('x', panelState ? lblAmbientAttributes.x : originalAttributes.x);\n            element.setAttribute('x', panelState ? lblAmbientAttributes.x : originalAttributes.x);\n            element.setAttribute('y', panelState ? lblAmbientAttributes.y : originalAttributes.y);\n            element.setAttribute('font-size', panelState ? lblAmbientAttributes.size : originalAttributes.size);\n\n        };\n\n\n        function setTargetClick() {\n\n            targetPanel = targetPanel ? false : true;\n            setClass(lblMode, \"nodisplay\", targetPanel);\n            switchMainView(lblTarget, lblTargetAttributes, options.labels.set, options.labels.minus, options.labels.plus, targetPanel);\n\n            lblTargetDec.setAttribute('font-size', targetPanel ? lblAmbientDecAttributes.size : lblTargetDecAttributes.size);\n\n            if (targetPanel) {\n                btnLeft.onclick = \"\";\n                btnRight.onclick = \"\";\n\n                btnLeft.onmousedown = function() {\n                    calcTargetTemperature(\"-\");\n                    if (mousedownID == -1) { //Prevent multimple loops!\n                        mousedownID = setInterval(calcTargetTemperature, 500, '-');\n                    }\n                };\n                btnLeft.onmouseup = function() {\n                    if (mousedownID != -1) { //Only stop if exists\n                        clearInterval(mousedownID);\n                        mousedownID = -1;\n                    }\n                };\n\n                btnRight.onmousedown = function() {\n                    calcTargetTemperature(\"+\");\n                    if (mousedownID == -1) { //Prevent multimple loops!\n                        mousedownID = setInterval(calcTargetTemperature, 500, '+');\n                    }\n                };\n                btnRight.onmouseup = function() {\n                    if (mousedownID != -1) { //Only stop if exists\n                        clearInterval(mousedownID);\n                        mousedownID = -1;\n                    }\n                };\n\n                lblTarget.onclick = function() {\n                    setTargetClick();\n                };\n            } else {\n                resetButton()\n            }\n        };\n\n        function setModeClick() {\n\n            modePanel = modePanel ? false : true;\n            setClass(lblTarget, \"nodisplay\", modePanel);\n            switchMainView(lblMode, lblModeAttributes, options.labels.mode, options.labels.left, options.labels.right, modePanel);\n\n            if (modePanel) {\n\n                btnLeft.onclick = function() {\n                    mode = state.mode;\n                    mode = --mode < 0 ? properties.modes.length - 1 : mode;\n                    console.log(\"MODE :\" + mode);\n                    setModeName(properties.modeNames[mode]);\n                    chkSwitchState();\n                    sendMsg();\n                };\n\n                btnRight.onclick = function() {\n                    mode = state.mode;\n                    mode = ++mode > properties.modes.length - 1 ? 0 : mode;\n                    console.log(\"MODE :\" + mode);\n                    setModeName(properties.modeNames[mode]);\n                    chkSwitchState();\n                    sendMsg();\n                };\n//                document.getElementById(targetElement.getAttribute('id') + \"lblMode\").onclick = function() {\n                lblMode.onclick = function() {\n                    setModeClick();\n                };\n            } else {\n                resetButton()\n            }\n        };\n\n        function setModeName(modeName) {\n            lblMode.textContent = properties.modes[properties.modeNames.indexOf(modeName)].icon;\n            lblMode.style.fill = properties.modes[properties.modeNames.indexOf(modeName)].color;\n            state.mode = properties.modeNames.indexOf(modeName);\n        };\n\n        function sendMsg() {\n            if (typeof options.onChangeState == 'function') {\n                options.onChangeState(state.switch_state);\n            }\n        };\n\n        function render() {\n            console.log(\"RENDER\");\n            setAmbientTemperature(self.ambient_temperature);\n            setTargetTemperature(self.target_temperature);\n            setModeName(self.mode_name);\n            chkSwitchState();\n        };\n\n    };\n})();\n\nvar initializing = true;\n(function(scope) {\n    console.log(\"scope.id = GhostThermostat\" + scope.$id);\n    $(function() {\n        var ghostThermostat = new ghostThermostatDial(document.getElementById('GhostThermostat' + scope.$id), {\n            onChangeState: function() {\n                var p = {\n                    \"ambient_temperature\": ghostThermostat.ambient_temperature,\n                    \"target_temperature\": ghostThermostat.target_temperature,\n                    \"mode\": ghostThermostat.mode_name,\n                    \"switch_state\": ghostThermostat.switch_state,\n                    \"away\": ghostThermostat.away\n                };\n                scope.send({\n                    topic: \"changed_state\",\n                    payload: p\n                });\n            }\n        });\n\n\n        scope.$watch('msg', function(data) {\n            if (initializing) {\n                initializing = false;\n            } else {\n                ghostThermostat.ambient_temperature = data.payload.ambient_temperature || ghostThermostat.ambient_temperature;\n                ghostThermostat.target_temperature = data.payload.target_temperature || ghostThermostat.target_temperature;\n                ghostThermostat.mode_name = data.payload.mode || ghostThermostat.mode_name;\n                ghostThermostat.switch_state = data.payload.switch_state || ghostThermostat.switch_state;\n                ghostThermostat.away = data.payload.away || ghostThermostat.away;\n            }\n        });\n    });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":590,"y":280,"wires":[["3619c6bb1af6d574","db8eed00df446e88","de86770d2afb8e56"]],"icon":"font-awesome/fa-tachometer"},{"id":"3619c6bb1af6d574","type":"function","z":"392c1bb3c1c96f96","name":"turn on heat","func":"let Z = msg.payload.switch_state;\n\nif (Z == \"heating\"){\n    msg = {\n        payload: 1,\n        topic: \"heating\",\n    }\n    return msg;\n}\n\nif (Z == \"cooling\") {\n    msg = {\n        payload: 1,\n        topic: \"cooling\",\n    }\n    return msg;\n}\n\nmsg = {\n    payload: 0,\n    topic: \"off\",\n}\n\nnode.status({fill:\"blue\",shape:\"dot\",text:msg.topic});\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":770,"y":360,"wires":[[]]},{"id":"bd175ed19a1ca4cb","type":"function","z":"392c1bb3c1c96f96","name":"set ambient","func":"let Z = msg.payload;\nZ= Number(Z);\nZ = Z - 4;\nlet num = Z;\nZ = num.toFixed(1);\n\nmsg.topic = 'ambient_temperature';\nvar data = {\n    'ambient_temperature': Z,\n}\nmsg.payload = data;\n\nnode.status({ fill: \"blue\", shape: \"dot\", text: Z });\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":280,"wires":[["5afda673dba62107"]]},{"id":"1d8b2e54ef52fb6b","type":"smooth","z":"392c1bb3c1c96f96","name":"","property":"payload","action":"mean","count":"5","round":"1","mult":"single","reduce":false,"x":180,"y":280,"wires":[["bd175ed19a1ca4cb"]]},{"id":"db8eed00df446e88","type":"function","z":"392c1bb3c1c96f96","name":"store","func":"let Z = msg.payload.mode;\nflow.set(\"mode\",Z);\n\nZ = msg.payload.away;\nflow.set(\"away\",Z);\n\nZ = msg.payload.target_temperature;\nflow.set(\"target\",Z);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":420,"wires":[[]]},{"id":"e6ba72baec704adf","type":"inject","z":"392c1bb3c1c96f96","name":"pwr on","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"10","topic":"","payload":"1","payloadType":"str","x":140,"y":160,"wires":[["d3a088cc0ed7208e"]]},{"id":"d3a088cc0ed7208e","type":"function","z":"392c1bb3c1c96f96","name":"set on pwr up","func":"var Ambient = flow.get(\"ambient\");\nvar Away = flow.get(\"away\");\nvar Mode = flow.get(\"mode\");\nvar Target = flow.get(\"target\");\n\nmsg.topic = 'ambient_temperature';\nvar data = {\n//    'ambient_temperature': Ambient,\n    'target_temperature': Target,\n    'away': Away,\n    'mode': Mode,\n}\nmsg.payload = data;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":200,"wires":[["de86770d2afb8e56"]]},{"id":"10636c65ec2b2239","type":"mqtt in","z":"392c1bb3c1c96f96","name":"","topic":"inside1_tempC","qos":"2","datatype":"auto-detect","broker":"718df452c076bbbe","nl":false,"rap":true,"rh":0,"inputs":0,"x":80,"y":220,"wires":[["1d8b2e54ef52fb6b"]]},{"id":"de86770d2afb8e56","type":"function","z":"392c1bb3c1c96f96","name":"refresh","func":"\nvar Ambient;\nvar Away;\nvar Mode;\nvar Target;\n//Target = context.get(\"Target\");\n\nif (msg.topic == \"changed_state\"  || msg.topic == \"ambient_temperature\"){\n    Ambient = msg.payload.ambient_temperature;\n    context.set(\"Ambient\",Ambient);\n    Away = msg.payload.away;\n    context.set(\"Away\",Away);\n    Mode = msg.payload.mode;\n    context.set(\"Mode\",Mode);\n    Target = msg.payload.target_temperature;\n    context.set(\"Target\",Target);\n    msg.topic = 'ambient_temperature';\n    var data = {\n    //    'ambient_temperature': Ambient,\n        'target_temperature': Target,\n        'away': Away,\n        'mode': Mode,\n    }\n    msg.payload = data;\n    return msg;\n}\n\nAmbient = context.get(\"Ambient\");\nAway = context.get(\"Away\");\nMode = context.get(\"Mode\");\nTarget = context.get(\"Target\");\n\nif (Target == undefined) {\n    msg.payload = \"undefined\";\n    return msg;\n}\n\nmsg.topic = 'ambient_temperature';\nmsg.payload = {\n//    'ambient_temperature': Ambient,\n    'target_temperature': Target,\n    'away': Away,\n    'mode': Mode,\n}\n\nnode.status({ fill: \"blue\", shape: \"dot\", text: Away });\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":200,"wires":[["5afda673dba62107"]]},{"id":"6912e86781efd9e9","type":"inject","z":"392c1bb3c1c96f96","name":"3 second","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3","crontab":"","once":true,"onceDelay":"1","topic":"5second","payload":"1","payloadType":"str","x":390,"y":140,"wires":[["de86770d2afb8e56"]]},{"id":"9c90a075584ede2b","type":"ui_group","name":"Thermostat","tab":"f394bc89e321d6f1","order":1,"disp":false,"width":6,"collapse":false,"className":""},{"id":"718df452c076bbbe","type":"mqtt-broker","name":"","broker":"192.168.1.5","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"5","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"f394bc89e321d6f1","type":"ui_tab","name":"Thermostat","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

this is the only node red log file in the /var/log sub-dir

nodered-install.log (1.6 KB)

and I did a restart command several times

Steve meant the output from

node-red-stop
node-red-start

It should be contextStorage, not ContextStorage. In .node-red/settings.js you should have found that line already present, and just had to amend the contents of the object.

2 Likes

Wow, great catch @Colin. That was the problem, Changed to small "c" and presto the sub-dir showed up.

I don't understand how you ended up with the error. The default settings.js file already includes a contextStorage entry that just needs to be edited. Did you not do that or did your settings.js not already include it?

I was wondering if you were going to bring it up. So... yes the entry was there and yes I only needed to modify it, however, and I'm making a guess here for part of it. The cursor wasn't where I thought it was and instead of deleting a character I deleted the block and thus I wound up having to retype the entire thing and used a capital letter instead of a lower case. But, I'm going with I did a great job with it as I only missed one character.

2 Likes

OK, that explains it. Hasn't your editor got an Undo feature?