Simple if statement not working - aarrgghh

Hi all,

I’ve been away from OH for the past few months, lots of work things going on during the pandemic…

I’ve just popped back into some rules to add a couple of little bits and one is just blowing my mind. I’m sure it’s something simple but I just can’t spot it…

Premise:

I have presence detection from my iphone, I have set a few distances from home as HOME, LOCAL, AWAY. These are then used to do things within OH, ie, if I’m HOME set my presence to ON, and if I’m away trun down the thermostat etc.

I want to add in a quick IF to my case statement where if previous location was away and current is local then I will assume I am coming home so let’s get the thermostat on to warm the house up rather than wait until I’m actually home. Simple you’d think…

The rule itself runs so I’ll only post relevant snippets:

rule "GP iPhone Location detection"
when
    Item GP_iPhone_Location changed
then
    val PointType phone_location = GP_iPhone_Location.state as PointType
    val int distance = phone_location.distanceFrom(home_location).intValue()
    val int workdistance = phone_location.distanceFrom(GP_work_location).intValue()

    // Calculate the current location for GP
    var GPCurrLoc = "UNKNOWN"
    switch distance {
        case workdistance <= 300:                             GPCurrLoc = "WORK"
        case distance <= 200:                                 GPCurrLoc = "HOME"
        case distance > 200     && distance <= 10000:         GPCurrLoc = "LOCAL"
        case distance > 10000:                                GPCurrLoc = "AWAY"
        }

    // Publish the current state when it changes
        vGPCurrLoc.sendCommand(GPCurrLoc)
        vGPPrevLoc.sendCommand(vGPCurrLoc.previousState(true, "influxdb").state.toString)

So this bit works a treat, it sets my current location and then updates the variable vGPCurrLoc and also set the previous location variable vGPPrevLoc from the influxdb I have set up for it.

This works as I broadcast the current and previous location to the logs:

2020-11-07 12:24:03.113 [INFO ] [ipse.smarthome.model.script.iCloudGP] - GP Current Location = HOME
2020-11-07 12:24:03.120 [INFO ] [ipse.smarthome.model.script.iCloudGP] - GP Previous Location = LOCAL

Perfect…

So, now for the actual rule:

//icloud GP iPhone rule
rule "GP iPhone Location detection - update based on vGPCurrLoc"
when
    Item vGPCurrLoc changed
then
    // Set Home Item based on vGPCurrLoc to set vPresent
    if(vGPCurrLoc.state.toString == "HOME") 
    {
        GP_iPhone_Home.postUpdate(ON)
        logInfo(logName, "GP New location is HOME")
        vThermostatCase.sendCommand(2) // ThermostatCase rule 2
            sendBroadcastNotification("GP New location is HOME")
    }
    else
    {
        // I am away so change vPresent = OFF
        GP_iPhone_Home.postUpdate(OFF)
        // do some things depending on the state of vGPCurrLoc
        switch vGPCurrLoc.state.toString {
            case "LOCAL":{
                logInfo(logName, "GP New location is LOCAL") // Post state to log              
                // Turn on Thermostat to warm up if coming home
                if(vGPPrevLoc.state.toString == "AWAY")
                {
                    vThermostatCase.sendCommand(2) // ThermostatCase rule 2
                    sendBroadcastNotification("GP Coming Home - Thermostat 2")
                }
                //if(vGPCurrLoc.state.toString != vGPPrevLoc.state.toString)
                //{
                sendBroadcastNotification("GP New location is LOCAL")
                //}   
            }

            case "AWAY":{
                logInfo(logName, "GP New location is AWAY") // Post state to log
                //if(vGPCurrLoc.state.toString != vGPPrevLoc.state.toString)
                //{
                    sendBroadcastNotification("GP New location is AWAY")
                //}
            }
etc etc etc more cases here...

so, this whole rule works, when a location changes, ie I’ve moved, it runs the rule.

If I’m HOME then update my presence variable and turn the thermostat to rule 2 - works, tick

The LOCAL case is the issue, the first part works, so if I am LOCAL the logs show that I’m LOCAL, but the IF just doesn’t seem to run, at first I thougt maybe I’m never marked as AWAY so it wouldn’t run but I can see in the logs that I have been AWAY and then moved to LOCAL so it should trigger.

I can also hover over the variables in VSC and see the values of the vGPCurrLoc and vGPPrevLoc and they also show correctly…

I just don’t get it…

Any ideas / thoughts / pointers / you’re an idiot comments welcome please…

I suppose you might log out the thing you are testing, to see if it is what you thought it was at the moment the rule executes.
vGPPrevLoc.state.toString

When does that get updated, does that take time, do you expect that to have been completed by now?

Ah, you might be into something there. I wonder if the IF statement is running before the vGPPrevLoc is being updated in influx.

Any one have any real life timings for how long that process can take…I wonder if a simple pause step would fix it…

I can’t tell you any timings, however I think both rules would fit into one which would give you the chance to already know the previous state.
Your first rule runs on every changed event of GP_iPhone_Location, although the most important lines should be really performed only in the changed event of vGPCurrLoc ( sending a command if the state doesn’t change is not necessary). Why not use this part also for your second rule?
Keep the new calculated state in a local variable and work with that one instead of “waiting” for the changed item state:

Something like this:

rule "GP iPhone Location detection"
when
    Item GP_iPhone_Location changed
then
    val PointType phone_location = GP_iPhone_Location.state as PointType
    val int distance = phone_location.distanceFrom(home_location).intValue()
    val int workdistance = phone_location.distanceFrom(GP_work_location).intValue()

    // Calculate the current location for GP
    var GPCurrLoc = "UNKNOWN"
    switch distance {
        case workdistance <= 300:                             GPCurrLoc = "WORK"
        case distance <= 200:                                 GPCurrLoc = "HOME"
        case distance > 200     && distance <= 10000:         GPCurrLoc = "LOCAL"
        case distance > 10000:                                GPCurrLoc = "AWAY"
        }
       // do the following only if vGPCurrLoc is suppossed to be chsanged!
       if ( GPCurrLoc != vGPCurrLoc.state.toString) {
             var GPPrevLoc =  vGPCurrLoc.state.toString // the old state of vGPCurrLoc will be the new previous state.
             vGPPrevLoc.sendCommand(GPPrevLoc)
             vGPCurrLoc.sendCommand(GPCurrLoc)
             //when reaching here your are in the event `GPCurrLoc changed` 
             if(GPCurrLoc == "HOME")  // check the local variable instead of the item state
                   {
                       GP_iPhone_Home.postUpdate(ON)
                       logInfo(logName, "GP New location is HOME")
                       vThermostatCase.sendCommand(2) // ThermostatCase rule 2
                       sendBroadcastNotification("GP New location is HOME")
                  }
            else
                 {
                 // I am away so change vPresent = OFF
                 GP_iPhone_Home.postUpdate(OFF)
                // do some things depending on GPCurrLoc
                switch GPCurrLoc {
                 case "LOCAL":{
                          logInfo(logName, "GP New location is LOCAL") // Post state to log              
                         // Turn on Thermostat to warm up if coming home
                        if(GPPrevLoc == "AWAY")
                            {
                                vThermostatCase.sendCommand(2) // ThermostatCase rule 2
                                sendBroadcastNotification("GP Coming Home - Thermostat 2")
                             }
                        //if(GPCurrLoc != GPPrevLoc)
                             //{
                                 sendBroadcastNotification("GP New location is LOCAL")
                             //}   
                          }

               case "AWAY":{
                         logInfo(logName, "GP New location is AWAY") // Post state to log
                         //if(GPCurrLoc != GPPrevLoc)
                           //{
                                sendBroadcastNotification("GP New location is AWAY")
                            //}
               }
                //etc etc etc more cases here...

            }

I hope you get the point. The code is writtten on the website, so no code checks done! Sorry for indentions, I tried to make it readable.

Hi,

That’s neat…there are quite a few of the older rules that I think could be rewritten now I know / understand more about scripting…I like your solution…thanks.

Ps - I’ve just added in a 10 second timer and some logging to see what the current and previous states are at each point in time…It does make sense that the first and the second rules are running at the same time so the IF is bypassed as the first rule hasn’t updated the previous location…

Will report back if it works.

EDIT - First trip outside the area, now works perfectly.

Seems it just needed a few seconds to fill the previous value and the 2 rules just ran at the same time. I may well rewrite the rules as per the above, or perhaps do the second rule as an on change of previous location rather than current so it will only run when I’ve moved from one zone to another, that might be a neater solution all round.

Thanks for your pointers.