Dynamically editing URL message content using a function

Hello everyone, I have a flow that is supposed to send me a WhatsApp message via "CallMeBot" when there is an inequality between two nodes
But in practice I can't get it to work even though I checked the API KEY and it works, and the join node also outputs an array Something in the function doesn't work for me....


[
    {
        "id": "node1",
        "type": "inject",
        "z": "flow1",
        "name": "Node 1 Value",
        "props": [
            {
                "p": "payload",
                "v": "{\"name\": \"Sensor A\", \"value\": 50}",
                "vt": "json"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "wires": [["joinNode"]]
    },
    {
        "id": "node2",
        "type": "inject",
        "z": "flow1",
        "name": "Node 2 Value",
        "props": [
            {
                "p": "payload",
                "v": "{\"name\": \"Sensor B\", \"value\": 40}",
                "vt": "json"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "wires": [["joinNode"]]
    },
    {
        "id": "joinNode",
        "type": "join",
        "z": "flow1",
        "name": "Join Sensor Data",
        "mode": "custom",
        "build": "array",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "timeout": "",
        "count": "2",
        "wires": [["functionNode"]]
    },
    {
        "id": "functionNode",
        "type": "function",
        "z": "flow1",
        "name": "Compare & Alert",
        "func": "let node1 = msg.payload[0];\nlet node2 = msg.payload[1];\n\nlet node1Value = node1.value;\nlet node2Value = node2.value;\n\nlet node1Name = node1.name || \"Node 1\";\nlet node2Name = node2.name || \"Node 2\";\n\nlet currentDifference = Math.abs(node1Value - node2Value);\nlet threshold = 10;\nlet previousDifference = context.get(\"previousDifference\") || currentDifference;\nlet differenceChange = Math.abs(currentDifference - previousDifference);\n\nif (differenceChange >= threshold) {\n    let alertMessage = `āš ļø Alert! Significant change detected!\\nšŸ“ Node: ${node1Name} vs. ${node2Name}\\nšŸ”¢ Previous Difference: ${previousDifference}\\nšŸ”¢ Current Difference: ${currentDifference}\\nšŸ“‰ Change: ${differenceChange}`;\n    \n    msg.payload = {\n        url: \"https://api.callmebot.com/whatsapp.php?phone=+1234567890&text=\" + encodeURIComponent(alertMessage) + \"&apikey=YOUR_API_KEY\",\n        method: \"GET\"\n    };\n    \n    context.set(\"previousDifference\", currentDifference);\n    return msg;\n}\nreturn null;",
        "outputs": 1,
        "noerr": 0,
        "wires": [["httpRequestNode"]]
    },
    {
        "id": "httpRequestNode",
        "type": "http request",
        "z": "flow1",
        "name": "Send CallMeBot Alert",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "query",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "x": 500,
        "y": 200,
        "wires": [["debugNode"]]
    },
    {
        "id": "debugNode",
        "type": "debug",
        "z": "flow1",
        "name": "Debug Response",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 700,
        "y": 200,
        "wires": []
    }
]

Hi, welcome to the forum,

In your function you send

    msg.payload = {
        url: "https://api.callmebot.com/whatsapp.php?phone=+1234567890&text=" + encodeURIComponent(alertMessage) + "&apikey=YOUR_API_KEY",
        method: "GET"
    };

That is not correct. The built in help does not explicitly say that the inputs are or are not part of payload so I can understand your confusion but the answer is...

    msg.url = "https://blah-blah",
    msg.method = ... etc
    msg.headers = ... etc
1 Like

Hi Stephen, thank you for your help. I made this correction, but it still doesn't solve my problem...
What bothers me is the fact that the debug node after the function doesn't output anything.

 msg.url = "https://api.callmebot.com/whatsapp.php?phone=972587202215&text=" + encodeURIComponent(alertMessage) + "&apikey = 1201647" ,
 msg.method = "GET",

did you delete the return msg from the end? Thats how the msg is passed to the next node.

https://nodered.org/docs/user-guide/writing-functions

Now I see that the "return msg" was before the brackets
I fixed it, and now the Http node gives me a debug like this "No url specified"
Including the latest function

let node1 = msg.payload[0];
let node2 = msg.payload[1];

let node1Value = node1.value;
let node2Value = node2.value;

let node1Name = node1.name || "Node 1";
let node2Name = node2.name || "Node 2";

let currentDifference = Math.abs(node1Value - node2Value);
let threshold = 9;
let previousDifference = context.get("previousDifference") || currentDifference;
let differenceChange = Math.abs(currentDifference - previousDifference);

 if (differenceChange >= threshold) {
    let alertMessage = " Alert! Significant change detected!\n Node: ${node1Name} vs. ${node2Name}\n Previous Difference: ${previousDifference}\n Current Difference: ${currentDifference}\n Change: ${differenceChange}";
    msg.url = "https://api.callmebot.com/whatsapp.php?phone=972587202215&text=" + encodeURIComponent(alertMessage) + "&apikey = 1201647" ,
    msg.method = "GET",
  
    
    context.set("previousDifference", currentDifference);
   
 } 
return msg;

Did the debug contain msg.url? (you might need to set the debug to "Show complete Message"

At a guess, differenceChange >= threshold was NOT true.

Try adding debug statemenets to your code to understand why

node.warn({differenceChange, threshold})

if (differenceChange >= threshold) {
    let alertMessage = " Alert! Significant change detected!\n Node: ${node1Name} vs. ${node2Name}\n Previous Difference: ${previousDifference}\n Current Difference: ${currentDifference}\n Change: ${differenceChange}";
    msg.url = "https://api.callmebot.com/whatsapp.php?phone=972587202215&text=" + encodeURIComponent(alertMessage) + "&apikey = 1201647" ,
    msg.method = "GET",
    context.set("previousDifference", currentDifference);   
 }  else {
    node.warn("differenceChange is NOT >= threshold")
 } 


Lastly, you probably dont want to send the msg to the REQUEST if the URL is not set so move your return inside of the if OR use a switch node AFTER the function to check that msg.url is a string.

e.g.

node.warn({differenceChange, threshold})

if (differenceChange >= threshold) {
    let alertMessage = " Alert! Significant change detected!\n Node: ${node1Name} vs. ${node2Name}\n Previous Difference: ${previousDifference}\n Current Difference: ${currentDifference}\n Change: ${differenceChange}";
    msg.url = "https://api.callmebot.com/whatsapp.php?phone=972587202215&text=" + encodeURIComponent(alertMessage) + "&apikey = 1201647" ,
    msg.method = "GET",
    context.set("previousDifference", currentDifference);   
    return msg // <<<<<< Return the msg - pass it to the next node
 }  else {
    node.warn("differenceChange is NOT >= threshold")
    return null // <<<<<< STOP THE FLOW - dont pass it to the next node
 }

Just to point out that there's already a filter node to do precisely that - only pass on a message if a value differs enough from the previous value.

Not everything has to be coded in javascript :slightly_smiling_face: