Weird behavior using buttons

I'm testing some functions and using the inject option works as expected, but I need to use buttons and the behavior is strange.

When using buttons the messages are repeated and the result of the function is wrong and the counter adds up several times even with just one click.

Am I missing something?

[{"id":"d6239213f9f33d98","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"32393c49c17a1533","type":"ha-button","z":"d6239213f9f33d98","name":"teste","version":0,"debugenabled":false,"outputs":1,"entityConfig":"8849e89d9e6c9ed1","outputProperties":[],"x":250,"y":520,"wires":[["ce21d5a89db4fc2a"]]},{"id":"ce21d5a89db4fc2a","type":"function","z":"d6239213f9f33d98","name":"Gerador de comandos","func":"msg.senha = flow.get(\"senhaflow\") || {};\nvar i;\nfor (i = 0; i < msg.senha.length; i++) { msg.senha[i] = msg.senha[i] + 0x30; }\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":520,"wires":[["e294ddf47043dffd"]]},{"id":"e294ddf47043dffd","type":"debug","z":"d6239213f9f33d98","name":"Button ?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"senha","targetType":"msg","statusVal":"","statusType":"auto","x":1000,"y":520,"wires":[]},{"id":"b1e1146df5ec4324","type":"inject","z":"d6239213f9f33d98","name":"Inject Senha","props":[{"p":"senha","v":"[1,2,3,4,5,6]","vt":"bin"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":290,"y":380,"wires":[["a894df8dc67e8858"]]},{"id":"a894df8dc67e8858","type":"change","z":"d6239213f9f33d98","name":"","rules":[{"t":"set","p":"senhaflow","pt":"flow","to":"senha","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":380,"wires":[["47a8cf7a5a7ece2c"]]},{"id":"47a8cf7a5a7ece2c","type":"debug","z":"d6239213f9f33d98","name":"Inject Senha OK","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"senha","targetType":"msg","statusVal":"","statusType":"auto","x":1020,"y":380,"wires":[]},{"id":"634256b7.2d6818","type":"inject","z":"d6239213f9f33d98","name":"JSON String","props":[{"p":"payload","v":"{\"a\":1}","vt":"str"},{"p":"topic","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"a\":1}","payloadType":"str","x":650,"y":900,"wires":[["a2fe0fc8.095e1"]]},{"id":"a2fe0fc8.095e1","type":"json","z":"d6239213f9f33d98","name":"","property":"payload","action":"","pretty":false,"x":810,"y":900,"wires":[["9a4ce2b8.47698"]]},{"id":"9a4ce2b8.47698","type":"debug","z":"d6239213f9f33d98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":900,"wires":[]},{"id":"80032e2.7c92cd","type":"inject","z":"d6239213f9f33d98","name":"Object","props":[{"p":"payload","v":"{\"a\":1}","vt":"json"},{"p":"topic","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"a\":1}","payloadType":"json","x":630,"y":940,"wires":[["cd40a0f4.4f5ac"]]},{"id":"cd40a0f4.4f5ac","type":"json","z":"d6239213f9f33d98","name":"","property":"payload","action":"","pretty":false,"x":810,"y":940,"wires":[["478b4106.4fd7c"]]},{"id":"478b4106.4fd7c","type":"debug","z":"d6239213f9f33d98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":940,"wires":[]},{"id":"d4193da45aa7857b","type":"change","z":"d6239213f9f33d98","name":"","rules":[{"t":"set","p":"senha","pt":"msg","to":"senhaflow","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":440,"wires":[["8072f4c60228ec49"]]},{"id":"8072f4c60228ec49","type":"function","z":"d6239213f9f33d98","name":"Gerador de comandos","func":"msg.senha = flow.get(\"senhaflow\") || {};\nvar i;\nfor (i = 0; i < msg.senha.length; i++) { msg.senha[i] = msg.senha[i] + 0x30; }\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":440,"wires":[["c1e543183f6e03e1"]]},{"id":"ec7ef9ed7988596c","type":"inject","z":"d6239213f9f33d98","name":"Inject for loop","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":290,"y":440,"wires":[["d4193da45aa7857b"]]},{"id":"c1e543183f6e03e1","type":"debug","z":"d6239213f9f33d98","name":"Inject for loop OK","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"senha","targetType":"msg","statusVal":"","statusType":"auto","x":1030,"y":440,"wires":[]},{"id":"ec964dd4ec3d5f03","type":"ha-button","z":"d6239213f9f33d98","name":"Teste Count","version":0,"debugenabled":false,"outputs":1,"entityConfig":"ff15b2b7b6f131da","outputProperties":[],"x":270,"y":740,"wires":[["4ab66cb451cdd144"]]},{"id":"4ab66cb451cdd144","type":"counter","z":"d6239213f9f33d98","name":"","init":"0","step":"1","lower":null,"upper":null,"mode":"increment","outputs":"1","x":520,"y":740,"wires":[["a74f85d6b4803048"]]},{"id":"a74f85d6b4803048","type":"debug","z":"d6239213f9f33d98","name":"Teste Count ???","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"count","targetType":"msg","statusVal":"","statusType":"auto","x":780,"y":740,"wires":[]},{"id":"aa5f0364ed1fa230","type":"counter","z":"d6239213f9f33d98","name":"","init":"0","step":"1","lower":null,"upper":null,"mode":"increment","outputs":"1","x":520,"y":600,"wires":[["5b724edbdec978d4"]]},{"id":"5b724edbdec978d4","type":"debug","z":"d6239213f9f33d98","name":"Inject Count OK","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"count","targetType":"msg","statusVal":"","statusType":"auto","x":780,"y":600,"wires":[]},{"id":"a4086267efbe0cc2","type":"inject","z":"d6239213f9f33d98","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":270,"y":600,"wires":[["aa5f0364ed1fa230"]]},{"id":"dd1541f911e7f121","type":"inject","z":"d6239213f9f33d98","name":"Reset","props":[{"p":"reset","v":" ","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":270,"y":640,"wires":[["aa5f0364ed1fa230","4ab66cb451cdd144"]]},{"id":"8849e89d9e6c9ed1","type":"ha-entity-config","server":"33803899.487d48","deviceConfig":"","name":"teste","version":"6","entityType":"button","haConfig":[{"property":"name","value":"teste"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":true},{"id":"ff15b2b7b6f131da","type":"ha-entity-config","server":"33803899.487d48","deviceConfig":"","name":"Teste Count","version":"6","entityType":"button","haConfig":[{"property":"name","value":"Teste Count"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"33803899.487d48","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Add a debug node on the output of the button to see whether there are multiple messages coming out.

I can't test the flow as I see you are using Home Assistant nodes. Are the buttons virtual buttons on a display or real push buttons. If the latter then you may need to add some debounce to the button input. That feature is built into the node-red GPIO nodes, but I don't know about HA. If it is a debounce issue then you will see multiple messages coming from the button each time you press it.

I already tested with the button sending some msg.something, but now for test purposes the button send nothing

They are virtual buttons

Since the counter is not a standard node, lets concentrate on this bit

Does that send repeated messages from the function node?
If so then connect a debug node showing the button output, make sure nothing else is connected to the function input and show us what you see.

At least in HA it's standard :thinking:

2 messages at the button output and 10 at the function output with the wrong function calculation

Can you show us the node red startup log please. I don't know how to get that if you are using the HA addon but presumably you can find that out.

First do a reboot and make sure it still misbehaves.

This?

s6-rc: info: service s6rc-oneshot-runner: starting
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
cont-init: info: running /etc/cont-init.d/00-banner.sh
-----------------------------------------------------------
 Add-on: Node-RED
 Flow-based programming for the Internet of Things
-----------------------------------------------------------
 Add-on version: 13.5.3
 You are running the latest version of this add-on.
 System: Home Assistant OS 9.3  (aarch64 / raspberrypi4-64)
 Home Assistant Core: 2022.11.3
 Home Assistant Supervisor: 2022.10.2
-----------------------------------------------------------
 Please, share the above information when looking for help
 or support in, e.g., GitHub, forums or the Discord chat.
-----------------------------------------------------------
cont-init: info: /etc/cont-init.d/00-banner.sh exited 0
cont-init: info: running /etc/cont-init.d/01-log-level.sh
cont-init: info: /etc/cont-init.d/01-log-level.sh exited 0
cont-init: info: running /etc/cont-init.d/customizations.sh
cont-init: info: /etc/cont-init.d/customizations.sh exited 0
cont-init: info: running /etc/cont-init.d/nginx.sh
cont-init: info: /etc/cont-init.d/nginx.sh exited 0
cont-init: info: running /etc/cont-init.d/node-red.sh
patching file nodes/ui_base.html
Hunk #1 succeeded at 1164 (offset 633 lines).
up to date, audited 2 packages in 1s
found 0 vulnerabilities
cont-init: info: /etc/cont-init.d/node-red.sh exited 0
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
services-up: info: copying legacy longrun nginx (no readiness notification)
services-up: info: copying legacy longrun nodered (no readiness notification)
s6-rc: info: service legacy-services successfully started
[16:26:51] INFO: Starting Node-RED...
> start
> node $NODE_OPTIONS node_modules/node-red/red.js "--settings" "/etc/node-red/config.js"
21 Nov 16:26:55 - [info] 
Welcome to Node-RED
===================
21 Nov 16:26:55 - [info] Node-RED version: v3.0.2
21 Nov 16:26:55 - [info] Node.js  version: v16.17.1
21 Nov 16:26:55 - [info] Linux 5.15.61-v8 arm64 LE
21 Nov 16:26:56 - [info] Loading palette nodes
21 Nov 16:27:01 - [info] Dashboard version 3.2.0 started at /endpoint/ui
21 Nov 16:27:02 - [info] Settings file  : /etc/node-red/config.js
21 Nov 16:27:02 - [info] Context store  : 'default' [module=memory]
21 Nov 16:27:02 - [info] User directory : /config/node-red/
21 Nov 16:27:02 - [warn] Projects disabled : editorTheme.projects.enabled=false
21 Nov 16:27:02 - [info] Flows file     : /config/node-red/flows.json
21 Nov 16:27:02 - [warn] Encrypted credentials not found
21 Nov 16:27:02 - [info] Server now running at http://127.0.0.1:46836/
21 Nov 16:27:02 - [info] Starting flows
21 Nov 16:27:02 - [info] Started flows
[16:27:02] INFO: Starting NGinx...
21 Nov 16:27:07 - [info] [server:Home Assistant] Connecting to http://supervisor/core
21 Nov 16:27:07 - [info] [server:Home Assistant] Connected to http://supervisor/core
21 Nov 16:27:57 - [info] Stopping modified flows
21 Nov 16:27:57 - [info] Stopped modified flows
21 Nov 16:27:57 - [info] Updated flows
21 Nov 16:27:57 - [info] Starting modified flows
21 Nov 16:27:57 - [info] Started modified flows

If I restart node-red the duplicate messages stop until I edit the function. Even a blank line causes the problem to return.

And somehow my "for" is surviving button clicks. The first result after the restart is correct, after the second result it is added again

msg.password = flow.get("password") || {};
var i;
for (i = 0; i < msg.password.length; i++)
 { msg.password[i] = msg.password[i] + 0x30; }
return msg;

That should be || [] but I don't see why that would cause the problem you see.

That is because javascript uses references for addressing objects, so when you say msg.password = flow.get("password")
that effectively gives you a pointer to the password object in context and saves it in msg.password. Then when you modify the contents of msg.password it is modifying the one in context through the pointer in msg.password. To avoid that you can make a copy of the context object using
msg.password = RED.util.cloneMessage( flow.get("password") ) || []

Didn't work, same result. I'm going to need to review some logic.

A little off topic...

I have a function with the msg shown in the debug.

Is there any way to get sensor information similar to this?

What didn't work? If your function is still modifying the context value then show us what you have now.

Agreed. For a different question please start a new thread.

msg.password = RED.util.cloneMessage(flow.get("password")) || []
var i;
for (i = 0; i < msg.password.length; i++) { msg.password[i] = msg.password[i] + 0x30; }
return msg;

Each click continues to add the 0x30 from the "for" to the next result

Does it do that if you use the Inject button? If so then please export those nodes and paste them here so we can try it.

Yes, same behavior

[{"id":"32393c49c17a1533","type":"ha-button","z":"d6239213f9f33d98","name":"teste","version":0,"debugenabled":false,"outputs":1,"entityConfig":"8849e89d9e6c9ed1","outputProperties":[],"x":270,"y":180,"wires":[["ea70c9aac12e32fb","ce21d5a89db4fc2a"]]},{"id":"ce21d5a89db4fc2a","type":"function","z":"d6239213f9f33d98","name":"Gerador de comandos","func":"msg.password = RED.util.cloneMessage(flow.get(\"password\")) || []\nvar i;\nfor (i = 0; i < msg.password.length; i++) { msg.password[i] = msg.password[i] + 0x30; }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":180,"wires":[["e294ddf47043dffd"]]},{"id":"e294ddf47043dffd","type":"debug","z":"d6239213f9f33d98","name":"Button ?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1020,"y":180,"wires":[]},{"id":"b1e1146df5ec4324","type":"inject","z":"d6239213f9f33d98","name":"Inject Senha","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[1,2,3,4,5,6]","payloadType":"bin","x":290,"y":320,"wires":[["a894df8dc67e8858"]]},{"id":"a894df8dc67e8858","type":"change","z":"d6239213f9f33d98","name":"","rules":[{"t":"set","p":"password","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":320,"wires":[["47a8cf7a5a7ece2c"]]},{"id":"47a8cf7a5a7ece2c","type":"debug","z":"d6239213f9f33d98","name":"Inject Senha OK","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1020,"y":320,"wires":[]},{"id":"ea70c9aac12e32fb","type":"debug","z":"d6239213f9f33d98","name":"debug 38","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":420,"y":220,"wires":[]},{"id":"75e2115aac463d61","type":"inject","z":"d6239213f9f33d98","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":270,"y":120,"wires":[["ce21d5a89db4fc2a"]]},{"id":"8849e89d9e6c9ed1","type":"ha-entity-config","server":"33803899.487d48","deviceConfig":"","name":"teste","version":"6","entityType":"button","haConfig":[{"property":"name","value":"teste"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":true},{"id":"33803899.487d48","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

You are right. I had not noticed that the data in context is a buffer rather than an array. It appears that RED.util.cloneMessage() does not clone if it is passed a buffer.

@knolleary is it expected behaviour that, apparently, RED.util.cloneMessage() does not clone if it is passed a buffer?
This flow exhibits the behaviour.

[{"id":"ce21d5a89db4fc2a","type":"function","z":"e8ef959d13de8230","name":"Gerador de comandos","func":"msg.payload = RED.util.cloneMessage(flow.get(\"password\")) || []\nvar i;\nfor (i = 0; i < msg.payload.length; i++) { msg.payload[i] = msg.payload[i] + 0x30; }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":220,"wires":[["e294ddf47043dffd"]]},{"id":"e294ddf47043dffd","type":"debug","z":"e8ef959d13de8230","name":"Button ?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":560,"y":220,"wires":[]},{"id":"b1e1146df5ec4324","type":"inject","z":"e8ef959d13de8230","name":"Inject Buffer","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[1,2,3,4,5,6]","payloadType":"bin","x":150,"y":320,"wires":[["a894df8dc67e8858"]]},{"id":"a894df8dc67e8858","type":"change","z":"e8ef959d13de8230","name":"","rules":[{"t":"set","p":"password","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":320,"wires":[["47a8cf7a5a7ece2c"]]},{"id":"47a8cf7a5a7ece2c","type":"debug","z":"e8ef959d13de8230","name":"Inject Senha OK","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":560,"y":320,"wires":[]},{"id":"75e2115aac463d61","type":"inject","z":"e8ef959d13de8230","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":220,"wires":[["ce21d5a89db4fc2a"]]},{"id":"a850bdb5c20a27ae","type":"inject","z":"e8ef959d13de8230","name":"Inject Array","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[1,2,3,4,5,6]","payloadType":"json","x":140,"y":380,"wires":[["a894df8dc67e8858"]]}]

@walberjunior it seems to work if you use
msg.password = Buffer.from(flow.get("password")) || []
though I am not entirely sure why. I thought that buffer.from() on an existing buffer would just make another reference to it, but it appears not in this situation.

Yes, is working.

Thanks for the help.