Beginner questions on IF expressions and wildcard usage in function node

Actually, I used the wrong word
msg.powerDelta = []
does not declare an array variable (as I said), it creates a property of msg that is called powerDelta and is an array. An array must exist before you can write to it.

You could have said something like
msg.powerDelta = [1,7]
which will create and initialise it at the same time, but because you want to set an arbitrary element (i) that won't work.

Well, yes, I need to set [i] because I am iterating through the input array and creating a msg property per input array item.

    if (Array.isArray(msg.payload.ENERGY.Power)) {
        for (let i = 0; i < msg.payload.ENERGY.Power.length; i++) {
.
.
.
      msg.Update[i] = "True"
      msg.PowerDelta[i] = Math.abs(msg.payload.ENERGY.Power[i] - flow.get(msg.topic + "_Power" + [i]))

I was trying to recude code and make it work universally with any array length. So declaring first of course adds code when I am trying to minimize code.
But if that is required then that is what I will have to do :slight_smile:

Judging solely on indentation, msg.Update[i] appears to be outside the scope of your definition of i

Sorry, typing while on the road with a mobile does not let me indent while writing.

So no worries, of course everything is indented correctly. It is just supposed to show what I am doing and where the ì` is coming from.
Since I am declaring 5-6 arrays, I was hoping not to have to declare them as such first, but if I have to... well, I will :slight_smile:

Do you mean minimise the amount of work that has to be done at run time, or minimise the amount of typing you have to do?

If your original code had worked it would possibly make the generated code larger as it would have have to check every time it wrote to the array whether it already existed or not.

The initial approach check if [0] exists, then [1], then [2] and each then with the full set of statements.
So I changed to the i in length.

Goal was to reduce lines of code (after having written them) and make it more "elegant" and efficient

Using msg.payload.ENERGY.Power.forEach() would be more elegant than a for loop.
Also use push() to add elements to msg.Update and PowerDelta

1 Like

Could you explain what the advantage of push() is?
Did a quick syntax check and push always adds to the end. Is there any chance this will cause false order due to async or something? The order is relevant.

I will check out forEach(). Need to see if it is just as easy :wink:

That could only happen if you are doing the push inside an async process or if what you are pushing is an output from an async process.. Sorry, not checked the detailed flow so don't know if that is the case.

More elegant, no need to use i. Probably more efficient too. The order will always be the same as the order you go through the input array, provided you have not got any async code in there.
Using forEach() you won't need to use i at all.

Give it a try just now and although it works in principle, I have the problem that I am checking if a msg property needs updating and when it does not, I move to the next.

So if item 1 does not need updating, it is not written to the array. If item 2 needs updating, it is written to the array as second item.
If I use push(), then the second item (which is in need of updating) will be pushed to the number 1 spot in the array.
I could counteract that by always writting instead of leaving something undefined.

But not sure which approach I will use then.... hmmmm....

But how would I solve the msg.myVariable[i] problem if I use the forEach() approach. Then it will always overwrite the msg property because it will not turn it into an array.
I need the array to be able to procduce a msg property array.

Sorry, I know I probably sound confusing. I will need to sleep over it :slight_smile:

        for (let i = 0; i < msg.payload.ENERGY.Power.length; i++) {     // replaceable with forEach()
            if (flow.get(msg.topic + "_Power" + [i]) == undefined) {       // will not get the correct the correct context without an index
                flow.set(msg.topic + "_Power" + [i], msg.payload.ENERGY.Power[i]) // will not set a new context
                flow.set(msg.topic + "_PowerTime" + [i], msg.payload.Time)
                context.set(msg.topic + "_UpdateValue" + [i], msg.payload.ENERGY.Power[i])
                msg.DeviceName = flow.get(msg.topic + "/DeviceName")
                msg.Update[i] = "True"  // will keep overwriting msg.Update if I don't turn it into an array with index i
                //node.warn("PowerUndefined" + [i])
            }

In that case you need to use i to write the output data. You can make the current index available in the callback function in forEach() by providing a second argument to the callback function. JavaScript Array forEach() Method has an example of how to do that.

Yes, I had tried that and it works. Was just thinking if I can really do without the index, but I was not able to do so in my testing. :slight_smile:

I am about to rename my contexts and wanted to know what the best practice is for contexts that are not two joined words.
So for lowerCamelCase, you would e.g. name a msg property ˋmsg.temperatureDeltaˋ but would you then just use ˋmsg.temperatureˋ for the pure temperature property? So a name without actual CC or would you then force an addition like ˋmsg.newTemperatureˋ?

You can see the current convention from msg.payload, topic, etc. The majority of names are one word.

Yes, but how to you distinguish between what you created and what the system created?

Or, for instance, would you also use lowerCC for topics?

Because e.g. Tasmota uses ˋmsg.payload.ENERGY.Powerˋ which really is not CC at all. ENERGY would be a constant in the normal convention and Power would be a system variable, if I am not mistaken.

Ah, I don't know. Somehow I like to see what I created for debugging vs what I created for publishing or rather what is needed for the client to understand the message.

Other than HTML and CSS which have some of their own conventions, I would rarely care whether the system created a name or I did. By convention in JavaScript, variables and function/method names start with a lower-case letter and most people stick with lowerCC. Constants are all upper case and Class names start with upper case so are Upper CC.

Just be consistent and don't worry too much - is my advice :slight_smile: Oh, and don't over shorten variables. I've always learned that code will be read vastly more times than it will be edited and by many more people than necessarily just developers. So keep it clear.

The system creates very few properties, payload, topic, _msg_id. I can't immediately think of any others.

Tasmota does not use that, it knows nothing about node red messages. A device running Tasmota may publish to the topic "ENERGY.Power", but that is nothing to do with node red or javascript. If you subscribe to that topic in node red then that string appears as a value in msg.topic. If you choose to use that as a property name that is up to you.

I don't know what you mean by 'created for debugging' or by 'what is needed for the client to understand the message.

Hi @AleXSR700 Alex,

Yesterday I stumbled on a very similar issue you had and spent half a day looking for the elegant solution, tested JSonata, tried different javascripts, etc, etc, but nothing worked well enough, or wasn't elegant :smile: And looks like I am using a similar setup to yours - few Mi reflashed temp/humidity sensors (ATC), some Flora plant sensors, some low temperature sensors from other providers (can't remember exact brandname), as well as ESP32 with Tasmota and tasmota-blerry (GitHub - tony-fav/tasmota-blerry). So my JSON payloads looked very similar and it had part of the MAC address incorporated into the message attribute as well as single msg would have data from a few sensors. So after countless hours :slight_smile: I guess I found a solution that works really nice, looks absolutely simple, and even notifies me by sending a Telegram message if some new BT sensor appears in near proximity advertising any data. And the solution was to split these messages using Split node! After that, I can use a Switch node where I just route messages to different outputs using MAC address of each sensor. There is my flow, just change MAC addresses at the Split node and it should be good to go!

[
    {
        "id": "52b2a545b72cfa71",
        "type": "tab",
        "label": "BT playground",
        "disabled": false,
        "info": ""
    },
    {
        "id": "04e1de72fcd923c9",
        "type": "mqtt in",
        "z": "52b2a545b72cfa71",
        "name": "",
        "topic": "tele/ESP32_TTGO/SENSOR",
        "qos": "2",
        "datatype": "auto",
        "broker": "e48f09ae03fedc14",
        "nl": false,
        "rap": true,
        "rh": 0,
        "x": 180,
        "y": 360,
        "wires": [
            [
                "4b5cdbfc0e4aa168"
            ]
        ]
    },
    {
        "id": "4b5cdbfc0e4aa168",
        "type": "json",
        "z": "52b2a545b72cfa71",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 130,
        "y": 420,
        "wires": [
            [
                "681534a78b9adc5e"
            ]
        ]
    },
    {
        "id": "681534a78b9adc5e",
        "type": "split",
        "z": "52b2a545b72cfa71",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 270,
        "y": 420,
        "wires": [
            [
                "e5a77bf21953892c"
            ]
        ]
    },
    {
        "id": "32486456ea455ed3",
        "type": "switch",
        "z": "52b2a545b72cfa71",
        "name": "MAC",
        "property": "payload.mac",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "a4c138ff28a3",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c1386897d4",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "c47c8d6d5f6a",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c13848693f",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c1387d88b3",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c138ba35d5",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c138743a83",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c138957b93",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c138861f45",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "c47c8d6d614e",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "a4c138cce2c4",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 12,
        "x": 550,
        "y": 420,
        "wires": [
            [
                "4c36bebd1fb7117a"
            ],
            [
                "084e113f9cf70f54"
            ],
            [
                "d4d41c4f1837a37e"
            ],
            [
                "47aad4e57787631d"
            ],
            [
                "805c966f49cbb098"
            ],
            [
                "5e36a488f2e45872"
            ],
            [
                "f9e6a5b9858ed54e"
            ],
            [
                "3daec7313e6d86c1"
            ],
            [
                "9790c2af543dd33e"
            ],
            [
                "09dfe887802b3db9"
            ],
            [
                "de3801a43ae74740"
            ],
            [
                "2101bf4b50b16521"
            ]
        ]
    },
    {
        "id": "4c36bebd1fb7117a",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c138ff28a3",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 220,
        "wires": [],
        "icon": "font-awesome/fa-terminal"
    },
    {
        "id": "084e113f9cf70f54",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c1386897d4",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 260,
        "wires": []
    },
    {
        "id": "d4d41c4f1837a37e",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "c47c8d6d5f6a",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 300,
        "wires": []
    },
    {
        "id": "47aad4e57787631d",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c13848693f",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 340,
        "wires": []
    },
    {
        "id": "805c966f49cbb098",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c1387d88b3",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 380,
        "wires": []
    },
    {
        "id": "5e36a488f2e45872",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c138ba35d5",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 420,
        "wires": []
    },
    {
        "id": "f9e6a5b9858ed54e",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c138743a83",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 460,
        "wires": []
    },
    {
        "id": "3daec7313e6d86c1",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c138957b93",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 500,
        "wires": []
    },
    {
        "id": "9790c2af543dd33e",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c138861f45",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 540,
        "wires": []
    },
    {
        "id": "09dfe887802b3db9",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "c47c8d6d614e",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 580,
        "wires": []
    },
    {
        "id": "de3801a43ae74740",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "a4c138cce2c4",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 620,
        "wires": []
    },
    {
        "id": "e5a77bf21953892c",
        "type": "function",
        "z": "52b2a545b72cfa71",
        "name": "Filter",
        "func": "if (msg.payload != \"C\") {\n    return msg;}\nelse {\n    return null;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 410,
        "y": 420,
        "wires": [
            [
                "32486456ea455ed3"
            ]
        ]
    },
    {
        "id": "ba5ad095c774f057",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "Time",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 870,
        "y": 60,
        "wires": []
    },
    {
        "id": "2101bf4b50b16521",
        "type": "switch",
        "z": "52b2a545b72cfa71",
        "name": "non MAC",
        "property": "parts.key",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "Time",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "ANALOG",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 3,
        "x": 720,
        "y": 100,
        "wires": [
            [
                "ba5ad095c774f057"
            ],
            [
                "8a11aa18418b980e"
            ],
            [
                "480f31ca3b8cb9f7",
                "a1ee28e00882e162"
            ]
        ]
    },
    {
        "id": "8a11aa18418b980e",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "Range1",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 880,
        "y": 100,
        "wires": []
    },
    {
        "id": "480f31ca3b8cb9f7",
        "type": "debug",
        "z": "52b2a545b72cfa71",
        "name": "Unknown",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 880,
        "y": 140,
        "wires": []
    },
    {
        "id": "546f7588d1738427",
        "type": "telegram sender",
        "z": "52b2a545b72cfa71",
        "name": "New BT Device",
        "bot": "XXX",
        "haserroroutput": false,
        "outputs": 1,
        "x": 900,
        "y": 180,
        "wires": [
            []
        ]
    },
    {
        "id": "a1ee28e00882e162",
        "type": "function",
        "z": "52b2a545b72cfa71",
        "name": "Format",
        "func": "payload = {\n    chatId:XXX,\n    type:\"message\",\n    content: \"New BT device discovered\"\n};\n\nreturn {payload};\n\n/*\nhi= \"New BT device discovered \";\npayload={chatId:XXX,\ntype:\"message\",\ncontent: hi\n};\nreturn {payload};\n*/",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 740,
        "y": 180,
        "wires": [
            [
                "546f7588d1738427"
            ]
        ]
    },
    {
        "id": "XXX",
        "type": "mqtt-broker",
        "name": "Brain",
        "broker": "123.123.123.123",
        "port": "1883",
        "tls": "",
        "clientid": "",
        "usetls": false,
        "protocolVersion": "5",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "sessionExpiry": ""
    },
    {
        "id": "XXXXX",
        "type": "telegram bot",
        "botname": "New BT Device",
        "usernames": "",
        "chatids": "",
        "baseapiurl": "",
        "updatemode": "polling",
        "pollinterval": "300",
        "usesocks": false,
        "sockshost": "",
        "socksprotocol": "socks5",
        "socksport": "6667",
        "socksusername": "anonymous",
        "sockspassword": "",
        "bothost": "",
        "botpath": "",
        "localbotport": "8443",
        "publicbotport": "8443",
        "privatekey": "",
        "certificate": "",
        "useselfsignedcertificate": false,
        "sslterminated": false,
        "verboselogging": false
    }
]
1 Like

Sorry for the late reply. I was on a business trip and then on vacation (I must have overlooked the subscription e-mail during one of the two).

I am trying to. I still catch myself being inconsistent now and then. And then I fix it to match the rest of my code. :slight_smile:

Sorry, yes, you are right. My phrasing was incorrect.

Enough for me, because I also only create 2-3 of my own, so if all are lower case, then I will not immediately see which is mine. If mine are PascalCase, then I will know immediately :slight_smile:

Those additional msg properties show me which parameter causes the msg return and gives me other information as well. So I can perform a first plausibility check (mini-debug) before turing on lots of node.warn.

Cool! Thank you for sharing :slight_smile:
I will give it a go as soon as I have my current issue fixed :slight_smile: