I struggle with an item and its value. Item is a Number item without any further definition.
The item looks like this: (Type=NumberItem, State=0.0, Label=Avarma Mischer WW, Category=switch, Groups=[StartPersist])
First of all I don’t know why the state is “0.0” as the item value switches from “0” to “1” and back.
My rule has the following line:
if (Avarma_G1.state != 0) Avarma_G1.sendCommand(0)
I checked the condition and it returns “false”. But the state of the item stays at “0.0” and does not change to “0”.
As I have at least five more items similar to this one, which behave as expected, I don’t know why this item is different from all the others. Any idea what is wrong?
No, the item has no channel link to a thing. Source is as modbus register with status bits. I use “bitwiseAnd” to find the bit value and the rule sets the item to “0” or “1”.
Your suggestion might help but does not guarantee that the item state won’t be “0.0” instead of “0” again.
testnumber.sendCommand (0) state = 0
testnumber.sendCommand (0.0) state = 0
testnumber.sendCommand (1) state = 1
testnumber.sendCommand (0.0) state = 0.0
testnumber.sendCommand (0) state = 0.0
testnumber.sendCommand (1) state = 1
testnumber.sendCommand (0) state = 0
so you cant change from 0 to 0.0 or vice versa
maybe you could use a transformation profile. but what changes your item?
rule "Avarma Parameter"
when
Item Avarma_C36_C44 changed
then
val Integer i = (Avarma_C36_C44.state as Number).intValue
if (i.bitwiseAnd(8) > 0) {
if (Avarma_C1.state != 1) Avarma_C1.sendCommand(1)
}
else {
if (Avarma_C1.state != 0) Avarma_C1.sendCommand(0)
}
.
.
.
if (i.bitwiseAnd(256) > 0) {
if (Avarma_G1.state != 1) Avarma_G1.sendCommand(1)
}
else {
if (Avarma_G1.state != 0) Avarma_G1.sendCommand(0)
}
end
Avarma_C1 and several other bits are transferred correctly to item states. Avarma_G1 is the only item which (sometimes, not always) shows “0.0” instead of “0” as item state. The above code is the only place where the item is changed.
This is by design. OH does not have an integer type. Just a Number which can be an int or a float but you pretty nmuch have to assume it’s a float. Also note that numbers stored in rrd4j get averaged over time so even if they are integers when they go into the DB, they will become floats later as the values are averaged and decimated.
Since you are using a rule to process this and have basically hard coded the 1 and the 0, why not use one of the boolean Item types in the first palce? That’s what they are there for. If this is a sensor, you’d use Contact and your rule would be:
rule "Avarma Parameter"
when
Item Avarma_C36_C44 changed
then
val Integer i = (Avarma_C36_C44.state as Number).intValue
if (i.bitwiseAnd(8) > 0) {
if (Avarma_C1.state != 1) Avarma_C1.postUpdate(OPEN)
}
else {
if (Avarma_C1.state != 0) Avarma_C1.postUpdate(CLOSED)
}
.
.
.
if (i.bitwiseAnd(256) > 0) {
if (Avarma_G1.state != 1) Avarma_G1.postUpdate(OPEN)
}
else {
if (Avarma_G1.state != 0) Avarma_G1.postUpdate(CLOSED)
}
end
If it’s an actuator you’d use a Swith and use ON/OFF instead of OPEN/CLOSED. These are stored in persitence as integers and they are enumerations.
Note I change the sendCommands to postUpdates. When changing the state of an Item you use postUpdate. Only when you are requesting what ever is attached to the Item to do something should you use sendCommand. You would never command a sensor.
Another way to handle this would be to use a script transformation profile instead of a rule. You would like the Chanel that is currently lined to Avarma_C36_C44 to Acarma_C1. You’d ad a SCRIPT transformation profile, choose Rules DSL as the language and the code would be:
if (Integer.parseInt(input).intValue.bitwiseAnd(8) > 0) return OPEN;
else return CLOSED;
Or you can use the ternary operator
return if(Integer.parseInt(input).intValue.bitwiseAnd(8) > 0) OPEN else CLOSED
In fact I just wanted the same representation when I started my project. Source is a 16 bit unsigned int modbus register, representing 16 different logical parameters of my heat pump. I only need (as of now) 5 from the first 8 bits and as the bits can have the value “0” or “1” I’ve chosen the number representation for my placeholder items.
Using “sendCommand” is intentional. The status bits start or stop an external heat circuit pump, trigger a mixer actuator to close or open a circuit (domestic hot water or heat circuit), …
Changing my placeholder items triggers other rules because there are dependencies between pumps and actuators.
I guess linking up to 16 items to a single modbus channel isn’t a very good idea. I always had trouble when I tried to link more than 1 item to a channel in other projects.
I have linked a number item to the modbus data channel of my “Avarma_C36_C44” thing. The DSL rule updates the placeholder items which have a new value which then triggers several other rules. Hard enough to keep cpu consumption under 20% that way.
Don’t forget that the main reason Items exist is to abstract from the variations of the end devices. A Switch is a Switch in OH whether it’s connected to modbus or Zwave or HTTP. That normalization is one of the key features that allows OH to bridge between more than 400 distinct technologies. Not using a Switch in a place where a switch is clearly what it is will potentially cause challenges for you down the road beyond even this current problem.
I’ve not experienced the same thing but I guess YMMV. But it’s definitely a bug if it doesn’t work and an issue should be filed.
Then either the hardware is under powered (is this an RPi 3?) or the rules are suboptimal (e.g. busy waits perhaps). Do any of these rules remain un-triggered long enough to become unloaded? That could account for some of the CPU problem. But with just this little bit of information there is no reason why OH should be using that much CPU based only on that.
But why worry about keeping the CPU under 20%? That basically means your machine is doing nothing at all 80% of the time.
thanks again for your input. I’m going to think about it. But as my whole home automation project has nearly 5000 lines of DSL code and more than 1300 items I’ll have to rework step by step.
The main reason for keeping the average CPU load low is, that I have some tasks which demand quite a lot CPU power. So I have to keep the load low for frequently occuring trigger events.
I don’t think it’s a hardware issue (RPi 4 with 8 GB RAM). My home automation has just grown to an extend I did not expect within the last 6 years and some rules could definitely be optimized. But the old rule “never touch a running system” is still valid.
Long running tasks like changing the position of a mixer actuator from “OPEN” to “CLOSE” (takes up to 140 seconds) are embedded in a “createTimer” call so that the sleep time while waiting for the actuator does not affect the rule itself. Downside of this is that changing the rule while the timer is active results in some log errors and an unknown mixer position. So I had to implement a “self calibration feature”.
Long story short: I was just wondering why my “integer switches” had float values every now and then. As they are persisted with “restore on startup” and with your explanations I now know why.
If you put the timer into the cache, when the rule is unloaded on the change it will get cancelled automatically. That will avoid the error.
If you put anything into the shared cache and it’s referenced by more than one rule, so long as at least one of the rules remains the data in the cache will remain. That could reduce the amount of times the calibration needs to run or eliminate it entirely.
In the other rules languages and hopefully soon in Rules DSL you could use Item metadta. This information gets saved to the JSONDB and persists across boots of OH. That could be another way to avoid that sort of problem.
Imagine the mixer is at 0% (fully closed) and Mixer.sendCommand(100) (=fully opened) is executed. It takes 140 seconds for the motor to fully open the mixer.
First problem: the zigbee actor has a maximum runtime of 120 seconds. To achieve a full circle I have to split the motion into two partial motions within the timer by sending “STOP” to the zigbee actor after half of the total runtime.
Second problem: If the timer is cancelled at any time within the 140 seconds there is no way to tell where the motor stopped. In fact the mixer item state is “100” but the real position could be anywhere between 0 and 100. And I cannot think of an easy way to tell that the last motion was interrupted and how it can be resumed.
Never the less your answer is interesting. How can I put a “createTimer” call into the shared cache?
So if you can keep that timer alive even when the rule unloads the STOP and START can be reissued without problem. You could create a single rule in a file all by itself that periodically just pulls the timer(s) from the sharedCache and as long as you don’t modify that file the timers will persist even when you modify the rule where the timer was created. Only if both rules become unloaded will the timer become canceled.
That should reduce this case down to just occurring when OH restarts.
If you record of the two commands (in an Item with restoreOnStartup, or Item metadata) then you’ll always know how much time has passed. So on an OH reboot you can trigger a rule, check how much time has passed and from there determine how much the mixer has moved and whether you need to issue the next command.
You probably still need some calibration logic because time based monitoring like this always has errors that accumulate. But you can reduce how often that needs to run.