Bit Mask not working correctly from Switch


Thank you for a great project! It makes things so easy. Your hard work benefits many.

Working with Dashboard switch, but nor sure if this should be in this Category.

When it comes to Javascript, I am to be considered dangerous, I know just enough to get myself into trouble!

Running a clean system on a Raspberry Pi B - installed yesterday.

31 Jul 07:25:18 - [info] Node-RED version: v0.20.7
31 Jul 07:25:18 - [info] Node.js version: v10.16.0
31 Jul 07:25:18 - [info] Linux 4.19.57-v7+ arm LE
31 Jul 07:25:20 - [info] Loading palette nodes
31 Jul 07:25:30 - [info] Dashboard version 2.15.5 started at /ui

I am trying to look at a variable/word and look for a particular bit being changed. Basically, this word is being used by Controller to see which bits are on, but it will only use this word if Bit 15 is on. If Bit 15 (or whichever) is flipped an output is required to send a message via telegram. I have eliminated the controller and telegram sections from the flow to keep things simple. Effectively, I have this little flow below to try to make this happen. (This is part of a Home Control system.)

It works OK for the appropriate Bit, but the problem is that if I use with the mask set for Bit 15, if Bit 5 is flipped it is allowed through as an unset action as well. If I change the mask to Bit 6 then Bit 2 is read as unset when it is flipped. I have been going nuts looking at this and just don't understand how this is happening, as only the mask bit should beallowed through if it is flipped.

Can anyone help point out any error please?


[{"id":"952cedf4.2a6bc","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"5bd5fb26.a9492c","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 15","tooltip":"","group":"1f54c10e.696d97","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":69,"wires":[["cf3964ba.880fb"]]},{"id":"9eb7afec.3f573","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 0","tooltip":"","group":"1f54c10e.696d97","order":2,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":109,"wires":[["e69645b3.8c8ec"]]},{"id":"afc6fcb4.94853","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 1","tooltip":"","group":"1f54c10e.696d97","order":3,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":149,"wires":[["7217d6a7.9de9c8"]]},{"id":"ba451a01.1ad57","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 2","tooltip":"","group":"1f54c10e.696d97","order":4,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":189,"wires":[["54c4a3c1.fea184"]]},{"id":"3f123bbc.682e04","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 4","tooltip":"","group":"1f54c10e.696d97","order":5,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":229,"wires":[["59d05d8e.b062c4"]]},{"id":"84402e22.b4b718","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 5","tooltip":"","group":"1f54c10e.696d97","order":6,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":269,"wires":[["e6d2f4e0.8f30e8"]]},{"id":"609926d1.2f178","type":"ui_switch","z":"952cedf4.2a6bc","name":"","label":"Bit 6","tooltip":"","group":"1f54c10e.696d97","order":7,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":293,"y":309,"wires":[["c2a318ab.90e61"]]},{"id":"cf3964ba.880fb","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 15;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":69,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"e69645b3.8c8ec","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 0;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":109,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"7217d6a7.9de9c8","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 1;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":149,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"54c4a3c1.fea184","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 2;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":189,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"59d05d8e.b062c4","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 4;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":229,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"e6d2f4e0.8f30e8","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 5;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":269,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"c2a318ab.90e61","type":"function","z":"952cedf4.2a6bc","name":"XOR word","func":"var mask = 1 << 6;  //Mask bit\nvar status = global.get('nSpecialStatus')||0;\nif (msg.payload === true) {\n  status |= mask;\n} else {\n   status &= ~mask;\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"x":523,"y":309,"wires":[["6e6dd55f.53e58c","d3a84cb6.6dd1f"]]},{"id":"6e6dd55f.53e58c","type":"debug","z":"952cedf4.2a6bc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":790,"y":320,"wires":[]},{"id":"15fe3a84.e6c075","type":"debug","z":"952cedf4.2a6bc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1073,"y":63,"wires":[]},{"id":"d3a84cb6.6dd1f","type":"function","z":"952cedf4.2a6bc","name":"","func":"var mask = 1 << 15;  //Mask bit 15\n//var mask = 1 << 6;  //Mask bit 6\n\nvar status = msg.payload;\nvar oldStatus = global.get(\"SpecialStatusOld\")||0;\nvar manipStatus = status ^ oldStatus;\n\nmanipStatus = manipStatus.toString(2);\nmanipStatus = \"0000000000000000\".substr(manipStatus.length) + manipStatus;\nnode.status({text:manipStatus});\nvar test = \"\";      //***********\n\nif ((manipStatus & mask) !==0){\ntest = (manipStatus & mask);      //***********\n   if ((status & mask) !== 0) {\n       msg.payload = \"Manual mode On\"; \n       global.set(\"SpecialStatusOld\", status);\nmsg.status = test + \"|\" + manipStatus + \"|\" + mask + \"|\" + status + \"|\" + oldStatus;      //***********\n        return msg;\n    } \n    else {\n        msg.payload = \"Manual mode Off\"; \n        global.set(\"SpecialStatusOld\", status);\nmsg.status = test + \"|\" + manipStatus  + \"|\" + mask+ \"|\" + status + \"|\" + oldStatus;      //***********\n        return msg;\n    }\n}\n\nmsg.status = test + \"|\" + manipStatus + \"|\" + mask + \"|\" + status + \"|\" + oldStatus;      //***********\nglobal.set(\"SpecialStatusOld\", status);\nreturn msg;","outputs":1,"noerr":0,"x":1034,"y":189,"wires":[["15fe3a84.e6c075","e39c67b2.36545"]]},{"id":"e39c67b2.36545","type":"debug","z":"952cedf4.2a6bc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"status","targetType":"msg","x":1135,"y":103,"wires":[]},{"id":"1f54c10e.696d97","type":"ui_group","z":"","name":"Manual Mode","tab":"43a7f88c.a95ad","order":4,"disp":true,"width":"6","collapse":false},{"id":"43a7f88c.a95ad","type":"ui_tab","z":"","name":"Status","icon":"dashboard","order":4,"disabled":false,"hidden":false}]

Which bit isn't working? The XOR or the function node?
Build a simple flow contaiining just a couple of inject nodes sending true and false and whatever else you need to demonstrate the problem. Post that, and tell us what it should do and what it actually does, so we can replicate the problem.

Hi Colin,

It is the function that is not working the actual mask for recognising Bit 15 or Bit 6 set and unset. The outputs from the XOR are fine.

You can use node.warn() to follow the flow through the function and see where it is going wrong. So for example after the line
manipStatus = manipStatus.toString(2);
you could insert the line

node.warn(`manipStatus is ${manipStatus}`)

and it will show that value in the debug window when it is executed. Using this method you should be able to work out which part is not working as you expect.
If you are using an old version of nodejs you might have to use
node.warn("manipStatus is " + manipStatus")

Thank you Colin, much appreciated.

Have a busy day today so will have to leave it until later.

Ok, continuing with the problem...

I can see how node.warn helps as a variable is processed.

Previously, I could see the relevant variables in my msg.status, and had moved them around according to what and where I wanted to monitor, but node.warn is easier!

So, what I have found...
Having flipped Bit 5 (the bit giving me the error, all others are OK),
status is 32 or 100000 showing that Bit 5 is on (say, off works with status returning to 0)
manipStatus is 100000 showing that Bit 5 has correctly flipped
mask is 32768 or Bit 15
test (manipStatus & mask) is 32768 or Bit 15

If I Bitwise AND manipStatus 100000 and Mask 1000000000000000 I get a result of 32768 or Bit 15

The testing of the variable status and mask always reflects the state of Bit 15.

Basically, I believe I am Bitwise anding Bit 5 and Bit 15 together and getting Bit 15 set.

I believe the problem is manipStatus, but the value in the node.warn shows the value I expect - Bit 5 has flipped.

Sorry, I am now completely lost and feel that I may be missing something silly!

As for nodejs being out of date, I installed from the setup page for the Raspberry Pi yesterday. Will try to update.


Node.js isn't out of date. You have the latest 10.x version installed which is what we recommend.

Thank you knolleary.

Your description is too complex. Tell us which line doesn't do what you expect and what node.warn shows before and after it.

Sorry, trying to give full information.

As described here.
If I Bitwise AND manipStatus 100000 and Mask 1000000000000000 I get a result of 32768 or Bit 15

This occurs here.
if ((manipStatus & mask) !==0){

Result is.

What are the types of manipStatus and mask (use node.warn(typeof manipStatus) and mask to see. I wonder whether one of them is a string instead of a number.

Hi. Not entirely sure of your issue or how you are setting bits / testing bits but perhaps the following might help...

To get a bit mask:

var mask = 1 << 5; // gets the 6th bit

To test if a bit is set:

if ((n & mask) != 0) {
  // bit is set
} else {
  // bit is not set

To set a bit:

n |= mask;

To clear a bit:

n &= ~mask;

To toggle a bit:

n ^= mask;

And remember, bitwise operators are 32bit.

1 Like

@Colin Thank you! manipStatus was a String and should be a String as I told it to be a String.

One thing that gets me with Javascript is that you don't define the variable type, which I do in the other languages I use. Used to frighten me at the beginning, but then you become used to it and forget the basics. Much appreciate your patience and guidance. I now have a couple more easy tools in my toolkit.

@Steve-Mcl Appreciate the input. I use a similar post on SE to remind me of the instructions for Bitwise operations. Always find it very handy as programming is not my main strength. (You can probably tell as I can't count!)

Must admit that bacause it was only the one input that was giving me an error, the rest seemingly operating correctly, I was completely confused! My hours of wrangling and moving messages around are over for the moment.

Thanks again for a fantastic project and a great bunch of People on this Forum. I lurk a lot and try to teach myself from others posts, adapting where necessary and of course trying to KISS so that I can break things down easily.

1 Like