XOR and ADD of the buffer numbers

I need help to make a XOR and ADD of the values from this buffer :
image
is ADD this :
var sum = msg.payload.DLE+msg.payload.SOH+msg.payload.BUSH+msg.payload.BUSL+msg.payload.RAMH+msg.payload.RAML+msg.payload.DC+msg.payload.D0_TMP_data+msg.payload.D1_STime+msg.payload.D2_STime+msg.payload.D3_ETime+msg.payload.D4_ETime

and XOR this :
var checksum = msg.payload.DLE^msg.payload.SOH^msg.payload.BUSH^msg.payload.BUSL;

?
Thanks

Is this to be performed on all the properties of the object or just a subset? If it is to be performed on all of them then use Object.entries() to give you an array of the properties, then Array.reduce() twice to give the two values.

only subset, last two bytes are reserved for add and xor results

Firstly, that is NOT a buffer - it is an object with properties.

It would be far easier it it was a Buffer (simply loop through and do XOR)

It there a particular reason you have chosen to store these values in this format?

IMO, you should be calculating the XOR before you format the data into an Object.

If you show your full flow and explain where data comes from and what you intend to do with it, we might be able to spot the best place to do this without resorting to Object.entries or some other hack.

sending my flow with explanation :


This flow must be able calculate different requests

Questions...

  1. Are you saying ALL properties of the Object (except ADDS, XORS and END) should be used in your calculations?
    If not, explain which properties should be excluded
  2. Will the last object ALWAYS have the same properties (or might there me more/less depending on the TCP data)?

Also...

  • share the flow (select those items on screen, CTRL+E) paste into a reply using the </> code button
  • copy the values from that buffer (using the "Copy Value" button in debug sidebar) and paste into a reply using the </> code button

Yes all is used for xor and add calculation. last 3 are still calculated adds, calculated xor and 0xFF
sending flow:

[{"id":"f3a9bffd6ad12212","type":"ui_button","z":"bc76ab2f.9bc068","name":"","group":"8c11279992e11f1f","order":5,"width":6,"height":1,"passthru":false,"label":"Heating","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"[\"0x00\",\"0x00\",\"0x00\",\"0x00\",\"0x11\",\"0x23\",\"0x00\",\"0x19\",\"0x00\",\"0x00\",\"0x01\",\"0x00\",\"0x00\",\"0x00\",\"0x00\"]","payloadType":"bin","topic":"topic","topicType":"msg","x":140,"y":2620,"wires":[["533f2e74ea7508a4"]]},{"id":"533f2e74ea7508a4","type":"buffer-parser","z":"bc76ab2f.9bc068","name":"","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"uint8","name":"DLE","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"SOH","offset":1,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"BUSH","offset":2,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"BUSL","offset":3,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"RAMH","offset":4,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"RAML","offset":5,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"DC","offset":6,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"D0_TMP_data","offset":7,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"D1_STime","offset":8,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"D2_STime","offset":9,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"D3_ETime","offset":10,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"D4_ETime","offset":11,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"ADDS","offset":12,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"XORS","offset":13,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"END","offset":14,"length":1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"return","multipleResult":false,"fanOutMultipleResult":true,"setTopic":false,"outputs":1,"x":350,"y":2720,"wires":[["b23eb81b5d848a85","15ff3389aa55fe16"]]},{"id":"15b911ea9a2a8484","type":"function","z":"bc76ab2f.9bc068","name":"ADD config","func":"//Main unit CFG\nmsg.payload.DLE = 0x10\nmsg.payload.SOH = 0x01\n//adresa 255,255\nmsg.payload.BUSH = 0xFF\nmsg.payload.BUSL = 0xFF\n//end fix 255\nmsg.payload.END = 0xFF\n//příkaz zapiš 5bajtů\nmsg.payload.DC = 0x4C\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":2660,"wires":[["3a8314f5ac24d842"]]},{"id":"15ff3389aa55fe16","type":"link call","z":"bc76ab2f.9bc068","name":"","links":["9ac24f5969ea7b69"],"timeout":"30","x":550,"y":2720,"wires":[["0464522be85c420c","c9bb0d9073ca8bcd"]]},{"id":"b23eb81b5d848a85","type":"debug","z":"bc76ab2f.9bc068","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":530,"y":2800,"wires":[]},{"id":"9ac24f5969ea7b69","type":"link in","z":"bc76ab2f.9bc068","name":"ADD config","links":[],"x":455,"y":2660,"wires":[["15b911ea9a2a8484"]]},{"id":"3a8314f5ac24d842","type":"link out","z":"bc76ab2f.9bc068","name":"","mode":"return","links":[],"x":655,"y":2660,"wires":[]},{"id":"f5c33dad152014a3","type":"link in","z":"bc76ab2f.9bc068","name":"Calculate StartTIME","links":[],"x":715,"y":2660,"wires":[["0eaac7424581f275"]]},{"id":"0eaac7424581f275","type":"function","z":"bc76ab2f.9bc068","name":"Calculate SartTIME","func":"//TOY čas roku - = (mesic_zacatek * 4096) + \n//(den_zacatek * 128) + (hodina_zacatek * 4) + (minuta_zacatek / 15)\n//- vyjde-li po zpětném převodu čas dne>23.45-platí jako 24.00\n//Read actual date and time\nvar Time=new Date();\n//posunuti zacatku pokud definovano\nTime.setDate(Time.getDate()+msg.payload.D1_STime);\nTime.setMinutes(Time.getMinutes()+msg.payload.D2_STime);\n//součet dle etathermu\nvar Final_Time=((Time.getMonth()+1)*4096)+(Time.getDate()*128)+(Time.getHours()*4)+Math.floor(Time.getMinutes()/15);\n//převod součtu na HEX\nFinal_Time=Final_Time.toString(16);\n//rozdělení HEX a uložení jako číslo na dvě adresy\nmsg.payload.D1_STime=parseInt((Final_Time.substr(0, 2)),16);\nmsg.payload.D2_STime=parseInt((Final_Time.substr(2, 4)),16);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":830,"y":2660,"wires":[["a35a10e5c1490593"]]},{"id":"a35a10e5c1490593","type":"link out","z":"bc76ab2f.9bc068","name":"","mode":"return","links":[],"x":955,"y":2660,"wires":[]},{"id":"0464522be85c420c","type":"link call","z":"bc76ab2f.9bc068","name":"","links":["f5c33dad152014a3"],"timeout":"30","x":820,"y":2720,"wires":[["6b88d4bf7de56f68","a2a64b1107efaab1"]]},{"id":"c9bb0d9073ca8bcd","type":"debug","z":"bc76ab2f.9bc068","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":770,"y":2800,"wires":[]},{"id":"6b88d4bf7de56f68","type":"debug","z":"bc76ab2f.9bc068","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1030,"y":2800,"wires":[]},{"id":"a2a64b1107efaab1","type":"link call","z":"bc76ab2f.9bc068","name":"","links":["6d564f29b081ef58"],"timeout":"30","x":1130,"y":2720,"wires":[["6395428f6fccbd0d","873fe74408b7d404"]]},{"id":"29415a1dd8ac7d13","type":"function","z":"bc76ab2f.9bc068","name":"Calculate EndTIME","func":"//TOY čas roku - = (mesic_zacatek * 4096) + \n//(den_zacatek * 128) + (hodina_zacatek * 4) + (minuta_zacatek / 15)\n//- vyjde-li po zpětném převodu čas dne>23.45-platí jako 24.00\n//Read actual date and time\nvar Time=new Date();\n//posunuti zacatku pokud definovano\nTime.setDate(Time.getDate()+msg.payload.D3_ETime);\nTime.setMinutes(Time.getMinutes()+msg.payload.D4_ETime);\n//součet dle etathermu\nvar Final_Time=((Time.getMonth()+1)*4096)+(Time.getDate()*128)+(Time.getHours()*4)+Math.floor(Time.getMinutes()/15);\n//převod součtu na HEX\nFinal_Time=Final_Time.toString(16);\n//rozdělení HEX a uložení jako číslo na dvě adresy\nmsg.payload.D3_ETime=parseInt((Final_Time.substr(0, 2)),16);\nmsg.payload.D4_ETime=parseInt((Final_Time.substr(2, 4)),16);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1130,"y":2660,"wires":[["9da99596ee482d6a"]]},{"id":"6d564f29b081ef58","type":"link in","z":"bc76ab2f.9bc068","name":"Calculate EndTIME","links":[],"x":1015,"y":2660,"wires":[["29415a1dd8ac7d13"]]},{"id":"9da99596ee482d6a","type":"link out","z":"bc76ab2f.9bc068","name":"","mode":"return","links":[],"x":1255,"y":2660,"wires":[]},{"id":"f9997fa7c0407834","type":"link in","z":"bc76ab2f.9bc068","name":"Calc ADDS XOR","links":[],"x":1315,"y":2660,"wires":[["322c16808ae63fa3"]]},{"id":"322c16808ae63fa3","type":"function","z":"bc76ab2f.9bc068","name":"Calc ADDS XOR","func":"var ADD = (msg.payload.DLE+msg.payload.SOH+msg.payload.BUSH+msg.payload.BUSL+\nmsg.payload.RAMH+msg.payload.RAML+msg.payload.DC+msg.payload.D0_TMP_data+\nmsg.payload.D1_STime+msg.payload.D2_STime+msg.payload.D3_ETime+msg.payload.D4_ETime)^0xAA;\nmsg.payload.ADDS=ADD.toString(16);\nmsg.payload.ADDS=parseInt((msg.payload.ADDS.substr(1, 2)),16);\n\nvar XOR = msg.payload.DLE^msg.payload.SOH^msg.payload.BUSH^msg.payload.BUSL^msg.payload.RAMH\n^msg.payload.RAML^msg.payload.DC^msg.payload.D0_TMP_data^msg.payload.D1_STime^msg.payload.D2_STime\n^msg.payload.D3_ETime^msg.payload.D4_ETime^0xAA;  \nmsg.payload.XORS = XOR.toString(16);\nmsg.payload.XORS=parseInt((msg.payload.XORS.substr(0, 2)),16);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1430,"y":2660,"wires":[["40160757ca91f25c"]]},{"id":"40160757ca91f25c","type":"link out","z":"bc76ab2f.9bc068","name":"","mode":"return","links":[],"x":1555,"y":2660,"wires":[]},{"id":"873fe74408b7d404","type":"link call","z":"bc76ab2f.9bc068","name":"","links":["f9997fa7c0407834"],"timeout":"30","x":1430,"y":2720,"wires":[["3ac51e1b63d26b45"]]},{"id":"6395428f6fccbd0d","type":"debug","z":"bc76ab2f.9bc068","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1330,"y":2800,"wires":[]},{"id":"3ac51e1b63d26b45","type":"debug","z":"bc76ab2f.9bc068","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1630,"y":2800,"wires":[]},{"id":"8c11279992e11f1f","type":"ui_group","name":"OPERATIVNÍ ZMĚNY","tab":"befeb13c.bfa17","order":41,"disp":true,"width":6,"collapse":false,"className":""},{"id":"befeb13c.bfa17","type":"ui_tab","name":"TOPENÍ ETATHERM","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

+one notice : on the end of adds and xor is always xor with 0xAA

That really didnt answer any of my questions (and part of the problem why it has taken so long to get an answer in the forum)

Never mind - I'll guess what you are trying to do. Here you go, with assumptions and all...

Calc ADDS XOR function...

const data = Object.entries(msg.payload);

let ADDS = 0;
let XORS = 0;
for (let index = 0; index < data.length; index++) {
    const item = data[index][0];
    const value = data[index][1];
    if (item === "ADDS") continue; //skip ADDS prop
    if (item === "XORS") continue; //skip XORS prop
    if (item === "END") continue; //skip END prop
    ADDS += value;
    XORS ^= value;
}
msg.payload.ADDS = (ADDS ^ 0xAA) & 0xFF;
msg.payload.XORS = (XORS ^ 0xAA) & 0xFF;

return msg;

Proof (my code plus your original code) ...
image

very nice, only there is one "problem"
when reslut of add is too big, let say 890 dec = 37A, so is saved only 0x7A
that's why I'm doing this in my code:
msg.payload.ADDS=parseInt((msg.payload.ADDS.substr(1, 2)),16);
no sure if it's the best way, but it's working :slight_smile:

so with you code is result of adds wrong :
image
maximum is 0xFF

hard to explain rest of the code regarding time calculations, because it's defined by communication protocol with main unit and this protocol I don't have in English to share it with you. Sorry

the & 0xff should have masked that.

Give me a copy of your sample data that generated that result & I'll double check code.

Ohhh, sorry my mistake. It's ok and working as you expected.
May I ask you one more question ?
How to make automatic loops like this ?:

Dont. Avoid loops if you can. They will catch you out & cause you to exhaust stack space (node-red hard crash).

Cant you use a simple inject or cron node to schedule your requests?

I will try explain what I want (perhaps understandably).
Normaly one request = set temperature for one room. But I want implement button request which sets temperature for three rooms. To do this I must send three requests step by step with delay or depends on answer from main unit (0xFF).

So use a split node to break the request into 3 separate messages...

image

[{"id":"8274dbd97b65fc7f","type":"inject","z":"a73202046ef1075d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":190,"y":920,"wires":[["84acc85a548ff39a"]]},{"id":"84acc85a548ff39a","type":"function","z":"a73202046ef1075d","name":"prepare messages","func":"msg.payload = [\n    [\"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x11\", \"0x23\", \"0x00\", \"0x19\", \"0x00\", \"0x00\", \"0x01\", \"0x00\", \"0x00\", \"0x00\", \"0x00\"],\n    [\"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x12\", \"0x23\", \"0x00\", \"0x19\", \"0x00\", \"0x00\", \"0x01\", \"0x00\", \"0x00\", \"0x00\", \"0x00\"],\n    [\"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x13\", \"0x23\", \"0x00\", \"0x19\", \"0x00\", \"0x00\", \"0x01\", \"0x00\", \"0x00\", \"0x00\", \"0x00\"],\n]\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":920,"wires":[["daf5245d70bcf6fd"]]},{"id":"daf5245d70bcf6fd","type":"split","z":"a73202046ef1075d","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":230,"y":1000,"wires":[["0844564647638622"]]},{"id":"0844564647638622","type":"function","z":"a73202046ef1075d","name":"to buffer","func":"msg.payload = Buffer.from(msg.payload)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":1000,"wires":[["533f2e74ea7508a4"]]}]

ok, is very good idea. But this will send three requests in one row, but I must give a time to main unit to process each requset.

then use a delay set to rate limit - OR - use the semaphore nodes to ensure 1 message traveling at one time - OR - use a queue/gate node to control the flow of messages.

ok, please let me check, because this nodes are new for me. I must check which one is best for me. Thank you

When I have a section of flow that must only have one message flowing through it at a time then I use the semaphore node, node-red-contrib-semaphore. It is easy to use and works well. One thing you have to be careful of is to make sure that every exit from the section has a semaphore release node or everything stops. Think about network timeouts and such like that might case a timeout error, for example.

so like this ?

[{"id":"8274dbd97b65fc7f","type":"inject","z":"59fb2f9263e14661","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":470,"y":420,"wires":[["84acc85a548ff39a"]]},{"id":"84acc85a548ff39a","type":"function","z":"59fb2f9263e14661","name":"prepare messages","func":"msg.payload = [\n    [\"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x11\", \"0x23\", \"0x00\", \"0x19\", \"0x00\", \"0x00\", \"0x01\", \"0x00\", \"0x00\", \"0x00\", \"0x00\"],\n    [\"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x12\", \"0x23\", \"0x00\", \"0x19\", \"0x00\", \"0x00\", \"0x01\", \"0x00\", \"0x00\", \"0x00\", \"0x00\"],\n    [\"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x13\", \"0x23\", \"0x00\", \"0x19\", \"0x00\", \"0x00\", \"0x01\", \"0x00\", \"0x00\", \"0x00\", \"0x00\"],\n]\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":420,"wires":[["daf5245d70bcf6fd"]]},{"id":"daf5245d70bcf6fd","type":"split","z":"59fb2f9263e14661","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":510,"y":500,"wires":[["0844564647638622"]]},{"id":"0844564647638622","type":"function","z":"59fb2f9263e14661","name":"to buffer","func":"msg.payload = Buffer.from(msg.payload)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":500,"wires":[["6392600171d3fd5e"]]},{"id":"31b479d1151399b1","type":"debug","z":"59fb2f9263e14661","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1230,"y":460,"wires":[]},{"id":"6392600171d3fd5e","type":"semaphore-take","z":"59fb2f9263e14661","config":"6dab6620e4aba0d8","name":"","x":820,"y":500,"wires":[["26bb78863f1c9a24"]]},{"id":"26bb78863f1c9a24","type":"delay","z":"59fb2f9263e14661","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1020,"y":500,"wires":[["b99243d93bd6f734","31b479d1151399b1"]]},{"id":"b99243d93bd6f734","type":"semaphore-leave","z":"59fb2f9263e14661","config":"6dab6620e4aba0d8","name":"","x":1250,"y":500,"wires":[[]]},{"id":"6dab6620e4aba0d8","type":"semaphore-config","name":"input","capacity":"1"}]

in my code is only delay, but there can be my communication code. Is there any way to reset a semaphore when I will detect any error ?

You can use a trigger node instead - set to rate limit mode with a long timeout... (which acts as a backstop if all else fails) - and then use a msg.flush=1 message to release the next message - you can control this by either the success of your flow - or indeed failure.