Weather based lights Rule

I have a rule that turns on my indoor dimmer lights when cloudiness from OpenWeatherMap is over a certain percentage. It works great, but now I’m trying to turn on the dimmer lights to different levels based on the cloudiness percentage. For example if cloudiness is 30% set lights to 40%, if cloudiness is 80% set lights to 60%… . I have tried various things but have been unable to figure it out. I have searched online for something that might be similar but I haven’t found anything. If anybody could point me in the right direction to get this rule working it would be greatly appreciated. Here is the current working rule:

 rule "Automated Weather Lights"
 when
     Item TimeOfDay changed to Day or
     Item owmCurrentCloudiness changed
then
     if(TimeOfDay.state.toString == "Day") {

            // Get the new light state
            val Number state = if(owmCurrentCloudiness.state as Number > 0.30) "20" else "0"
             // Toggle any non-overridden lights
            GWeatherLights.members.forEach[ light |
                    if(GLightsOverride.members.filter[o|o.name == light.name + "_Override"].head.state == OFF &&
                       light.state.toString != state.toString){
                            V_WhoCalled.sendCommand("WEATHER")
                            try {Thread::sleep(100)} catch(InterruptedException e){}
                            logInfo("Lights", "Weather turning " + light.name + " " + state.toString)
                            light.sendCommand(state.toString)
                            try {Thread::sleep(100)} catch(InterruptedException e){} // don't overwhelm "Any light in gLight triggered" rule
                       }
            ]
    }
end
1 Like

It’s been a while since I’ve done DSL based rules so my knowledge about the syntax is a bit rusty, but what if you change that line to:

var Number state = 0
if(owmCurrentCloudiness.state as Number > 0.80) {
  state = 60
} else if(owmCurrentCloudiness.state as Number > 0.30) { 
  state = 40
}

Note the use of var instead of val. By using val you’re creating a read-only variable that you can only assign a value once. By using var you can assign values as often as you’d like.

marcel_erkel,
Thanks for your help. I will try this out. One thing though, could I add additional “else if” if I want to have 3 or 4 levels of light level? For example would this work:

var Number state = 0
if(owmCurrentCloudiness.state as Number > 0.80) {
  state = 60
} else if(owmCurrentCloudiness.state as Number > 0.60) { 
  state = 50
}
 else if(owmCurrentCloudiness.state as Number > 0.40) { 
  state = 30
}

Yes, just make sure you keep the order from the highest cloud density to the lowest. So if for example you wanted to add a cloud density of 50% then you need to add it in between of 60% and 40%. If you’d like to add one for 30% cloud density then it needs to go after the 40%.

What if you made the light brightness be a function of the percent cloudiness?

For example, set the brightness to be a 80% of the cloudiness. So, for example, if the cloudiness is 80%, the brightness would be set to 64%. If the cloudiness is 40%, the brightness would be set to 32%.

Then you don’t special conditions for each level and you can handle it all in one forumla.

var Number state = ((ownCurrentCloudiness.state as Number) * .8).intValue

You can make the formula as simple or complex as necessary.

Hey Rich,
I might try that. Right now I’m getting error messages on the “state” variable in the lambda. " Cannot refer to the non-final variable state inside a lambda expression". Would that fix it?

With all the different versions of the code you will have to post what you are actually using right now. It isn’t clear what lambda you have that is using state. But you can first change the var to a val to see if that works. though that assumes you don’t reassign state elsewhere.

I tried to simplify the rule. It runs, but always gets 0 for light value. Here is the rule right now:

rule "Automated Weather Lights"
 when
     Item TimeOfDay changed to Day or
     Item owmCurrentCloudiness changed or
     Time cron "0 26 9 1/1 * ? *"
 then
     val Number state = ((owmCurrentCloudiness.state as Number) * 0.8).intValue
     
     if(TimeOfDay.state.toString == "Day") {
         V_WhoCalled.sendCommand("WEATHER")
         logInfo("Lights", "Adjusting Weather Lights")
         GWeatherLights.sendCommand(state)
         try {Thread::sleep(100)} catch(InterruptedException e){} // don't overwhelm "Any light in gLight triggered" rule
     }
end

But it no longer has the error, right?

What type of item is ownCurrentCloudiness? Is it a Number:Dimensionless?

Drop the .intValue and log out the result of the multiplication. It might be treating the % as 0.XX instead of XX which would definitely result in 0 being the result.

The Thread::sleep(100) isn’t actually doing anything for you. It delays the exiting of the Rule but it doesn’t delay the Rule from running again nor does it delay the commands sent to the members of the Group. It is essentially a noop.

There are no errors showing in Visual Studio on this rule now. Yes, the item type is Number:Dimensionless. Here is my log when the rule runs:

2019-01-29 10:21:02.329 [ome.event.ItemCommandEvent] - Item 'V_WhoCalled' received command WEATHER
2019-01-29 10:21:02.332 [ome.event.ItemCommandEvent] - Item 'GWeatherLights' received command 0
2019-01-29 10:21:02.332 [ome.event.ItemCommandEvent] - Item 'KitchenSinkLight' received command 0
2019-01-29 10:21:02.333 [ome.event.ItemCommandEvent] - Item 'LivingRoomLights' received command 0
2019-01-29 10:21:02.336 [vent.ItemStateChangedEvent] - V_WhoCalled changed from MANUAL to WEATHER
2019-01-29 10:21:02.342 [vent.ItemStateChangedEvent] - KitchenSinkLight changed from 0.72 to 0
2019-01-29 10:21:02.342 [vent.ItemStateChangedEvent] - LivingRoomLights changed from 0.72 to 0

Update:
I dropped the .intValue and after reading your statement about how it might be treating the % as 0.XX instead of XX, I changed the 0.8 to 80. It works now. Thanks Rich!!!