How to set context variables containing spaces?

I know this isn't a huge deal and I could just use underscores, except that I'm positive I did this literally yesterday and now I've no idea how I accomplished it.

I'm trying to create the property "heat index" in the global context object, but I've tried the following to no avail:

global.set("[\"heat index\"]",hindex);

and

var tmp = "heat index";
global.set(tmp,hindex);

What am I missing? Just yesterday I created that context, changed my mind and today I'm trying to change it back, but I have no idea what I did to create it.

I even tried to change the global.json file, replacing the underscore with a space, which caused NodeRED to crash every time it tried to set up.

So now I'm wondering whether I only thought I accomplished that yesterday in my late night delirium and now I'm losing my mind trying to redo what can't be done...

You are right, there seems to be a bug when there are spaces in the key.

I just tried to set and get a context value named foo bar

global.set('foo bar', 123);
global.get('foo bar');

and ended up with the following error:

Error: Invalid property expression: unexpected ' ' at position 3"

After removing the space it worked.

You should open a ticket here.

EDIT:

I believe the key is evaluated as an expression, so this may be a feature rather than a bug. :sweat_smile:

That being said... if you really need to use keys with spaces

global.set('\'foo baz\'', 456);

should do the trick.

However, I found that it will not show up in the context sidebar, if there are any spaces in the key.

Global variables should be considered just that, a variable rather than a key to a variable. In that case, a space isn't valid so I'm guessing that's why it hasn't been implemented.

Just create a variable name without the space and if you need something with a space, add it to that variable as an object instead.

But you can't use global 'variables' as variables... You can neither assign them nor retrieve them as you would a variable, you must .get() and .set() all context variables or the changes will not persist between nodes.

For example, let's string two function nodes together. The first node is:

// Set test1 like a variable
global.test1 = true;
// Set test2 like a property
global.set("test2",true);
return msg;

Second node:

var newMsg = {
    // Retrieve both like variables
    "variable": {
        "test1": global.test1,
        "test2": global.test2
    },
    // Retrieve both like properties
    "property": {
        "test1": global.get("test1"),
        "test2": global.get("test2")
    }
};
return newMsg;

This returns the following object:

{
    "variable": {},
    "property": {
        "test2": true
    },
    "_msgid": "1e2b86c4.b17c99"
}

Even in change nodes it's immediately apparent that they're object properties and not variables.

I only wanted to improve the look of the context panel, since I'm currently using NodeRED as my dashboard, where only the top-level properties are listed in plaintext. It's just frustrating that the devs have set arbitrary JSON formatting rules.

  1. Inside a function the deprecated way of accessing was

    context.global.test1 = true

Not global.test1

  1. we have always said the editor is NOT a dashboard

I was just following up on some old flows that broke due to a recent upgrade of NR and the no-space-in-context-keys is the cause for breakage. Context keys with spaces used to work just fine and that got broken. I really don't understand why you need to somehow disallow that. Javascript objects can have properties with spaces in them, maps can have keys with spaces in them, why disallow it for context?

NB: this limitation is not documented as far as I can tell. What is the character set that is allowed so I can fix my flows?

@tve

I have never set a flow or global base property with a space so I have no idea if this used to be possible but you are correct that it doesnt work in latest

change node...
image

function node...
flow.set("key with spaces", "the value")
image

Maybe you should raise this as an issue on gitthub?

I initially wasn't sure whether I was hallucinating about the "it used to work part" so I looked in the forum and bumped into this post... I don't want to add yet another github issue if it falls into the "we're not gonna change this" category...

They were always marked as invalid (red border) inside the change node. The latest release now properly surfaces config errors up when the dialog is closed.

Marking up the context name as a string seems to work with no errors, although it isn't displayed in the context sidebar.
For example "test context works"

context

[{"id":"6bdf9081.09c6b","type":"inject","z":"b3b413d1.05b1b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":275,"y":1415,"wires":[["50e436de.2dece8"]]},{"id":"50e436de.2dece8","type":"change","z":"b3b413d1.05b1b","name":"","rules":[{"t":"set","p":"\"test context works\"","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":1415,"wires":[[]]},{"id":"f42acc0d.824fc","type":"inject","z":"b3b413d1.05b1b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":280,"y":1455,"wires":[["bb42b3a1.6767a"]]},{"id":"bb42b3a1.6767a","type":"change","z":"b3b413d1.05b1b","name":"get \"test context works\"","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"test context works\"","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":480,"y":1455,"wires":[["29b9ad76.33e972"]]},{"id":"29b9ad76.33e972","type":"debug","z":"b3b413d1.05b1b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":685,"y":1455,"wires":[]}]

Interesting find! Trying to read the "test context works" state in a function node fails:

[{"id":"f20fd17d.b0cdd","type":"inject","z":"630bc809.3cefa8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1480,"wires":[["71aa708a.cb207"]]},{"id":"71aa708a.cb207","type":"change","z":"630bc809.3cefa8","name":"","rules":[{"t":"set","p":"\"test context works\"","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":355,"y":1480,"wires":[[]]},{"id":"655bebce.96bbf4","type":"inject","z":"630bc809.3cefa8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":145,"y":1520,"wires":[["b0ab4b49.050988"]]},{"id":"b0ab4b49.050988","type":"change","z":"630bc809.3cefa8","name":"get \"test context works\"","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"test context works\"","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":345,"y":1520,"wires":[["a43a66e3.f11ef8"]]},{"id":"a43a66e3.f11ef8","type":"debug","z":"630bc809.3cefa8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":550,"y":1520,"wires":[]},{"id":"dcb2dc5b.3a9f5","type":"inject","z":"630bc809.3cefa8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":150,"y":1560,"wires":[["e1ed036d.063a7"]]},{"id":"68cb3090.876aa","type":"debug","z":"630bc809.3cefa8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":555,"y":1560,"wires":[]},{"id":"e1ed036d.063a7","type":"function","z":"630bc809.3cefa8","name":"get \"test context works\"","func":"return { payload: flow.get(\"test context works\") }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":1560,"wires":[["68cb3090.876aa"]]}]

And the context variable doesn't show at all in the context panel in the admin UI.

I never used change nodes for the contact, only function nodes, and there it worked fine.

More findings: it seems that the context goes out of its way to reject keys with spaces 'cause -, =, ||, even Δ all work fine:

 [{"id":"717ae0f1.22128","type":"inject","z":"630bc809.3cefa8","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"helloΔworld","payloadType":"str","x":130,"y":1660,"wires":[["fcd0185f.4d6538"]]},{"id":"a20f8b96.a99128","type":"debug","z":"630bc809.3cefa8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":555,"y":1660,"wires":[]},{"id":"fcd0185f.4d6538","type":"function","z":"630bc809.3cefa8","name":"set flow[payload]","func":"flow.set(msg.payload, \"777\")\nreturn { payload: msg.payload + \"=\" + flow.get(msg.payload) }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":1660,"wires":[["a20f8b96.a99128"]]}]

Yes, because a JavaScript identifier cannot contain a space. You cannot write:

let my variable = 1;

But an object property name can contain a space if you use the bracket notation to access it:

let obj = {};
obj["my variable"] = 1;

The same holds true for top level properties in context as far as the TypedInput widget we use is concerned.

Do you have an example of a flow that used to work for you and now doesn't?

I can't think of any recent changes in this area (other than the Change node I mentioned). Certainly not changed any of the context code for a long time.

What version of NR was it working on?

Last I know JavaScript identifiers cannot contain -, =, or || either, yet these work just fine in context keys:

[{"id":"717ae0f1.22128","type":"inject","z":"630bc809.3cefa8","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"hello||world","payloadType":"str","x":130,"y":1660,"wires":[["fcd0185f.4d6538"]]},{"id":"a20f8b96.a99128","type":"debug","z":"630bc809.3cefa8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":555,"y":1660,"wires":[]},{"id":"fcd0185f.4d6538","type":"function","z":"630bc809.3cefa8","name":"set flow[payload]","func":"flow.set(msg.payload, \"777\")\nreturn { payload: msg.payload + \"=\" + flow.get(msg.payload) }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":1660,"wires":[["a20f8b96.a99128"]]}]

I still don't really understand the need to restrict the character set...

1 Like

So you're right, it didn't used to work. I checked back to 0.19.3 which is 3 years old. I guess I'll have to resort to doing a key.replace(" ", "∥") since every other character seems to work...

So are you now saying this wasn't the cause of whatever breakage you've had?

Correct. My apologies for being misleading. Something else must have changed...
(I use the name of irrigation circuits as keys into the context store and it's possible that I changed the names from "old-citrus" to "old citrus" or something like that. The functionality that uses the context variables has been broken for a few months so my recollection of what exactly changed is fuzzy.)

For anyone trying to figure out how to address devices that have already been given "friendly names" in zigbee2mqtt; you can simply use the IEEE Address (e.g.: 0x0017880109c080a8) in your automations.