Node-red won't start

@dceejay thanks that flow was handy.

I can find the flow and global being written, I can't find the context, however all my other flow variables are not in the same flow file as the new "foo" variable....

image

None of these are visible though:

image

Ok, I have to stop for a bit, my wife if reminding me that I have this thing called a "family" to attend to.
I'll get back to this later this afternoon.... thanks for your help so far. I'm learning more each day :slight_smile:

Ok, back from a walk with the kids and coffee in hand, I can see how the context folder works. Pretty straightforward really.

  • There is a folder per canvas
  • if you have flow variables, then each folder has a "flow.json" file
  • if you have node/context variables, then each folder has a randomly generated file name.json file
    The global folder contains the global variables

image

So there is the problemo, the last folder in the list below if the folder that contains my hot water panel flow variables, despite having changed them a lot of time the last update was last night at 23:13....

I am going to copy all my nodes to a new canvas and see if that fixes it, however now I am thinking that this is a bug and not my doing...... hmmmm

PS:I'll keep the nodes in the old canvas incase someone wants some info on it to help debug.... :wink:

The numbers are the id s of the nodes, tabs(flows) etc. So if you create new ones they will have different numbers.

@dceejay

Ok, this is weird. I have created a new flow and copied all the nodes into it. It is working fine. On deploy the flow.json file is created in a new context folder (with its own unique number, as you described), however the data in it will no longer update, after creation, despite me making changes that I can see in the context data side-bar.

However, when I paste your flow into the new flow/canvas and inject the variables I can see the flow.json updating almost instantly and at that point in time the flow.json gets updated with the latest values from my flow variables....

What have I done to get this behaviour? I can't help but think it must be something I have done now....

Thanks to your little flow I can set it to run every 30 seconds / 1 minute (whatever) and that will force the flow.json to be updated, but what on earth is going on, any ideas?

PS: set your inject and function to run every 1 minute interval and now it's working fine.... hmmmm :thinking:

Can you show us the code you are using to write to the context? Is it possible you are not doing flow.set()?

1 Like

OMG, I am as thick as two bricks. :flushed:

@UnborN pointed that out to me a while back and I confidently said, but it works... I read a variable in. I then update it, and it shows as being updated in the sidebar, but I did not use the flow.set command and I guess that's the problem.... doh!!!!

Lesson learnt!
Time to update my code...

PS: this is the code here...

No point in pasting the actual code as I'm sure you have pointed out the error in my ways...

Thanks @Colin for being patient and persistent.

1 Like

I remember why I did what I did... I couldn't find out how to update just a single property of a variable (using flow.set) without overwriting the whole variable with just one value.... and it updated just fine when I update the variable directly (but obviously that was not the case).... I'll dig around and find out how now, however it feels much easier for me to leave an inject in my flow to writes to a context, flow and global every minute.... that's the lazy option anyway as I don't need to make any changes to my code.

Because the thing you are saving in context is an object, when you do flow.get it gives you a reference (or pointer) to the cache of the object from the file in memory. When you change a property of that object it changes the version in memory so appears to work fine. It is, however, the flow.set() that tells the s/w that you have changed something so that it knows to write the cache out to disc.
I wouldn't recommend that you leave it as you have it. Since the s/w does not know that you have changed it, if node-red is stopped after you change the data but before your inject fires it will not write the cache out to the file so you will lose the latest changes. By using flow.set() it will know that it has changed and so write it out when node-red stops, if it has not already written it.

@Colin

Yeah, I kinda figured that out (the writing to memory vs to disc) when you asked the question about did you use "flow.set".

So I am fiddling around again and maybe you know the answer... how would I flow.set my HW_Values flow variable?

[{"id":"d2657346.fe2d5","type":"function","z":"f5fbd2bf.ac7f4","name":"Update Status","func":"var HW_Values               = flow.get(\"hw_values\");\nHW_Values                   = HW_Values.find(HW_Value => HW_Value.device == msg.topic);\n\nif (HW_Values.pump_status !== undefined) {HW_Values.pump_status = msg.payload} else  {HW_Values.actual = msg.payload}\n\nmsg.payload = {};\nmsg.cache = true\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":760,"y":600,"wires":[["ac79691f.d2d9f8","31d023d8.22c92c","3a207611.49589a"]]}]

I can't seem to get it right...

BTW, running a flow.set every 1 minute is fine for this panel as things rarely change i.e. once the temps / schedule is set it doesn't change much, but I would like to learn how to do it properly.... I'll keep reading up to see what I've missed and see if I can get the answer either way.

EDIT: actually in the world of hacks I can just link my (read; your) generic flow.set to the 2x nodes that update variables, so the updates will be instant anyway... haha, good old programming a 100 ways to do almost anything and probably only one or two that are optimal.

Don't overwrite the reference that you get from flow.get() (ie HW_Values), that is not a good idea anyway, it means your code is rather confusing. Use a new variable name on the second line. Then at the end
flow.set("hw_values", HW_Values)

I've timed out on this one, have to start preparing for dinner.

I can only see complicated ways of reading and updating a variable to presumably then allow me to flow.set the whole variable .... too many lines of code and too much testing, and the big AND, I am updating variables all over the shop in my nodes, so for now this works a treat....

You can see the 3x dotted lines to the function "write to disc"

the function has this in it:

flow.set("flowfoo","flowbar-leo");
global.set("globalfoo","globalbar");
context.set("nodefoo","nodebar")
return msg;

Works fine for me for now, it's near instant and requires no more testing for it to work... thanks again @Colin!

PS: I realise I was being a big harsh on myself about not knowing how local storage works for Node-RED, obviously I had assumed every 30 seconds meant, every 30 seconds for all data.... clearly, not the case... another valuable lesson learnt.

Time for dinner now, Veggies/Vegans look away .... 1.2kg rib-eye on the bone and red wine tonight plus some of the stuff that food eats on the side ie salad... hahahaha :slight_smile:

PPS: I'm waiting for someone clever to tell me there's an easier/better way

1 Like

What's complicate about

const HW_Values               = flow.get("hw_values");
const HW_Val                   = HW_Values.find(HW_Value => HW_Value.device == msg.topic);

if (HW_Val.pump_status !== undefined) {HW_Val.pump_status = msg.payload} else  {HW_Val.actual = msg.payload}

msg.payload = {};
msg.cache = true
flow.set("hw_values",  HW_Values)
return msg;

get() the value at the start of the function, don't overwrite the reference within the function, and set() it at the end. Plus don't return in the middle of a function, but again that is a bad idea anyway, I have seen many bugs caused by doing that.

But you don't have to get/set the whole of an object when using Node-RED's variables.

Here is a quick example:

var env = {
    "args":"--userDir,./data",
    "automation":"true",
    "autorestart":"true",
    "windir":"C:\\WINDOWS",
    "windowsHide":"true",
    "_prog":"node"
}

context.set('env', env)

context.set('env.automation', 'false')

const env2 = context.get('env.automation')

msg.payload = env2

return msg

You can use this form as well: 'env["automation"]'

Generally, I do the same as Colin though because it makes the code easier to read. But if you want a bit more efficiency, this is the way to go.

Are you sure it is more efficient? Does context.set do a clone or just set a reference?

You would have to dig into the code I'm afraid - but I suspect it is probably slightly better on memory, at least for a big object, since the full object reference is likely to be released earlier. Of course, I might well be wrong.

Something to test on a slow, rainy day :smiley:

Aha haha... Don't put me in charge of heavy machinery tonight.

I clearly wasn't on form there. If I overwrite the variable then off course it won't work.

I'm sticking to my hack for now, cause it works, but I'll do it properly going forward.

Which properly is yet to be determined, but I don't think any of my variables will be that big that there will be a big performance issue either way.

Not sure what you mean by that.

In theory, once a reference is finished with, the garbage collection routines of node.js can recover the space. So even if something like flow.get('xxx.property') gets the full object as it only returns the individual property, the rest can be released once the function finishes.

Least, that's what I think might happen. But, as I say, I am no expert so I might be completely wrong.

We know that flow.get for an object does not do a clone, as it is not actually necessary to do the flow.set at all after modifying properties, so I don't know what there is to be garbage collected whichever way it is done.