Calculate hex checksum

I would like to send a hex string to my AC unit and need to know how to calculate the checksum in a rule. The checksum calculation is adding all the hex digits together and discarding all but the lowest byte which is the checksum that’s used.
Is there an easy way to do this?

The short answer is no, there is no easy way to do this. There is nothing in Xtend to support binary operations like this and Java’s support for binary operations like this is pretty awkward to use.

Something like this is what you will need:

This should get you started.

Xtend does support bitwise opperators and it does support arithmetic expressions.

In the past I used expressions like Item.state.toBigDecimal.toBigInteger.intValue.bitwiseAnd(0x03) Not sure, if all these concersions are really neccessary, but a few years ago it was the only way I could make it work.

So it probaby would be possibe: Splitting the string to individual bytes, converting them to int (not sure, if there is a build in funtion for that, but I assume so) and than a .bitwiseAnd(0xff)

Nowdays I personally would use Jython or JavaScript rules for these tasks.

I’ve just been fiddling with bitwise operations in rules, and so far as I can tell you do really need to work with BigInteger to get useful bit(N) methods. Going that far is probably unnecessary for simple add + mask, though.

Make sure you are not reinventing wheels here, and that the mystery AC unit is not using some protocol already implemented in openHAB

That is using Java, not Xtend.

When you look at, you will see that none of the bitwise operators like |, &, ^, and ~ (bitwise OR, bitwise AND, bitwise XOR, and bitwise complement) are supported and the shift operators have a different meaning in Xtend. So you have to use the Java classes and methods to manipulate binary data, just as you demonstrate.

To spell out what that line does:

We start with an Item, which is a Java Object and call .state.
This returns a State Object, which is a Java Object. Assuming the state is a DecimalType and not NULL or UNDEF the next part will work.
Then we call toBigDecimal which to a large extent I think is a noop because DecimalType is already of type BigDecimal, but I could be wrong. Either way, BigDecimal is a Java Object.
Then we call toBigInteger which returns the value as a BigInteger type. BigInteger is a Java Object.
Then we call intValue which gives you a primitive int.
Then we try to call bitwaiseAnd on the primitive int value which Xtend sees and in order to make it happen converts the primitive int to an Integer class so it can then call the bitwiseAnd method. Integer is a Java Object.

The whole thing could be reduced to

(Item.state as Number).intValue.bitwaiseAnd(0x03)

However, be aware that int and Integer are signed which may or may not be a problem depending on the types of binary manipulation you are doing. byteValue may be more appropriate.

But, now that I’ve said all of the above, @kevin, this may be as simple as a loop to convert each hex value to a number and add them all together. Xtend will put the results into a BigDecimal by default. Then call byteValue which I’m pretty sure will give you the lowest byte.You’d have to test to verify that though.

Thanks for the comprehensive reply, albeit a lot went over my head, especially as I don’t know anything about loops in Java. Moving on to a conventional example, lets assume I have 6 hex pairs that I would like to checksum together, can you help me with an example based on this?
I knocked up the rule below which gives the correct result according to and also my experience using the full 20 byte set with correct checksum I got from the existing remote.
Whilst this now works, I wonder if there Is there an easier way of doing this?

 val String byte1 = "AB"
 val String byte2 = "EF"
 val String byte3 = "10"
 val String byte4 = "22"
 val String byte5 = "34"
 val String byte6 = "56"

 rule "Calculate Checksum" when Item Testing changed then
 val total = Integer.parseInt(byte1, 16) + Integer.parseInt(byte2, 16) + Integer.parseInt(byte3, 16) + Integer.parseInt(byte4, 16) + Integer.parseInt(byte5, 16) + Integer.parseInt(byte6, 16)
 val result = total / 256
 val newTotal = total - (result * 256)
 var String checkSum = String::format(Integer::toHexString(newTotal))
 logInfo("test", "The checksum is "+checkSum)

You could logInfo your key intermediate values to follow events better.

I think you need to make sure the divide by 256 result is integer, discarding (not rounding) any decimals.

OpenHAB appears to work in integers with this rule presumably because each of the values in “total” are derived from Integers, but I have encountered the rounding error with values derived from states.

To convert the time I had to use

val currentDecTime = (CurrentHour.state as DecimalType).intValue * 60 + (CurrentMinute.state as DecimalType).intValue

I also found an error in the larger rule I was using in my rules file, so now the calculated checksum is the same as from the IR remote, albeit I wonder whether there is an easier way to do it other than adding all the values individually.
@rikoshak is there a tutorial anywhere that explains loops? I’ve used simple ones in DOS Batch files some time ago, but not in OpenHAB rules

Nope. That’s why it’s called a checksum.
You can make something that looks more elegant and is more flexible about message length by automating a loop.
But with a short, fixed length message, it’s simple and more efficient just to add.

You should find many examples of while loop in this forum. Treat with caution, to avoid endless or long running loops

1 Like

Thanks for that, I’ve decided to leave the code as it is. I used it live for the first time overnight to control the bedroom AC using IR which allowed access the quiet fan modes which I can’t get to with the Api. It worked very well