Receiving input to function node while the function is running

I want to receive input to a function that is already running without restarting the function, and I want this to be able to happen an arbitrary amount of times during the functions execution.

I tried using the flow context to set a variable in a function f1, and then reading it asynchronously in my function f2. It didnt work as I wanted; when I try to read the variable it will read it right away and not wait for it to be initialized or created, despite the fact that I delete the variable with a change node every time I retry.

Any ideas?

Hi, by the sounds of it, you are looping or running a constant process in a function node? this is not the ideal (events based) methodology that node-red is most commonly used for.

Perhaps if you share a commented / sanitised snipped of your flow we can help more.

to export flow, select the NODEs to export, press CTRL+E, copy to clipboard then paste into your reply between three back ticks like this...

code paste here

Thanks for the fast answere. I am using one function node that uses several JS-timers and timeouts (setTimeout() and setInterval()) to create a "long lived" simulation.

This is a snippet:

    generateForkliftSpeedId = setInterval(generateForkliftSpeed, telemetryIntervalMoving);
    setTimeout(function() {
        clearInterval(generateForkliftSpeedId); //Stop speed generator.
        generateForksRisingTelemetryId = setInterval(generateForksRisingTelemetry, 
    }, timeToMove/2); //Forklift stopping to load.

This is the whole function code:

[{"id":"425c9e02.96f3","type":"function","z":"3a02ebf.434c414","name":"GenerateTelemetryLaglyftare0","func":"var timeToComplete = msg.payload.timeToComplete * 1000; //ms\nvar timeToMove = timeToComplete - 1000; //ms\nvar telemetryIntervalMoving = 1000;\nvar telemetryIntervalMovingForks=1000;\nvar palletSrcHeight = msg.payload.palletSrcHeight;\nvar palletWeight = msg.payload.palletWeight;\n\nvar forkliftSpeed, forkSpeed = 1, forksIncline=0, forkLoadWeight=0, forkHeightPos = 0, forkliftTippingPoint=12.5;\nvar forkliftSpeedUpperBound = 5; // m/s\nvar forkliftSpeedLowerBound = 1;\nvar tippingRate=4;//4 degrees per unit time.\n\nvar weightCapacity = 600;\nvar heightCapacity=5;\nvar forkliftHeightCapacityBreakingPoint=(weightCapacity/palletWeight)*heightCapacity;//Point where the forklifts start to lean.\nnode.send({payload:forkliftHeightCapacityBreakingPoint});\n\nvar generateForkliftSpeedId, generateForksRisingTelemetryId, generateForkliftLoweringTelemetryId;\n\nfunction generateForkliftSpeed(){\n    forkliftSpeed = Math.floor(Math.random() * (forkliftSpeedUpperBound - forkliftSpeedLowerBound + 1)) + forkliftSpeedLowerBound;\n    var testMsg = {};\n    testMsg.payload = \"Speed: \" + forkliftSpeed;\n    node.send(testMsg);\n}\n\nfunction loadPalletAndStartLoweringForks(){\n    forkHeightPos=palletSrcHeight;\n    clearInterval(generateForksRisingTelemetryId); //Stop lifting forks.\n    forkLoadWeight=palletWeight;\n    generateForkliftLoweringTelemetryId = setInterval(function(){generateForkliftLoweringTelemetry(true)}, telemetryIntervalMovingForks);\n}\n\nfunction generateForksRisingTelemetry(){\n    forkHeightPos += forkSpeed*(telemetryIntervalMovingForks/1000);\n    \n    //Conditional stop.\n    if (forkHeightPos>=heightCapacity && palletSrcHeight>heightCapacity){\n        //Forks above capacity, capacity can NOT handle the height.\n        forkHeightPos=heightCapacity;\n        clearInterval(generateForksRisingTelemetryId); //Stop lifting forks.\n        generateForkliftLoweringTelemetryId = setInterval(function(){generateForkliftLoweringTelemetry(false)}, telemetryIntervalMovingForks);\n    }else if (forkHeightPos>=palletSrcHeight && palletSrcHeight<heightCapacity){\n        //Forks above height, capacity can handle the height.\n       loadPalletAndStartLoweringForks();\n    }else if (forkHeightPos>=heightCapacity && heightCapacity==palletSrcHeight){\n        //Forks above capacity and height, which are the same. Capacity can handle the height.\n        loadPalletAndStartLoweringForks();\n    }\n    node.send({payload:{forkHeight: forkHeightPos, forkCap: heightCapacity, itemHeight: palletSrcHeight}});\n}\n\n/*\n* If the truck doesn't have a pallet, it lowers its forks to 0.\n* If the truck has a pallet that weighs to much for the truck\n* it will lower the pallet to the appropriate height if it gets\n* a command from the GGC. If the pallet weights to much the forklift\n* will start to lean. However, if the truck\n* can handle the weight at the palletSrcHeight, it will keep\n* it there and the function does nothing.\n*/\nfunction generateForkliftLoweringTelemetry(hasPallet){\n    \n    if (!hasPallet){\n        forkHeightPos -= forkSpeed*(telemetryIntervalMovingForks/1000); //Convert to seconds\n        //Forklift is free, report back so that the forklift can take a new job.\n        if (forkHeightPos<=0){//Adjust the forks.\n            forkHeightPos=0;//Lift forks a little.\n            clearInterval(generateForkliftLoweringTelemetryId); //Stop lowering forks.\n            node.send({payload:\"No pallet\"});\n        }\n    }else{\n        //Forklift starts to lean.\n        if (forkHeightPos>=forkliftHeightCapacityBreakingPoint){\n            forksIncline+=tippingRate;\n            node.send({payload:\"Forklift leaning\"});\n            //Forklift tipped over.\n            if (forksIncline>=forkliftTippingPoint){\n                clearInterval(generateForkliftLoweringTelemetryId); //Stop generate lowering telemetry.\n                node.send({payload:\"Forklift tipped over!\"});\n            }\n            \n        }else{\n            //Forklift keep moving to destination.\n            node.send({payload:\"Forklift moving to dest\"});\n            clearInterval(generateForkliftLoweringTelemetryId); //Stop lowering forks.\n            generateForkliftSpeedId = setInterval(generateForkliftSpeed, telemetryIntervalMoving);\n            setTimeout(function() { //Anonymous function.\n                clearInterval(generateForkliftSpeedId); //Stop speed generator.Forklift job done, report back.\n            }, timeToMove/2); //Forklift stopping to load.\n        }\n    }\n    \n    node.send({payload:forkHeightPos});\n}\n\nfunction main(){\n    flow.get('instr0', function(err, instr0){\n        if (err){\n            node.error(err, msg);\n            node.send({payload:\"ERROR\"});\n        }else{\n            switch (instr0){\n                case 0:\n                    node.send({payload:\"Instruction was 0!!!!\"});\n                    break;\n                case 1:\n                    node.send({payload:\"Lowering forks!!!!!!!!!!!!!\"});\n                    break;\n                case 2:\n                    break;\n                case 3:\n                    break;\n                default:\n                    node.send({payload:instr0});\n                    break;\n            }\n            flow.set('instr0', 0);\n        }\n    });\n    generateForkliftSpeedId = setInterval(generateForkliftSpeed, telemetryIntervalMoving);\n    setTimeout(function() { //Anonymous function.\n        clearInterval(generateForkliftSpeedId); //Stop speed generator.\n        generateForksRisingTelemetryId = setInterval(generateForksRisingTelemetry, telemetryIntervalMovingForks);\n    }, timeToMove/2); //Forklift stopping to load.\n}\n\nmain();\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1610,"y":160,"wires":[["89c570e0.ff0ec"]]}]

Yeah, as i suspected, you've written this like a procedural program - IMO, that's your issue here.

I would recommend avoid using setTimeouts/setIntervals in functions and use inject nodes etc for your timings. Pass the events with a topic name to identify the timed events into your function, picking up any changes you need beforehand to "mix in" required data into the msg object.

in fact, it looks more like a state machine I would also look at these nodes

Hope that helps.

Ah, okay, I think I understand. So for example, I trigger interval based injections when something particular happens in the flow. When you say "events with a topic name", do you really mean "messages with a topic name"?

Sure, same thing (an event is something that happens, the msg is what is sent)

Yes, that is possible, you can also use an inject node to generate periodic / timed events

the basic premise is that each node does a little bit work & you lay it all out graphically (instead of one big program in a function node. TBH, if you write a program like that, you might as well have written a straight node.js program as you wont benefit from the huge benefits of the "flow programming paradigm")

1 Like

I see, thank you!

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