Error in a function in Node-Re 2.2 not present in previous versoins

The setup funnction with condition removed

//if (!timing || !Array.isArray(timing)) // new
//if ( typeof context.global.timing == 'undefined' ) 
    {
       //context.global.timing=[
       global.set("timing",[
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
                        8,14
                        ]);
        context.saving=0;
        msg.payload="anything";  msg.foryou="Restoring"; return([null,null,msg]);
    }

var timing=global.get("timing");

and the "process heat" function in total

var timing=global.get("timing");
node.warn(["timing is -->", timing]);
var now = new Date();
msg.payload=timing[(now.getDay()*24)+now.getHours()];
node.warn(["msg.payload is now -->", msg.payload]);
msg.away=timing[169];

msg.temperature=flow.get("incomingTemperature");
node.warn(["msg.temperature is -->", msg.temperature]);
msg.humidity=flow.get("incomingHumidity");
msg.set=msg.payload;
if (flow.get("manualTimer")) flow.set("manualTimer",flow.get("manualTimer")-1);
else flow.set("manual",0);
msg.desired=msg.set;
flow.set("setTemperature",msg.desired);
msg.desired+=flow.get("manual");
// fixed local away to global away on jan 17 2020
if (global.get("away"))   msg.desired=global.get("timing")[169];  
if (msg.desired>msg.temperature) { msg.relay=1; } else { msg.relay=0; }

msg.payload=flow.get("incomingTemperature");

node.status({fill:"blue",shape:"dot",text:"Set point " + msg.desired + "c - Actual " + msg.temperature +"c"});

msg.topic="processHeat";
if (msg.temperature<msg.desired) msg.colour="#ff5555";
node.send([msg,null]);
msg.payload=msg.relay;
node.send([null,msg]);

Something else in your flow must deleting global.timing be an issue because your version of the function DOES set global.timing...

and I can retrieve it...

Are you using a change node or another function somewhere to update global.timing?

Your marker that said it wsan't going anywhere - after thah code in the startup function, I do some checks on timing. As for PROCESS HEAT you have the whole function.
i put up your conext viewer and JUST after manually triggering the init you see I hit refresh in the relevant conbtext viewer part and still no sign of timing...

Peter,
How have you defined 'context storage' in settings.js? (if you look at your startup log you should see something like this:

28 Jan 05:39:37 - [info] Context store  : 'default' [module=localfilesystem]
1 Like

Peter, can you do a couple of basic tests & show me the results please...

chrome_AIi0y5Y8op

[{"id":"43a432396bcb5e59","type":"inject","z":"950e6f56f9415563","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":2500,"y":360,"wires":[["0fcd5312e67aa420"]]},{"id":"0fcd5312e67aa420","type":"function","z":"950e6f56f9415563","name":"set flow.test","func":"flow.set(\"test\", (new Date()).toISOString())\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2680,"y":360,"wires":[["4ae9e8044fa3e804"]]},{"id":"4ae9e8044fa3e804","type":"function","z":"950e6f56f9415563","name":"set global.test","func":"global.set(\"test\", (new Date()).toISOString())\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2690,"y":400,"wires":[["4a7a3179e32066c9"]]},{"id":"4a7a3179e32066c9","type":"change","z":"950e6f56f9415563","name":"flow.test2","rules":[{"t":"set","p":"test2","pt":"flow","to":"$now()","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2670,"y":440,"wires":[["8d7f9a8bedc3824c"]]},{"id":"8d7f9a8bedc3824c","type":"change","z":"950e6f56f9415563","name":"global.test2","rules":[{"t":"set","p":"test2","pt":"global","to":"$now()","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2680,"y":480,"wires":[["13ad3631ca929c25"]]},{"id":"13ad3631ca929c25","type":"function","z":"950e6f56f9415563","name":"node warn","func":"var x = {\n    \"flow.test\": global.get(\"test\"),\n    \"global.test\": global.get(\"test\"),\n    \"flow.test2\": flow.get(\"test2\"),\n    \"global.test2\": global.get(\"test2\"),\n}\nnode.warn(x)\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2710,"y":540,"wires":[[]]}]

Sorry - I've been working with heating engineers servicing our heating - just as I'm messing here with the thrermostat. I'm back and will read this now.

Does this help - my /home/pi/.node-red/settings.js - relevant part

     contextStorage: {
    	default    : { module: "localfilesystem"}
    },

Steve

I imported your code into the flow
image

image

And the GLOBAL is historical - the array is not used outside of this page (flow)

Test and test2 appear in globals on refresh - they also appear in flow

But there is no sign of my TIMING array in globals - yet this has worked for years..

If this helps - the entire flow..

[{"id":"43a432396bcb5e59","type":"inject","z":"950e6f56f9415563","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":2500,"y":360,"wires":[["0fcd5312e67aa420"]]},{"id":"0fcd5312e67aa420","type":"function","z":"950e6f56f9415563","name":"set flow.test","func":"flow.set(\"test\", (new Date()).toISOString())\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2680,"y":360,"wires":[["4ae9e8044fa3e804"]]},{"id":"4ae9e8044fa3e804","type":"function","z":"950e6f56f9415563","name":"set global.test","func":"global.set(\"test\", (new Date()).toISOString())\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2690,"y":400,"wires":[["4a7a3179e32066c9"]]},{"id":"4a7a3179e32066c9","type":"change","z":"950e6f56f9415563","name":"flow.test2","rules":[{"t":"set","p":"test2","pt":"flow","to":"$now()","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2670,"y":440,"wires":[["8d7f9a8bedc3824c"]]},{"id":"8d7f9a8bedc3824c","type":"change","z":"950e6f56f9415563","name":"global.test2","rules":[{"t":"set","p":"test2","pt":"global","to":"$now()","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2680,"y":480,"wires":[["13ad3631ca929c25"]]},{"id":"13ad3631ca929c25","type":"function","z":"950e6f56f9415563","name":"node warn","func":"var x = {\n    \"flow.test\": global.get(\"test\"),\n    \"global.test\": global.get(\"test\"),\n    \"flow.test2\": flow.get(\"test2\"),\n    \"global.test2\": global.get(\"test2\"),\n}\nnode.warn(x)\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2710,"y":540,"wires":[[]]}]

Of interest the array is stored in a file -
and I just checked - that file is still intact with my settings.

[20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,20,19,19,19,19,19,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,20,8,12]

This proves your context storage is working - good.

That means something else (possibly in your flow) is destroying the global.timing array.

Interesting

Interesting.

Would you be able to share that file (private message if need be)

Unfortunately, that is just the test flow I sent you :frowning:

I think that you will need to search your flows for global.set("timing" and see if there are any other references.

I think that I would also rename that variable to be more descriptive. That might also drive out some other references to it that you may have overlooked.

That would be because between us we had var timing and let timing. I'm assuming LET is a reference to the global sa against a local version? It SEEMS now to work... I've left LET in place and commened out the VAR version..

The stat SEEMS to be working... and thanks for your efforts guys...

Is LET a copy or does it point to the original? Never used that before.

let is (almost) the same as var (i wont get into the finer details like scoping or hoisting) but let me simplify it further by offering you this golden rule...

  • Use const for everything
  • Use let when const doesn't work
  • Dont use var

Happy to help.

I think that it is worth pointing out that the difference between let/const and var can easily catch you out.

let/const only work from ES6 onwards. But that is all currently supported versions of node.js

let/const is position sensitive. var on the other hand is not, JavaScript will "hoist" a var to the top-level context of your function. But let/const are restricted in context to the parent code block and must be declared before use. Also, you can re-declare a variable using let/const within a child code block, you cannot do that with a var.

For the most part, most people ignore the differences but it WILL eventually catch you out :slight_smile:

So as Steve says, generally don't use var. But, there are still a few cases where the limited context of let/const is difficult or annoying to deal with and it is just easier to use a var.

In the browser, things are different - if you have to support old browsers. Anything old enough not to support ES6 requires only the use of var. So old iPads or Android tablets for example that you may not be able to upgrade.

3 Likes

But Julian will :smiley:

Well written Julian - I just didn't want to be the one to raise his blood pressure.


I'll amend my earlier statement...

  • In node / function node
    • Use const for everything
    • Use let when const doesn't work
    • Try to avoid using var
  • In browser/client side code (ui template etc)
    • You will be forgiven for using var :slight_smile:
2 Likes

hi

Perhhaps I could ask one of you clever chaps for a last clarification. Oh and my blood pressure is chemically controlled so no worries :slight_smile:

The reason I used "var timing" was laziness - to avoid having to key in clobal.get etc every time - so timeing was a temporary local copy of the array (I hope). Can you clarify:

let timing=global.get("timing")

Am I now working with a copy of the original global of is "timing" the actual global? If I'm working with the global I'm more than happy but I'd like to be sure - and thanks once again for helping. I'm no-where near a node-red newbie but like most self-taught, I have the odd gap in my knowledge and clarification will hopefully clear it up.

Regards

Pete

It returns a reference to the object in context, not a copy.

If you want to modify it without changing in context, you will need to clone it first.

As you know it's an array, you could do:

let timing = [ ...global.get("timing")]

Or, more generally

let timing = RED.util.cloneMessage(global.get("timing"))
3 Likes