Small engine dyno need help to reset my counter after run

Using a raspberry pi and a hall effects sensor to capture shaft rpm.
this code will give me the rpm. but after a run i need to start over with zero rpm. this couter just keepd adding the rpm every test run

My function code
counter = flow.get("counter") || 0
counter ++
flow.set("counter, counter)
msg.payload = counter
returm msg;

Welcome to the forum @dirtydredrt

I can't see how that gives you revs per minute, it looks to me as if it is counting up the total rotation.

To reset it all you need to do is to write zero to the flow variable. You can do that in a change node or in a function
flow.set("counter", 0)

Thanks Colin for the fast response. flow.set("counter", 0) works great.
First Node-red project...
Here's my plan.
Start the small 2 stroke engine (like a weed eater size) running say at 3000 rpm
Using RPI 3B, I will need to have an accurate time stamp.
This is an inertia dyno spinning a fly wheel.
Node red push a start button, have a servo to open the throttle, when the hall effects read 3000rpm start counting
run up to 13000 rpm and stop the test. servo closes the throttle.
record the time it takes to reach 13000 rpm.
I would like to be able to set the Max rpm for different tests, like 3000 to 11000 to set the expansion chamber length.
Later add torque.
Using the node red dash board i would like to be able to save each test. I have created the gauges for RPM, Graph, temperature, humidity and pressure.

Sounds like a great project.

adding flow.set("counter", 0)
I now just get a 1 on every count.
I will need a loop to count to say 1000 and end the counter.
Not sure what type of loop is needed

Post the code you now have and explain exactly what it is given and what it is supposed to do. Remember that I know virtually nothing about the what this signal you are counting represents in the real word. See this post for details of how to post code or flows - How to share code or flow json

not finding the 'Preformatted Text' icon
I can see export, will export work

It is the </> button at the top of this window where you type stuff

image

The only area where i can find </> is inside of a function node
I double click on a function node
Click on discription icon
then i see the </>

Just mark and copy the code in the normal way from the function node then start entering a reply in the forum and it is in the row of buttons along the top of the window where you type. Nothing to do with node-red, it is a forum feature.

flow.set("counter",0)
counter = flow.get("counter") || 0
counter ++
flow.set("counter", counter)
msg.payload = counter

return msg;

when i run this function it returns 1, never counts because at the of the flow.set("counter",0)
I input a signal from a hall effects into the function node.
I would like the function to start counting at 3000 counts
Then run until 13000 counts. this would complete a single run of the dyno.
Capture the time it takes the engine to rev up to 13000
it would be nice to be able to set the start rpm 3000 and the max rpm 13000 in the dash board

flow.set("counter",0)
counter = flow.get("counter") || 0
counter ++
flow.set("counter", counter)
msg.payload = counter

return msg;

when i run this function it returns 1, never counts because at the start

You said earlier that you want to run till 13000 rpm, but that is a speed, 13000 revs/min. Are you actually just counting revolutions, not rpm?

[{"id":"e9df2383.82df9","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"c2f31d17.2bc5f","type":"inject","z":"e9df2383.82df9","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":140,"wires":[["8cea1145.809d"]]},{"id":"8cea1145.809d","type":"rpi-dht22","z":"e9df2383.82df9","name":"dht11","topic":"rpi-dht22","dht":"11","pintype":"0","pin":"4","x":290,"y":140,"wires":[["f34cadf0.5a452","85e1b96a.a45e58"]]},{"id":"949b5392.57d51","type":"debug","z":"e9df2383.82df9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":260,"wires":[]},{"id":"f34cadf0.5a452","type":"function","z":"e9df2383.82df9","name":"Temperature","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":140,"wires":[["1ecc1aec.d81c35","7b80934f.fd688c"]]},{"id":"85e1b96a.a45e58","type":"function","z":"e9df2383.82df9","name":"Humidity data","func":"msg.payload = msg.humidity;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":500,"y":220,"wires":[["949b5392.57d51","b9dd181c.228368"]]},{"id":"1ecc1aec.d81c35","type":"ui_gauge","z":"e9df2383.82df9","name":"Temperature monitor","group":"9e96c901.0264f8","order":2,"width":5,"height":3,"gtype":"gage","title":"temperature","label":"deg C","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":720,"y":140,"wires":[]},{"id":"b9dd181c.228368","type":"ui_gauge","z":"e9df2383.82df9","name":"Humidity data","group":"9e96c901.0264f8","order":3,"width":5,"height":3,"gtype":"gage","title":"Humidity","label":"%","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":700,"y":220,"wires":[]},{"id":"7b80934f.fd688c","type":"debug","z":"e9df2383.82df9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":180,"wires":[]},{"id":"9cfdb189.d211b","type":"function","z":"e9df2383.82df9","name":"RPM","func":"//flow.set(\"counter\",0)\ncounter = flow.get(\"counter\") || 0\ncounter ++\nflow.set(\"counter\", counter)\nmsg.payload = counter\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":320,"wires":[["42c6bbdc.42c5c4","26186fee.63466"]],"info":"``/flow.set(\"counter\",0)\ncounter = flow.get(\"counter\") || 0\ncounter ++\nflow.set(\"counter\", counter)\nmsg.payload = counter\n\nreturn msg;\n``\n"},{"id":"547cb430.bdd5dc","type":"debug","z":"e9df2383.82df9","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":770,"y":420,"wires":[]},{"id":"26186fee.63466","type":"ui_gauge","z":"e9df2383.82df9","name":"","group":"9e96c901.0264f8","order":3,"width":0,"height":0,"gtype":"gage","title":"RPM","label":"RPM","format":"{{value}}","min":0,"max":"500","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":770,"y":320,"wires":[]},{"id":"3186801a.cd10f","type":"inject","z":"e9df2383.82df9","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":240,"wires":[["9cfdb189.d211b"]]},{"id":"42c6bbdc.42c5c4","type":"timeframerlt","z":"e9df2383.82df9","name":"","throttleType":"reset","timeLimit":"5","timeLimitType":"seconds","countLimit":"1000","byresetcountLimit":"4","x":590,"y":420,"wires":[["547cb430.bdd5dc"]]},{"id":"32f1d447.3aa4ac","type":"inject","z":"e9df2383.82df9","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"reset","payloadType":"msg","x":300,"y":440,"wires":[["42c6bbdc.42c5c4","2d12e318.927f8c"]]},{"id":"2d12e318.927f8c","type":"debug","z":"e9df2383.82df9","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":560,"y":520,"wires":[]},{"id":"9e96c901.0264f8","type":"ui_group","name":"DYNO","tab":"70eb2da0.452ad4","order":1,"disp":true,"width":"10","collapse":false},{"id":"70eb2da0.452ad4","type":"ui_tab","name":"LANGE RACING","icon":"dashboard","disabled":false,"hidden":false}]

[editied to make importable by mod]

you are correct.
I just need to know how long it takes the engine to reach from 3000 counts to 13000 counts.
The faster i get there is better for my application
Its a 52" RC unlimited hydroplane racing around an oval race track

You didn't use the </> button when posting the flow, so we can't import it, but it doesn't matter, all we are worried about is the function.
Something like this should do it

image

The top three inject nodes clear the counter and set the low and high thresholds to 3 and 10. It would be too boring to have to feed in 30000 counts to test it so I have gone for 3 and 10 instead. You can replace those with values from your dashboard to get it fully going.

The fourth Inject node simulates your sensor. The function increments the count each time and when it gets to the low threshold it saves the current time in msec, and uses node.warn() to show it in the debug pane. You can remove that statement when you are happy it is working. When the count gets to the high threshold it works out the time difference in msec and sends it on.

To test it click the top three inject nodes then the bottom one multiple times. When you get to ten it should pass on the time interval between 3 and 10.

Here is the flow which you can import to test.

[{"id":"8583a880.175fd8","type":"inject","z":"84405ff5.25fa6","name":"Sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":130,"y":1040,"wires":[["12c451d2.0c1b5e"]]},{"id":"12c451d2.0c1b5e","type":"function","z":"84405ff5.25fa6","name":"Count Revs","func":"// starts timing when counts reach high threshold\n// when high threshold is reached then passes on time difference in msec\nconst lowCount = flow.get(\"lowThreshold\")\nconst highCount = flow.get(\"highThreshold\")\ncounter = flow.get(\"counter\") || 0\ncounter++\nif (counter == lowCount) {\n    // we have hit the first threshold, remember the current time in msec\n    const now = new Date().getTime()\n    context.set(\"startTime\", now)\n    node.warn(`startTime: ${now}`)\n    msg = null      // don't send anything\n} else if (counter == highCount) {\n    const highNow = new Date().getTime()\n    // we have hit the second the second threshold, work out the time difference\n    msg.payload = highNow - context.get(\"startTime\")\n} else {\n    // neither threshold so do nothing\n    msg = null\n}\nflow.set(\"counter\", counter)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":300,"y":1040,"wires":[["4ee39ede.8ba78"]]},{"id":"4ee39ede.8ba78","type":"debug","z":"84405ff5.25fa6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":370,"y":1140,"wires":[]},{"id":"acc6affc.931e5","type":"inject","z":"84405ff5.25fa6","name":"Clear counter","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":130,"y":860,"wires":[["9ef54e44.c8a648"]]},{"id":"9ef54e44.c8a648","type":"change","z":"84405ff5.25fa6","name":"","rules":[{"t":"set","p":"counter","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":860,"wires":[[]]},{"id":"aeac78ed.2ba2b8","type":"inject","z":"84405ff5.25fa6","name":"Set low threshold 3","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"3","payloadType":"num","x":160,"y":920,"wires":[["7b305d4f.9f4bcc"]]},{"id":"7b305d4f.9f4bcc","type":"change","z":"84405ff5.25fa6","name":"","rules":[{"t":"set","p":"lowThreshold","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":920,"wires":[[]]},{"id":"62f6b65a.24a0d8","type":"inject","z":"84405ff5.25fa6","name":"Set high threshold 10","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"10","payloadType":"num","x":170,"y":980,"wires":[["e20c4f0f.2dd8c"]]},{"id":"e20c4f0f.2dd8c","type":"change","z":"84405ff5.25fa6","name":"","rules":[{"t":"set","p":"highThreshold","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":980,"wires":[[]]}]

Thanks Colin for your help.
May day is done. i will test Monday

I like this version better, avoiding the use of flow context. It uses topic values to pass reset, low and high thresholds into the function which makes the data flow clearer. Make sure you set the topics up in the dashboard nodes that reset the counter and set the threshold values.

[{"id":"8583a880.175fd8","type":"inject","z":"84405ff5.25fa6","name":"Sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":130,"y":1100,"wires":[["12c451d2.0c1b5e"]]},{"id":"12c451d2.0c1b5e","type":"function","z":"84405ff5.25fa6","name":"Count Revs","func":"// starts timing when counts reach low threshold\n// when high threshold is reached then passes on time difference in msec\n// Count can be reset by passing a message with topic \"reset\"\n// Set low and high thresholds by passing in topic of \"lowThreshold\" or \"highThreshold\"\n// with value in payload.\n// Any other topic is assumed to be a sensor input\n\nswitch(msg.topic) {\n    case \"reset\":\n        // reset counter\n        context.set(\"counter\", 0)\n        msg = null\n        break;\n        \n    case \"lowThreshold\":\n        context.set(\"lowThreshold\", msg.payload)\n        msg = null\n        break;\n        \n    case \"highThreshold\":\n        context.set(\"highThreshold\", msg.payload)\n        msg = null\n        break;\n        \n    default:\n        // sensor input\n        handleSensor()\n        break;\n}\nreturn msg\n\nfunction handleSensor() {\n    const lowThreshold = context.get(\"lowThreshold\")\n    const highThreshold = context.get(\"highThreshold\")\n    counter = context.get(\"counter\") || 0\n    counter++\n    if (counter == lowThreshold) {\n        // we have hit the first threshold, remember the current time in msec\n        const now = new Date().getTime()\n        context.set(\"startTime\", now)\n        node.warn(`startTime: ${now}`)\n        msg = null      // don't send anything\n    } else if (counter == highThreshold) {\n        const highNow = new Date().getTime()\n        // we have hit the second threshold, work out the time difference\n        msg.payload = highNow - context.get(\"startTime\")\n    } else {\n        // neither threshold so do nothing\n        msg = null\n    }\n    context.set(\"counter\", counter)\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":430,"y":1100,"wires":[["4ee39ede.8ba78"]]},{"id":"4ee39ede.8ba78","type":"debug","z":"84405ff5.25fa6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":370,"y":1200,"wires":[]},{"id":"acc6affc.931e5","type":"inject","z":"84405ff5.25fa6","name":"Clear counter","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reset","x":210,"y":860,"wires":[["12c451d2.0c1b5e"]]},{"id":"aeac78ed.2ba2b8","type":"inject","z":"84405ff5.25fa6","name":"Set low threshold 3","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"lowThreshold","payload":"3","payloadType":"num","x":160,"y":920,"wires":[["12c451d2.0c1b5e"]]},{"id":"62f6b65a.24a0d8","type":"inject","z":"84405ff5.25fa6","name":"Set high threshold 10","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"highThreshold","payload":"10","payloadType":"num","x":140,"y":980,"wires":[["12c451d2.0c1b5e"]]}]
[{"id":"9f4b9f9e.69796","type":"rpi-gpio in","z":"c502d54b.368d98","name":"","pin":"11","intype":"tri","debounce":"25","read":false,"x":250,"y":360,"wires":[["12c451d2.0c1b5e"]]}]

I have it up and running but im getting a crazy number when i click on the input like 1305. I just click on the input about 10 times. I would think after 3 counts it should start and the show around 7