Problem with Rule in OH 2.1

Im currently rewriting my rule and have massive problems im ob openhabian 2.1:

Rule:

Rule "Livingroom Demand"

when
    Item LivingrTemp received update or        //Current Tmperature in the Room
    Item LivingrTempTarget received update            //Target Tmperature in the Room 
then 
    if((LivingrHeatMan.state="ON")){}               //Is manual control mode for the Room Set ( Set Valves via Valve and manually turn on or off Boiler at Switch)

    else if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state="ON")){
     logWarn("Demo","This is a log entry of type Warn!")   
    }  // current temp - buffer lower then target but demand already on

    else if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state="OFF")){  // current temp - buffer lower then target turn on demand
    LivingrHeatDemand.postUpdate(ON)     
    logWarn("Demo","This is a log entry of type Warn!")
    }
    else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state="OFF")){
    logWarn("Demo","This is a log entry of type Warn!")    
    } // current temp - buffer higher then target but demand already off
    
    else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state="ON")){  // current temp - buffer higher then target turn off demand
    LivingrHeatDemand.postUpdate(OFF)
    logWarn("Demo","This is a log entry of type Warn!")     
    }
 // the check if the state is already appropiate and then do nothing will reduce unnecesarry rule triggers

end

Error:

[.script.engine.ScriptExecutionThread] - Rule 'Livingroom Demand': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.core.library.items.SwitchItem.setState(org.eclipse.smarthome.core.types.State) on instance: LivingrHeatMan (Type=SwitchItem, State=OFF, Label=Manual Heating Mode Livingroom, Category=null, Groups=[GroupHeatingManual])

I looked multiple times into names etc. but i cant seem to find a error any thoughts?

I’m not sure myself. But can you try this?

    if (LivingrHeatMan.state == ON) {}
1 Like

I think you just left out an equals:
if(LivingrHeatMan.state==“ON”){}

Both Tipps diddnt do the trick but the error changed to:

2017-08-11 09:59:28.376 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'Livingroom Demand': An error occurred during the script execution: The name '<XFeatureCallImplCustom>.state' cannot be resolved to an item or type.

current rule state:

ule "Livingroom Demand"

when
    Item LivingrTemp received update or        //Current Tmperature in the Room
    Item LivingrTempTarget received update            //Target Tmperature in the Room 
then 
    if(LivingrHeatMan.state == "ON"){}               //Is manual control mode for the Room Set ( Set Valves via Valve and manually turn on or off Boiler at Switch)

    else if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == "ON")){
     logWarn("Demo","This is a log entry of type Warn!")   
    }  // current temp - buffer lower then target but demand already on

    else if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == "OFF")){  // current temp - buffer lower then target turn on demand
    LivingrHeatDemand.postUpdate(ON)     
    logWarn("Demo","This is a log entry of type Warn!")
    }
    else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == "OFF")){
    logWarn("Demo","This is a log entry of type Warn!")    
    } // current temp - buffer higher then target but demand already off
    
    else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == "ON")){  // current temp - buffer higher then target turn off demand
    LivingrHeatDemand.postUpdate(OFF)
    logWarn("Demo","This is a log entry of type Warn!")     
    }
 // the check if the state is already appropiate and then do nothing will reduce unnecesarry rule triggers

end

As @Dries gave an example above: Remove the quotes around the ONs and OFFs. This could be a problem.

if(LivingrHeatMan.state == ON){}  

same like before:

if(LivingrHeatMan.state == ON){}               //Is manual control mode for the Room Set ( Set Valves via Valve and manually turn on or off Boiler at Switch)

    else if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == ON)){
     logWarn("Demo","This is a log entry of type Warn!")   
    }  // current temp - buffer lower then target but demand already on

    else if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == OFF)){  // current temp - buffer lower then target turn on demand
    LivingrHeatDemand.postUpdate(ON)     
    logWarn("Demo","This is a log entry of type Warn!")
    }
    else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == OFF)){
    logWarn("Demo","This is a log entry of type Warn!")    
    } // current temp - buffer higher then target but demand already off
    
    else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == ON)){  // current temp - buffer higher then target turn off demand
    LivingrHeatDemand.postUpdate(OFF)
    logWarn("Demo","This is a log entry of type Warn!")     
    }
 // the check if the state is already appropiate and then do

I wonder if this part is correct:

((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && (LivingrHeatDemand.state == ON))

should it be like this?

(LivingrTempTarget.state as Number > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) && LivingrHeatDemand.state == ON)

THANKS FOR THE HELP

Maybe this could work:

else if (((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number)) && (LivingrHeatDemand.state == ON))

Make sure that the comparison is in it’s own brackets (pseudo code for better understanding):
( (target>tmp) && demand== ON )

Okay makes sense so in the second part of the comparison i also do a subtraction so it would look like this
((target> current-tmp)&&demand==ON)

–thanks

Exactly. :slight_smile:

How about:

 if ( LivingrHeatMan.state != ON) {                //simplify the nesting by testing the negative
     if (LivingrHeatDemand.state == ON) {
        if ((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number)) {
            //current  lower than target but demand already on hence a NO-OP
            }
            else {  LivingrHeadDemand.postUpdate(OFF)
            }
       else {    //demand state is OFF
           if ((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number - LivingrTempBuffer.state as Number) {
                LivingrHeatDemand.postUpdate(ON)
           
           else {  // current temp higher than target but demand already off so a NO-OP
           }
} // end of LivingrHeatMan.state != ON test

Thanks a lot for that idea i will definatly consider this but would like to understand why its not working with my code first so very strange: i chaged to:

rule "Livingroom Demand"

when
    Item LivingrTemp received update or        //Current Tmperature in the Room
    Item LivingrTempTarget received update            //Target Tmperature in the Room 
then 
    if(LivingrHeatMan.state == ON){}               //Is manual control mode for the Room Set ( Set Valves via Valve and manually turn on or off Boiler at Switch)

    else if((LivingrTempTarget.state as Number > LivingrTemp.state as Number ) && LivingrHeatDemand.state == ON){
     logWarn("Demo","This is a log entry of type Warn!")   
    }  // current temp - buffer lower then target but demand already on

    else if((LivingrTempTarget.state as Number > LivingrTemp.state as Number ) && LivingrHeatDemand.state == OFF){  // current temp - buffer lower then target turn on demand
    LivingrHeatDemand.postUpdate(ON)     
    logWarn("Demo","This is a log entry of type Warn!")
    }
    //else if((LivingrTempTarget.state as Number < LivingrTemp.state as Number ) && LivingrHeatDemand.state == OFF){
    //logWarn("Demo","This is a log entry of type Warn!")    
    //} // current temp - buffer higher then target but demand already off
    
    //else if((LivingrTempTarget.state as Number < LivingrTemp.state as Number ) && LivingrHeatDemand.state == ON){  // current temp - buffer higher then target turn off demand
    //LivingrHeatDemand.postUpdate(OFF)
    //logWarn("Demo","This is a log entry of type Warn!")     
   // }
 // the check if the state is already appropiate and then do nothing will reduce unnecesarry rule triggers

end

it than gives me :

2017-08-11 12:18:37.222 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'newheating.rules' has errors, therefore ignoring it: [33,68]: missing '>' at 'as'

[37,68]: missing '>' at 'as'

if i comment the last two else if i dong get a error and it works. but can it really not work with < instead of > ?

so it works if i only use >. Is this an OH Limitation that i cant use <??? That was interseting. So know another question i change the temptarget via an setpoint in 0.1 steps between 16 and 23 degrees. the logs the gui shows 19.3 as an example. but the log shows me that the actual value is something like 19.2999999999999. How does this come? how can i solve it? just by manually setting the temp to 19.3 once via rest?

Thanks a lot for all your help

Simply leave the as Number part out. Then it should work fine.

As a side note, I think you’ll want to use LivingrHeatDemand.sendCommand(ON) and LivingrHeatDemand.sendCommand(OFF) unless you really only want to update the GUI.



rule "Livingroom Demand"

when
    Item LivingrTemp received update or        //Current Tmperature in the Room
    Item LivingrTempTarget received update            //Target Tmperature in the Room 
then 
    if(LivingrHeatMan.state == ON){}               //Is manual control mode for the Room Set ( Set Valves via Valve and manually turn on or off Boiler at Switch)

    else if((LivingrTempTarget.state > LivingrTemp.state) && LivingrHeatDemand.state == ON){
        logWarn("Livingroom Demand","LivingrTempTarget.state > LivingrTemp.state) && LivingrHeatDemand.state == ON")   
    }  // current temp - buffer lower then target but demand already on

    else if((LivingrTempTarget.state > LivingrTemp.state ) && LivingrHeatDemand.state == OFF){  // current temp - buffer lower then target turn on demand
        LivingrHeatDemand.postUpdate(ON)     
        logWarn("Livingroom Demand","LivingrTempTarget.state > LivingrTemp.state ) && LivingrHeatDemand.state == OFF")
    }
    else if((LivingrTempTarget.state < LivingrTemp.state) && LivingrHeatDemand.state == OFF){
        logWarn("Livingroom Demand","LivingrTempTarget.state < LivingrTemp.state) && LivingrHeatDemand.state == OFF")    
    } // current temp - buffer higher then target but demand already off
    
    else if((LivingrTempTarget.state < LivingrTemp.state) && LivingrHeatDemand.state == ON){  // current temp - buffer higher then target turn off demand
        LivingrHeatDemand.postUpdate(OFF)
        logWarn("Livingroom Demand","LivingrTempTarget.state < LivingrTemp.state) && LivingrHeatDemand.state == ON")     
    }
 // the check if the state is already appropiate and then do nothing will reduce unnecesarry rule triggers

edit: Added a bit more meaningful logging

Hey Marco,

thanks a lot deleting the states did the Deal. Wy is that exactly?
Also regarding the sendUpdate. I always thought for non physical Items like this ( just a proxy switch in OH) i should use sendUpdate and always when i want to do something with a physical Device i should use sendCommand. That confuses me a bit now.

Item is the item itself
Item.state is the state of the item as a state.
So, if the item is of type OnOffType, this would be ON or OFF (without quotation marks!)
"ON" is a string, where ON is a state, please keep that in mind

If dealing with numbers, you have to cast the state to a NumberType, so use
(Item.state as Number) or (Item.state as DecimalType). If comparing two item states of type number, make sure the brackets are correct:

(item1.state as Number < item2.state as Number) //WRONG
((item1.state as Number) < (item2.state as Number)) //CORRECT

So the rule should be like

rule "Livingroom Demand"
when
    Item LivingrTemp changed or        //better trigger on changed
    Item LivingrTempTarget changed
then 
    if(LivingrHeatMan.state != ON) {
        logInfo("LivingDem","Livingromm Heat is auto")
        logInfo("LivingDem","Target Temp  {}°C",LivingrTempTarget.state)
        logInfo("LivingDem","Current Temp {}°C",LivingrTemp.state)
        if((LivingrTempTarget.state as Number) > (LivingrTemp.state as Number )){
            logInfo("LivingDem","It's cold.")
            if(LivingrHeatDemand.state == ON) {
                logInfo("LivingDem","The heater is already on!")
            }
            else if(LivingrHeatDemand.state == OFF){
                logInfo("LivingDem","Let's switch the heater on!")
                LivingrHeatDemand.postUpdate(ON)
            }
        }
        else if((LivingrTempTarget.state as Number) < (LivingrTemp.state as Number )){
            logInfo("LivingDem","It's hot.")
            if(LivingrHeatDemand.state == ON) {
                logInfo("LivingDem","Let's switch the heater off!")
                LivingrHeatDemand.postUpdate(ON)
            }
            else if(LivingrHeatDemand.state == OFF){
                logInfo("LivingDem","The heater is already off!")
            }
        }
    }
end

Okay so thats good info but just so that i get it 100%

I dont fully understand when i can work with he Item only and not the state.

In addition my current working code now looks like the following:

then 
    if(LivingrHeatMan.state == ON){}               //Is manual control mode for the Room Set ( Set Valves via Valve and manually turn on or off Boiler at Switch)

    else if((LivingrTempTarget.state > LivingrTemp.state ) && LivingrHeatDemand.state == ON){
     logWarn("Demo","Target higher then current demand already on")   
    }  // current temp - buffer lower then target but demand already on

    else if((LivingrTempTarget.state  > LivingrTemp.state  ) && LivingrHeatDemand.state == OFF){  // current temp - buffer lower then target turn on demand
    LivingrHeatDemand.sendCommand(ON)     
    logWarn("Demo","Target higher then current demand off")
    }
    else if(( LivingrTempTarget.state < LivingrTemp.state ) && LivingrHeatDemand.state == OFF){
    logWarn("Demo","current higher then target demand already off")    
    } // current temp - buffer higher then target but demand already off
    
    else if((LivingrTempTarget.state  <  LivingrTemp.state  ) && LivingrHeatDemand.state == ON){  // current temp - buffer higher then target turn off demand
    LivingrHeatDemand.sendCommand(OFF)
    logWarn("Demo","current higher then target  demand on")     
    }
 // the check if the state is already appropriate and then do nothing will reduce unnecessary rule triggers

end

as you can see i am know working with states. But always without as number and it works. Also as you can see i only have a single backet around the full comparssion.
How would that look like if i add another var into the code? like this?

((item1.state as Number) < ((item2.state as Number)-var))

Thanks a lot for all this help