How do I select a bit value from a (status) byte?

I have made an MQTT binding which transfers two status byte from a central heating to openhab.
How can I select the individual bits from these status bytes to separate items in the user interface?
I prefer not to send all 16 status bits separately.

e.g.
status 0x80 is pump is running (0x00 = pump is off)
status 0x40 is on/off mode
status 0x20 is opentherm mode

These status bits are independent of each other

Even though you prefer not to, I’ll tell you right now it will be FAR easier to send each separately than it will be to bit parse them out on the OH side. Parsing out bit-packed binary data in Java/Xtext is a huge pain and you will spend a lot more time figuring out and debugging the parsing back out of the bits than you will sending them separately.

Even if all you did was increase the binary so that each field falls on a byte or two byte boundary will save you tons and tons of work. And if you are worried about network throughput, don’t. Even if you put the 16 status bits as bytes you are still well within your average IP packet size, meaning your MQTT message will still fit in one packet, and even though MQTT is still super light weight you will face way more latency and network traffic with the overhead added by MQTT than the increase from a 2 byte message to a 16 byte message.

See this message at Stackoverflow for a decent explanation and example of what you are facing if you choose to forge ahead.

Really?

rule "Opmode Bath FirstFloor"
when
  Item Heat_FF_Bath_Opmode received update                  //Opmode received from bus
then
  var tmp = Heat_FF_Bath_Opmode.state as DecimalType        //read value as Number
  var state = tmp.toBigDecimal.toBigInteger                 //write as (big)integer
  logDebug("heating.rules","Heat_FF_Bath_Opmode:"+state.toString)
  if (state.testBit(0) ) {                                  //test Bit 0
        if (Heat_FF_Bath_Opset.state!=1) 
            Heat_FF_Bath_Opset.postUpdate(1)                //if 1, then set Opmode to 1
  }    
  else if (state.testBit(1)) {                              //test Bit 1
        if (Heat_FF_Bath_Opset.state!=2) 
            Heat_FF_Bath_Opset.postUpdate(2)                //if 1, then set Opmode to 2
  }
  else if (state.testBit(2)) {                              //test Bit 2
        if (Heat_FF_Bath_Opset.state!=3) 
            Heat_FF_Bath_Opset.postUpdate(3)                //if 1, then set Opmode to 3
  }
  else if (state.testBit(3)) {                              //test Bit 3
          if (Heat_FF_Bath_Opset.state!=4) 
              Heat_FF_Bath_Opset.postUpdate(4)              //if 1, then set Opmode to 4
  }
  else {                                                    //else
        Heat_FF_Bath_Opset.postUpdate(2)                    //set Opmode to 2
  }
end

I may be wrong, but I think, it would be something similar to this rule :slight_smile:

1 Like

I didn’t know about the testBit method (there really wasn’t a BigDecimal in Java the last time I had to deal with binary data in Java more than 10 years ago now, gee I’m getting old).

So as long as you can convert a two byte binary into a BigDecimal and toBigInteger without the sign bit being messed with this should work pretty well.

Thanks for the testBit solution! This is what I was looking for.
I have an issue getting it to work. There is probably a typo in my rule.

BigDecimal has been there for almost 20 years now (JDK 1.1, early 1997) so maybe it’s been longer than you thought. I only know that because I’m a lot older than you. :slight_smile:

1 Like

Well shoot. I though BigDecimal was introduced in 1.4. I could have saved a ton of work parsing TADL-J messages way back when if I knew about it. Learn something new every day.

Openhab designer show an error on toBigDecimal, toBigInteger and testBit.
Which libraries do I need to import?
Already tried import java.math.BigDecimal and import java.math.BigInteger but that does not work…

Sorry, missed that part…

I have only this imports in this rule file:

import org.openhab.core.library.types.*
import java.lang.Math

Thanks I got a working now.

Hello
is there also a way to adress bits of a integer directly like it is described here:
bit adressing codesys

I need to do a datatype conversion from single bits [switch] to 16 bit integer [number] because the modbus binding does not support datatypes <16 bit and I do not want to waste memory. See here:
Datatype Modbus TCP Binding

Thank you in advance.
BR Sebastian

Addressing individual bits is explained above (testBit). Furthermore, if this is about modbus, you can use bit value type to read individual bits.

It’s the writing which is not supported for <16bit values, since there is nothing like that in modbus protocol itself.

From the above response I am not sure what you are exactly after…

How can I read indiviual bits with modbus?
With the explanation above I can do this with the testBit method. So I can convert a 16 bit value in bits.

But I also need the other way round to convert bits into 16 bit value with rules in OH. Is there a way to write direktly with the testBit method? How is this done?

Any idea? Do you unterstand my problem?
Thank you.

Well, this is psuedo-code but should give the idea

when
   myBit0 changed or
   myBit1 changed or
   myBit2 changed
then
   var outputword = 0
   if ( myBit0.state > 0 ) {
      outputword=outputword + 1
      }
   if ( myBit1.state > 0 ) {
      outputword=outputword + 2
      }
   if ( myBit2.state > 0 ) {
      outputword=outputword + 4
      }
   myRegisterItem.postUpdate( outputword )

You’ll probably need to adjust depending on the types of Items you use, and you can smarten up the rule trigger by using a Group.

2 Likes