Problem with item state variable

I am trying to write a simple script that will turn on my sump pump via my Zooz Z-Wave Plus Power Switch ZEN15 and turn it off when the wattage being drawn is less than 275 (when there is no more water left). It turns on but never turns off. I have tried to initialise the cur_wattage variable as DecimalType, int and Number but always has a problem with the while condition. If I don’t initialize a variable for Watts I get the same error. Under certain scenarios I can log the wattage and it looks like this [INFO ] [pse.smarthome.model.script.mySumpLog] - Seconds (-1): Watts (Type=NumberItem, State=193.927, Label=Watts, Category=Energy)

Rule:

var int i = 0
var NumberItem cur_wattage = 0

rule "Turn Sump Pump On - Afternoon"

when Time cron "01 59 15 ? * * *"

then Sump_Pump.sendCommand(ON)
Thread::sleep(2000)
cur_wattage = Watts
while (cur_wattage > 275)
{
    Thread::sleep(1000)
    cur_wattage = Watts
    i--
    logInfo("mySumpLog", "Seconds (" + i + "): " + Watts)
}
Sump_Pump.sendCommand(OFF)
end

Log:

2019-08-29 16:14:13.113 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule ‘Turn Sump Pump On - Afternoon’: Unknown variable or command ‘>’; line 12, column 8, length 17

What is Watts ?
Looks like it is an Item. That’s a complex object with label, name, etc. properties.
Here you are probably interested in its state so you would use
cur_wattage = Watts.state
after
var Number cur_wattage = 0

But unfortunately the rule is a bit of a horror. Sleeps and while loops are almost always to be avoided in openHABs event driven system.

I’ll sketch a rule, and if you can figure how it works you will get the approach

rule "Turn Sump Pump On - Afternoon"
when
   Time cron "01 59 15 ? * * *"
then
   Sump_Pump.sendCommand(ON)
end

rule "Turn Sump Pump Off - run dry"
when
   Item Watts changed
then
   if (Watts.state <  275 && Sump_Pump.state == ON) {
      Sump_Pump.sendCommand(OFF)
   }
end

You might need something else if you want the pump to stop before it runs dry, say after a fixed time

1 Like

Hi @rossko57 Thank you so much for your help. Your version worked perfectly. If you can help me understand why my code always has a problem at the while loop condition where i keep getting the error:

‘Watts’ is not a member of ‘org.eclipse.smarthome.core.library.items.NumberItem’
I am changed my code to stop using the variable so the condition looks like while (ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps.Watts.state > 275). (its the same error if i use Watts.state or just Watts.)

  1. Is the issue that the variable type for the item Watts cannot do the calculation or is it another reason having to do with openhab rules in general (that you alluded to in your first comment)?

here is my full adjusted rule that gets the error:
i am also trying to see how long it takes to empty the pit to calculate how much water was in there.
var int i = 0

rule "Turn Sump Pump On - Afternoon"

when Time cron "40 06 10 ? * * *"

then Sump_Pump.sendCommand(ON)

while (ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps.Watts.state > 275)
{
    Thread::sleep(1000)
    i++
    logInfo("mySumpLog", "Seconds (" + i + "): " + ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps.Watts.state)
}
Sump_Pump.sendCommand(OFF)
end

While you rule may work, it is holding on a thread for a potentially long time and that’s dangerous:
See:

There is a better approach using timers:
Your rule would become:

var timer = null // global variable
var secondsCounter = 0
rule "Turn Sump Pump On - Afternoon"
when
    Time cron "40 06 10 ? * * *"
then
    Sump_Pump.sendCommand(ON)
    timer = createTimer(now, [ |
        if(!ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps.Watts.state > 275) {
            logInfo("mySumpLog", "Seconds (" + secondsCounter.toString + "): " + ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps.Watts.state)
            timer.reschedule(now.plusMillis(1000))
        } else {
            timer = null
            secondsCounter = 0
            Sump_Pump.sendCommand(OFF)
        }
    ])
end

The issue is that the item is Watts not ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps.Watts
To get the Wattage you need to use Watts.state
BUT that is a Number with a Dimension, you need to convert it to a normal number:

Watts.getStateAs(QuantityType).doubleValue

So the rule is now:

var timer = null // global variable
var secondsCounter = 0
rule "Turn Sump Pump On - Afternoon"
when
    Time cron "40 06 10 ? * * *"
then
    Sump_Pump.sendCommand(ON)
    timer = createTimer(now, [ |
        if(!Watts.getStateAs(QuantityType).doubleValue > 275) {
            logInfo("mySumpLog", "Seconds (" + secondsCounter.toString + "): " + Watts.state.toString)
            timer.reschedule(now.plusMillis(1000))
        } else {
            timer = null
            secondsCounter = 0
            Sump_Pump.sendCommand(OFF)
        }
    ])
end

An alternative, perhaps a better alternative, is to convert the number you are comparing it to to a QuantityType.

if(!Watts.state > 275|"kWh")

or what ever is the appropriate unit. Then you don’t really need to know what units the Item is carrying (e.g. Watts could be using Ws or Wh) and the comparison will work. That’s what makes Units of Measure worth it despite all the trouble they cause in our Rules and elsewhere.

2 Likes

I was looking for this solution too but I’m a bit cold.
Thanks

Would you show us a line from your events.log that shows the Item you are interested in being updated. We’d have a better idea of what the heck it is.

I repeat that while-loops and sleeps are horrors best avoided.
You want to measure pump runtime, from start to empty?

yes, although I could get that with your version by just logging when the pump started and another log when it finished, but if not too taxing would be nice to get a number (eg “pump ran for 45 seconds”)

here are the last few lines from the events log:

2019-08-30 08:27:25.540 [me.event.ThingUpdatedEvent] - Thing ‘zwave:device:2cf9e7cd:node4’ has been updated.
2019-08-30 08:32:01.527 [vent.ItemStateChangedEvent] - zwave_device_2cf9e7cd_node4_sensor_luminance changed from 0.87 to 20.55
2019-08-30 08:34:50.954 [vent.ItemStateChangedEvent] - zwave_device_2cf9e7cd_node4_sensor_luminance changed from 20.55 to 0.87
2019-08-30 08:37:33.716 [me.event.ThingUpdatedEvent] - Thing ‘zwave:device:2cf9e7cd:node4’ has been updated.
2019-08-30 08:45:01.007 [ome.event.ItemCommandEvent] - Item ‘Sump_Pump’ received command ON
2019-08-30 08:45:01.010 [vent.ItemStateChangedEvent] - Sump_Pump changed from OFF to ON
2019-08-30 08:45:02.106 [vent.ItemStateChangedEvent] - Watts changed from 0 to 301.564
2019-08-30 08:45:02.109 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 0 to 301.564
2019-08-30 08:45:03.105 [vent.ItemStateChangedEvent] - Watts changed from 301.564 to 346.892
2019-08-30 08:45:03.107 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 301.564 to 346.892
2019-08-30 08:45:05.106 [vent.ItemStateChangedEvent] - Watts changed from 346.892 to 327.589
2019-08-30 08:45:05.106 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 346.892 to 327.589
2019-08-30 08:45:31.105 [vent.ItemStateChangedEvent] - Watts changed from 327.589 to 293.135
2019-08-30 08:45:31.106 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 327.589 to 293.135
2019-08-30 08:45:32.119 [vent.ItemStateChangedEvent] - Watts changed from 293.135 to 246.803
2019-08-30 08:45:32.122 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 293.135 to 246.803
2019-08-30 08:45:35.111 [vent.ItemStateChangedEvent] - Watts changed from 246.803 to 228.867
2019-08-30 08:45:35.114 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 246.803 to 228.867
2019-08-30 08:45:45.004 [ome.event.ItemCommandEvent] - Item ‘Sump_Pump’ received command OFF
2019-08-30 08:45:45.006 [vent.ItemStateChangedEvent] - Sump_Pump changed from ON to OFF
2019-08-30 08:45:45.206 [vent.ItemStateChangedEvent] - Watts changed from 228.867 to 0
2019-08-30 08:45:45.207 [vent.ItemStateChangedEvent] - ZWaveNode2ZEN15PowerSwitch_ElectricMeterAmps changed from 228.867 to 0
2019-08-30 08:47:42.318 [me.event.ThingUpdatedEvent] - Thing ‘zwave:device:2cf9e7cd:node4’ has been updated.
2019-08-30 08:57:50.922 [me.event.ThingUpdatedEvent] - Thing ‘zwave:device:2cf9e7cd:node4’ has been updated.
2019-08-30 09:07:58.629 [me.event.ThingUpdatedEvent] - Thing ‘zwave:device:2cf9e7cd:node4’ has been updated.

this is from the openhab.log (i had a couple rules just turning on and off for a fixed period of time (ie 45 seconds and logging:

2019-08-29 16:20:44.157 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model ‘dailysump-morning-night.rules’
2019-08-29 20:45:01.137 [INFO ] [pse.smarthome.model.script.mySumpLog] - Pump turned on
2019-08-29 20:45:29.005 [INFO ] [pse.smarthome.model.script.mySumpLog] - Wattage when turned off(night): Watts (Type=NumberItem, State=222.564, Label=Watts, Category=Energy)
2019-08-29 20:45:30.002 [INFO ] [pse.smarthome.model.script.mySumpLog] - Pump turned off
2019-08-30 08:45:01.007 [INFO ] [pse.smarthome.model.script.mySumpLog] - Pump turned on
2019-08-30 08:45:44.004 [INFO ] [pse.smarthome.model.script.mySumpLog] - Wattage when turned off(morning): Watts (Type=NumberItem, State=228.867, Label=Watts, Category=Energy)
2019-08-30 08:45:45.004 [INFO ] [pse.smarthome.model.script.mySumpLog] - Pump turned off

You seem to have two versions of the same Item here. That’s okay, you are allowed to link two Items to the same channel, but you probably only need one and can delete one.

You just need to develop that idea.

var Number pumpStamp = 0     // global var accessible to both rules

rule "Turn Sump Pump On - Afternoon"
when
   Time cron "01 59 15 ? * * *"
then
   Sump_Pump.sendCommand(ON)
   pumpStamp = now.millis / 1000   //store datetime in seconds
end

rule "Turn Sump Pump Off - run dry"
when
   Item Watts changed
then
   if (Watts.state <  275 && Sump_Pump.state == ON) {
      Sump_Pump.sendCommand(OFF)
      var Number duration = ( (now.millis / 1000) - pumpStamp ).intValue
      logInfo("empty", "Pump run " + duration.toString + " secs")
   }
end

If you need a running counter you should use @vzorglub timer based approach.