Rule for using only the lower byte of an 2 Byte value?

Hello to all,

I would like to have a rule where only the lower byte is used. Normaly you just add xFF to the 2byte Number and you will have the lower byte.

How do I have to enter this in an rule?
I tried the following ways

rule "MB_I_Reg_10" when Item MB_I_Reg_10 changed then SpitzbodenRT.sendCommand       (((MB_I_Reg_10.state & 255) as DecimalType) / 10) end

or

rule "MB_I_Reg_10" when Item MB_I_Reg_10 changed then SpitzbodenRT.sendCommand       (((MB_I_Reg_10.state as DecimalType) & 255) / 10) end

both are not working. I get no error. The byte number goes just thru. The “& 255” works here like an inline comment.

Has somebody a hint.

given MB_I_Reg_10 as Number, you have to cast the state to byte (this would cut away the high byte)
Maybe this will do it (did not test it, as I’m at work)

rule "MB_I_Reg_10" 
when 
    Item MB_I_Reg_10 changed 
then
    SpitzbodenRT.sendCommand(MB_I_Reg_10.state as Byte) 
end

If this does not work as expected, type conversion should work:

SpitzbodenRT.sendCommand((MB_I_Reg_10.state as DecimalType).toBigDecimal.toBigInteger && 255)

I’m using .testBit(n) to get various boolean informations from a BigInt:

myState = (MyItem as DecimalType).toBigDecimal.toBigInteger
if(myState.testBit(0))
{}
if(myState.testBit(1))
{}
if(myState.testBit(2))
{}
if(myState.testBit(3))
{}
if(myState.testBit(4))
{}
...

Hello thanks for the example,

I tried now

((MB_I_Reg_10.state as DecimalType).byteValue / 10)

This one seems to work… The only outstanding problem is, that the byte value is interpreted as signed I want to intepret it as unsigned.

Question: Where did you get the “.toBigDecimal” or “.toBigInteger” get from?
This was the hint for me to try “byteValue”. Later I noticed that I forgot the “to” :slight_smile:

Can you give me a link to the page where this kind of functions are described all together?

Hey @peaeater,
great to see that you found help in this thread. While @Udo_Hartmann is hopefully able to help you the rest of the way, I can answer your second question.

This is something I feel a lot of users do not know and I’ll make sure to add it to docs.openhab.org as soon as I am past my current work deadline. Here you go: Archived Projects | The Eclipse Foundation

I tried to find there something to be able to interpret a byte value as unsigned.

It seems that via the Formatter Option and Flag “o” it may be possible.

But I do not understand how I have to write that. Every way I tried runs into errors.

Does somebody know which Language is used within the rules definitions. Is it javascript our java or something special?

Normaly it should not be a big issue to interpret a byte or eaven integer as signed or unsigned.

I had now a little bit of time to study, what is happening here in my rule:

rule "MB_I_Reg_10" when Item MB_I_Reg_10 changed then SpitzbodenRT.sendCommand       
      (((MB_I_Reg_10.state as DecimalType).byteValue)) 
end

When the “changed” is fired the content of MB_I_Reg_10.state = 16587
after applying the rule the contend of SpitzbodenRT = -53

If write that in binary representation you get:

16587 = ‭0100 0000 1100 1011‬
  -53 = ‭1111 1111 1100 1011‬

So something in the conversion to DecimalTyp and then to byteValue goes completly wrong.
What changed the high byte to set all bits?

I just would like to have following conversion

     16587 <=> ‭0100 0000 1100 1011‬
AND    255 <=> 0000 0000 1111 1111
=      203 <=> 0000 0000 1100 1011

This is pretty easy.

But how do I formulate this in a openHAB 2 rule?

Did you try

myInt = (MB_I_Reg_10.state as DecimalType).toBigDecimal.toBigInteger && 255

already?
Maybe another aproach: do a MOD 256:

var Int myInt = (MB_I_Reg_10.state as DecimalType) % 256

I did not test this yet.

Hello Udo,

your example

which I changed to the following rule

rule "MB_I_Reg_10" when Item MB_I_Reg_10 changed then SpitzbodenRT.sendCommand      
 ((MB_I_Reg_10.state as DecimalType).toBigInteger && 255) end

runs into following messeage:

==> /var/log/openhab2/openhab.log <==
2016-10-22 19:33:43.450 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'MB_I_Reg_10': An error occured during the script execution: The name '<XCastedExpressionImpl>.toBigInteger' cannot be resolved to an item or type.

I changed to the rule

rule "MB_I_Reg_10" when Item MB_I_Reg_10 changed then SpitzbodenRT.sendCommand       
((MB_I_Reg_10.state as DecimalType)% 255) end

runs into the error

==> /var/log/openhab2/openhab.log <==
2016-10-22 19:40:30.200 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'MB_I_Reg_10': An error occured during the script execution: The name '<XCastedExpressionImpl> % <XNumberLiteralImpl>' cannot be resolved to an item or type.

I just noticed, that I forgott the toBigDecimal part in the rule. With that in runs into:

==> /var/log/openhab2/openhab.log <==
2016-10-22 20:51:35.718 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'MB_I_Reg_10': An error occured during the script execution: The name '<XMemberFeatureCallImplCustom> && <XNumberLiteralImpl>' cannot be resolved to an item or type.

If I change the “&&” to just “&” it is running without error, but the AND is not calculated.:frowning:

Please try

rule "MB_I_Reg_10"
when
    Item MB_I_Reg_10 changed
then
    SpitzbodenRT.sendCommand(((MB_I_Reg_10.state as DecimalType) % 256))
end

(yes, it’s 256)
What’s the item type of SpitzbodenRT?

Hello Udo,
yes I noticed the 256 allready yesterday.

Here comes the error messeage:

2016-10-23 11:02:07.149 [ItemStateChangedEvent     ] - MB_I_Reg_10 changed from 16580 to 16581

==> /var/log/openhab2/openhab.log <==
2016-10-23 11:02:07.165 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'MB_I_Reg_10': An error occured during the script execution: The name '<XCastedExpressionImpl> % <XNumberLiteralImpl>' cannot be resolved to an item or type.

This is a realy good question. I defined the item SpitzbodenRT as number like the MB_I_Reg_10

Number SpitzbodenRT "Raumtemperatur Spitzboden [%.1f °C]"          <temperature>

Number MB_I_Reg_10  "Modbus Register 10 raw value [%.1f]"    (gModbusRegister)

I just copy a Modbus Integer via the rest interface to MB_I_Reg_10

For testing purpose you can use the openhab REST API put /items/{itemname}/state command and send just the value ( for example 16587) to the MB_I_Reg_10 (by pressing the “try it” Button)

I have no problem with the modbus integer at all. Only with this one. Due to the modbus limitations, where you do not have so much memory space this integer has a space keeping format. The “High byte” seems to be the target value and the low byte is the actual value. As we here only measure the room temperature the measuring range goes from 0°C to 255°C (? this is not realy true, because 255 = 25.5°C there for it is possible that the temperture is not only the lower byte more probable is that the lower 10 to 12 bit equals the temperature.the upper 6 to 4 bit is the target value offset [here you specify normaly from -3° to +3°]), which is pretty engough. So we can transmit in only one integer 2 values. I have no documentation about that. I only can do here reverse engineering.

What I do not understand is, why is it not possible to just “AND” a number, this is a pretty fundamental function for programming languages…

Another aproach could be right and left shifting of the bits of the number. Is this somehow possible to do wihtin a rule?

I think we did not find the correct function yet :slight_smile: What I don’t understand is, the modulo operator is defined in xtend, this should definitely work…

Ok, tested (with OH1.8):

rule "MB_I_Reg_10"
when
    Item MB_I_Reg_10 changed
then
    var Number MyVal = (MB_I_Reg_10.state as DecimalType).toBigDecimal.toBigInteger
    SpitzbodenRT.sendCommand(MyVal-(MyVal/256).intValue*256) //do % manually
end

I confirm this function works with OH2 too.

It seem’s that we have to go over the middle step creating the variable MyVal.

I tried the “%” with MyVal as well as the “&” both run still into error.

I change your rule to

rule "MB_I_Reg_10"
when
    Item MB_I_Reg_10 changed
then
    var Number MyVal = (MB_I_Reg_10.state as DecimalType).toBigDecimal.toBigInteger
    SpitzbodenRT.sendCommand((MyVal-(MyVal/4096).intValue*4096)/10) //do % manually
end

This will cover the lower 12 Bits. I will start with that. Thank you very much for your help.

It is a complicated but working way to solve my problem.

Interessting for the future may be how to get the upper 4 bits.

But at the moment I’am lucky that I do not need it. :slight_smile:

Because of the not automatic appending of my item in the groups I had to reboot my device.

After rebooting the rule is not excuted an the raw value is passed through.
With the first update the rule becomes executed.

All the other rules excute direct at startup. Why is that?

Rules do not normally get executed on startup. You need to specify this explicitly by rule "..." when System started then. A rule is executed only on the event you specified: Item MB_I_Reg_10 changed.

My guess: These rules event triggers on system start. Just a coincidence.

This would be ok, but in my case the 16586 becomes written just after startup, The same to all other values. All
the other values are divided by 10 this is correct. By 16586 only the division by 10 worked (not the manually calculated modulo).

rule "MB_I_Reg_10"
when
    Item MB_I_Reg_10 changed
then
    var Number MyVal = (MB_I_Reg_10.state as DecimalType).toBigDecimal.toBigInteger
    SpitzbodenRT.sendCommand((MyVal-(MyVal/4096).intValue*4096)/10) //do % manually
end

Now I have the unfortunate situation, that in my rdd4j Database the first entry is 1658.6 and all the rest is around 20. The scale of the habmin chart is now to big (what is logical).

How can I delete the first value in rdd4j Database?
And how can I avoid that situation after the next reboot?

I did some more testing :slight_smile:

This works for me:

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import org.openhab.core.types.Command

var Number i = 2048
rule "MB_I_Reg_10"
when
    Time cron "0 45 * * * ?" // get the rule triggered
then
    while(i < 2305) {
        logInfo("test","i = {} i % 256 = {} i & 255 = {}",i, i.intValue % 256 , i.intValue.bitwiseAnd(255))
        i = i + 1
    }
end

So there is mod() and and() available… (EDIT: but the names are different…)

In question of the mysterious 16586, I think, this is not written by the rule, does this happen at every start?

I just made a reboot. It did not occur again.

Maybe my problem was anything else. This Special Temperatur was created without having any groups. After adding the groups the temperature was not shown on the sitemap and I did not become persistence data. (To test this I was writing the value via RestAPI, maybe I wrote the value to the wrong item? But why the division by ten) Because of the missing group entry in the sitemap I decided to reboot.

Should be engough for testing on my rule. Am I right, or do I have to do all the other import as well.

I just would change

SpitzbodenRT.sendCommand((MyVal-(MyVal/4096).intValue*4096)/10) //do % manually

to

SpitzbodenRT.sendCommand((MyVal.and(4095))/10) // Getting only the lower 12 bit

What is the diference between .and() and .bitwiseAnd(). I think a bitwiseAnd you only can use, if your value has the same bitlength as the “and” value.

In my case I have got a bigdecimal (16 or more bits?) and I just want to “and” 12bits (4095). So the bitwiseAnd should not work.

I will test it.

I just made the test

==> /var/log/openhab2/openhab.log <==
2016-10-25 14:52:08.946 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'MB_I_Reg_10': An error occured during the script execution: The name '<XFeatureCallImplCustom>.and(<XNumberLiteralImpl>)' cannot be resolved to an item or type.

my rule looks like

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import org.openhab.core.types.Command

rule "MB_I_Reg_10"
when
    Item MB_I_Reg_10 changed
then
    var Number MyVal = (MB_I_Reg_10.state as DecimalType).toBigDecimal.toBigInteger
//    SpitzbodenRT.sendCommand((MyVal-(MyVal/4096).intValue*4096)/10) //do % manually
    SpitzbodenRT.sendCommand((MyVal.and(4095))/10) // Getting only the lower 12 bit
end

So it does not work for me. There has to be a special trick to become such functions to work.

Do I have to reboot again?

No, the same error occurs after reboot as well.

I ried no also the bitwiseAnd()

2016-10-25 15:00:24.198 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'MB_I_Reg_10': An error occured during the script execution: The name '<XFeatureCallImplCustom>.bitwiseAnd(<XNumberLiteralImpl>)' cannot be resolved to an item or type.

I get the same error messeage.

Do I have to import anything more? Is the import to do in every rules file or just in one? (I’am lucky I only have one, but maybe you have more. In this rules file you may have an import I do not have at the moment)