Help with routing messages based on unique identifiers

Hi all,

Looking for some help in routing messages. I have a function node that is manipulating data pulled from an API every 60 seconds and doing some if/else statements to determine output and calculate when a relay should close or open. Once a condition is met the message is routed to trigger either relay A or B. If there is second concurrent event and relay B is triggered then relay C triggers. Relay A will only trigger on a certain program. Whereas relays B&C can be triggered concurrently. The issue I'm running into is once the first event ends on relay B, the second event "moves" from relay C to relay B. The events all have a unique ID associated with them and I'm thinking I can use that to route the message but not really sure how to implement it

Test flow below to inject some values into the function node.

[
    {
        "id": "831a451fa9d84779",
        "type": "tab",
        "label": "Flow 2",
        "disabled": false,
        "info": ""
    },
    {
        "id": "c9f6bc2d8b2f9ec2",
        "type": "inject",
        "z": "831a451fa9d84779",
        "name": "Test Event 2 Start",
        "props": [
            {
                "p": "payload.start2",
                "v": "1661431320000",
                "vt": "num"
            },
            {
                "p": "payload.end2",
                "v": "1661608000000",
                "vt": "num"
            },
            {
                "p": "payload.program2",
                "v": "DD",
                "vt": "str"
            },
            {
                "p": "payload.EventID2",
                "v": "10098",
                "vt": "num"
            },
            {
                "p": "payload.start3",
                "v": "",
                "vt": "str"
            },
            {
                "p": "payload.end3",
                "v": "",
                "vt": "str"
            },
            {
                "p": "payload.program3",
                "v": "",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 310,
        "y": 300,
        "wires": [
            [
                "0eafebad2a3b3ac0"
            ]
        ]
    },
    {
        "id": "5d147fbb54b3c9d3",
        "type": "debug",
        "z": "831a451fa9d84779",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "trig",
        "targetType": "msg",
        "statusVal": "payload.program2",
        "statusType": "auto",
        "x": 800,
        "y": 280,
        "wires": []
    },
    {
        "id": "c29ed9ffc09a4d48",
        "type": "debug",
        "z": "831a451fa9d84779",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "trig2",
        "targetType": "msg",
        "statusVal": "payload.program2",
        "statusType": "auto",
        "x": 800,
        "y": 340,
        "wires": []
    },
    {
        "id": "cc5cfc9f021caaae",
        "type": "debug",
        "z": "831a451fa9d84779",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "trig3",
        "targetType": "msg",
        "statusVal": "payload.program2",
        "statusType": "auto",
        "x": 800,
        "y": 400,
        "wires": []
    },
    {
        "id": "c916c60f52392d5d",
        "type": "inject",
        "z": "831a451fa9d84779",
        "name": "Both Events End",
        "props": [
            {
                "p": "payload.start2",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.end2",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.program2",
                "v": "",
                "vt": "str"
            },
            {
                "p": "payload.EventID2",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.start3",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.end3",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.program3",
                "v": "",
                "vt": "str"
            },
            {
                "p": "payload.EventID3",
                "v": "",
                "vt": "num"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 300,
        "y": 420,
        "wires": [
            [
                "0eafebad2a3b3ac0"
            ]
        ]
    },
    {
        "id": "0eafebad2a3b3ac0",
        "type": "function",
        "z": "831a451fa9d84779",
        "name": "Test Func",
        "func": "// Variable for UTC conversion\nvar UTC = \"UTC\"\nvar TimeString1 = msg.payload.start\nvar TimeString2 = msg.payload.start2\nvar TimeString3 = msg.payload.start3\n\nmsg.trig = msg.payload.trig\nmsg.trig2 = msg.payload.trig2\nmsg.trig3 = msg.payload.trig3\n\n//EPOCH Conversion\nmsg.payload.currentTime = new Date().getTime()\n\n\n//input 1 PRD\nif (typeof msg.payload.start == 'undefined') {\n    msg.payload.start = 32524027790000;\n} else {\n    msg.payload.start = msg.payload.start\n    msg.payload.start = TimeString1.concat(\" \", UTC)\n}\n\nmsg.payload.start = new Date(msg.payload.start).getTime()\nmsg.payload.startconv = msg.payload.start - (24 * 60 * 60 * 1000);\nmsg.payload.end = new Date(msg.payload.end).getTime()\n\n//input 2 DD\nif (typeof msg.payload.start2 == 'undefined') {\n    msg.payload.start2 = 32524027790000;\n} else {\n    msg.payload.start2 = msg.payload.start2\n    // msg.payload.start2 = TimeString2.concat(\" \", UTC)\n}\n\nmsg.payload.start2 = new Date(msg.payload.start2).getTime()\nmsg.payload.startconv2 = msg.payload.start2 - (24*60*60*1000);\nmsg.payload.end2 = new Date(msg.payload.end2).getTime()\n\n// input 3 DD(extra)\nif (typeof msg.payload.start3 == 'undefined') {\n    msg.payload.start3 = 32524027790000;\n} else {\n    msg.payload.start3 = msg.payload.start2\n    // msg.payload.start3 = TimeString3.concat(\" \", UTC)\n}\n\nmsg.payload.start3 = new Date(msg.payload.start3).getTime()\nmsg.payload.startconv3 = msg.payload.start3 - (24 * 60 * 60 * 1000);\nmsg.payload.end3 = new Date(msg.payload.end3).getTime()\n\n//Account for null objects\nif (typeof msg.payload.EventID1 == 'undefined') {\n    msg.payload.EventID1 = 0\n} else {\n    msg.payload.EventID1 = msg.payload.EventID1\n}\nif (typeof msg.payload.EventID2 == 'undefined') {\n    msg.payload.EventID2 = 0\n} else {\n    msg.payload.EventID2 = msg.payload.EventID2\n}\nif (typeof msg.payload.EventID3 == 'undefined') {\n    msg.payload.EventID3 = 0\n} else {msg.payload.EventID3 = msg.payload.EventID3\n}\n//Event trigger logic\nif (msg.payload.program == \"PRD\" || msg.payload.program2 == \"PRD\" || msg.payload.program3 == \"PRD\") {\n    msg.trig = 1;\n} else {\n    msg.trig = 0;\n}\nif (msg.payload.currentTime > msg.payload.startconv && msg.payload.program == \"DD\" ||\n    msg.payload.currentTime > msg.payload.startconv2 && msg.payload.program2 == \"DD\" ||\n    msg.payload.currentTime > msg.payload.startconv3 && msg.payload.program3 == \"DD\") {\n    msg.trig2 = 1;\n} else {\n    msg.trig2 = 0;\n}\nif (msg.payload.currentTime > msg.payload.startconv && msg.payload.program == \"DD\" && msg.trig2 == 1 && msg.payload.EventID2 != 0 ||\n    msg.payload.currentTime > msg.payload.startconv2 && msg.payload.program2 == \"DD\" && msg.trig2 == 1 && msg.payload.EventID3 != 0||\n    msg.payload.currentTime > msg.payload.startconv3 && msg.payload.program3 == \"DD\" && msg.trig2 == 1 && msg.payload.EventID1 != 0) {\n    msg.trig3 = 1;\n} else {\n    msg.trig3 = 0;\n}\nreturn msg;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 560,
        "y": 340,
        "wires": [
            [
                "5d147fbb54b3c9d3",
                "c29ed9ffc09a4d48",
                "cc5cfc9f021caaae",
                "dfc9b8feb229d577"
            ]
        ]
    },
    {
        "id": "dfc9b8feb229d577",
        "type": "debug",
        "z": "831a451fa9d84779",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload.start2",
        "statusType": "auto",
        "x": 810,
        "y": 460,
        "wires": []
    },
    {
        "id": "27636da3ca968676",
        "type": "inject",
        "z": "831a451fa9d84779",
        "name": "Test Event 2 & 3 Start",
        "props": [
            {
                "p": "payload.start2",
                "v": "1661431320000",
                "vt": "num"
            },
            {
                "p": "payload.end2",
                "v": "1961608000000",
                "vt": "num"
            },
            {
                "p": "payload.program2",
                "v": "DD",
                "vt": "str"
            },
            {
                "p": "payload.EventID2",
                "v": "10098",
                "vt": "num"
            },
            {
                "p": "payload.start3",
                "v": "1962066881",
                "vt": "str"
            },
            {
                "p": "payload.end3",
                "v": "1962099999",
                "vt": "str"
            },
            {
                "p": "payload.program3",
                "v": "DD",
                "vt": "str"
            },
            {
                "p": "payload.EventID3",
                "v": "12345",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 320,
        "y": 340,
        "wires": [
            [
                "0eafebad2a3b3ac0"
            ]
        ]
    },
    {
        "id": "54236686933e9762",
        "type": "inject",
        "z": "831a451fa9d84779",
        "name": "Test Event 2 End & 3 Start",
        "props": [
            {
                "p": "payload.start2",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.end2",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.program2",
                "v": "",
                "vt": "str"
            },
            {
                "p": "payload.EventID2",
                "v": "",
                "vt": "num"
            },
            {
                "p": "payload.start3",
                "v": "1962066881",
                "vt": "str"
            },
            {
                "p": "payload.end3",
                "v": "1962099999",
                "vt": "str"
            },
            {
                "p": "payload.program3",
                "v": "DD",
                "vt": "str"
            },
            {
                "p": "payload.EventID3",
                "v": "12345",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 330,
        "y": 380,
        "wires": [
            [
                "0eafebad2a3b3ac0"
            ]
        ]
    }
]

I'm just skimming as I do regular work...I'm also not very good, so I probably should shut up...
But I think your first ELSE content is overwritten. The second statement (italics) negates the first (bold).
I noticed you commented the negating line in subsequent if branches, but with nothing else previously changing msg.payload.start, it's also not needed, as it's effectively setting the content to what it already is. Might be irrelevant, but it might make debugging a little easier.
msg.payload.start = msg.payload.start
msg.payload.start = TimeString1.concat(" ", UTC)

//input 1 PRD
if (typeof msg.payload.start == 'undefined') {
    msg.payload.start = 32524027790000;
} else {
    msg.payload.start = msg.payload.start
    msg.payload.start = TimeString1.concat(" ", UTC)
}

I haven't gotten far enough to see how it will effect the rest, but if that's critical, it might be relevant.

If your start msg is always supposed to be time or a number, you can also do a check for isNaN, rather than specifically 'undefined', as it may somehow be accidentally converted to a string somewhere, and thus will be defined and satisfy the If, but is not what you're looking for. Also, I just learned isNaN and want to use it more... :smiley:

//input 1 PRD
if (isNaN(msg.payload.start)) {
    msg.payload.start = 32524027790000;
}

What exactly is the purpose of all of that messing about with times? The incoming times appear to be javascript timestamps already, so all those convoluted operations seem very odd.

I have to offset the start time by 24 hours, which is why I'm converting them to a epoch timestamp, then applying the logic. In this flow I just put the epoch time stamp in there.

Just want to stress...I'm not a programmer, so I may be suggesting things programmers find unhelpful, so take my advice with a shaker of salt.

One thing that might be helpful is to break up the test conditions. This is a really big bite to chew and debug:

if (msg.payload.currentTime > msg.payload.startconv && msg.payload.program == "DD" && msg.trig2 == 1 && msg.payload.EventID2 != 0 ||
    msg.payload.currentTime > msg.payload.startconv2 && msg.payload.program2 == "DD" && msg.trig2 == 1 && msg.payload.EventID3 != 0||
    msg.payload.currentTime > msg.payload.startconv3 && msg.payload.program3 == "DD" && msg.trig2 == 1 && msg.payload.EventID1 != 0) {

It might be more letters, but rather than trying to follow the ||/OR operators, you can else-if them. I think...I mean, this works in my head and makes it a little easier to list the conditions in which trig3 should be 1.

if (msg.payload.currentTime > msg.payload.startconv && msg.payload.program == "DD" && msg.trig2 == 1 && msg.payload.EventID2 != 0) {
    msg.trig3 = 1;
} else if (msg.payload.currentTime > msg.payload.startconv2 && msg.payload.program2 == "DD" && msg.trig2 == 1 && msg.payload.EventID3 != 0){
    msg.trig3 = 1;
} else if (msg.payload.currentTime > msg.payload.startconv3 && msg.payload.program3 == "DD" && msg.trig2 == 1 && msg.payload.EventID1 != 0) {
    msg.trig3 = 1;
} else {
    msg.trig3 = 0;
}

Edit, sorry forgot to paste in the text from the editor.
Also, rather than read msg.trig2 after setting it in earlier processing, I'd probably make it a variable (IE, trig2), then set msg.trig2 = trig2 at the end. Not sure that matters much, but I'd question whether I want trig2 vulnerable to inbound messages, or if I want it explicitly set by this function.

Regarding the original objective, do you want relay C to move to relay B when B's call ends, or are you saying it does that now and you don't want it to?
I'd expect the desire to be that once a relay is activated, it stays active for the duration of the condition that activated it, but no idea what the desired result is, so just want to clarify.

In case the API is unreachable using typeof will allow for any issues to still resolve. I think isNan would cause an issue and would break.

Relay C moves to relay B currently and I don't want it to. The goal is to have Relay C hold that status.

Also appreciate you taking a look!

Got it. I have to run to a site, but will try to take another look later today.

BTW, not sure if it's relevant, but don't forget that this function will retest every condition on every cycle, so if trig2 is released while trig 3 is active, the next processing cycle will see trig3 conditions no longer apply, but trig2 conditions do, so it will release trig3 and activate trig2. Thus "moving" the active state to relay 2.
You can set and unset flow variables or context variables to make these test conditions persist through run cycles, though. That might be something to dig into right now.

1 Like

Do you mean that in the real situation they are not of the form that you show in the inject node? What form are they in then?

Correct, they are in a date/time string and I'm converting it to an epoch timestamp.

Looking into this now, might be beneficial!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.