Cloudiness from OpenWeatherMap binding

Hello All,

New to OpenHAB and convert from Home Control Assistant. I’m trying create a rule for cloudy days using the Cloudiness channel in the OpenWeatherMap binding. I have an item created for the cloudiness channel.

I want this rule in effect only during the day so I used a cron function from 9am to 8pm. When the cloudiness reaches a value, say 80%, I want to send command to my Gosund Plug.

I’m using Visual Studio Code as the editor and I’m far from a software coder.

Here’s my rule from VSC:

rule “Test Cloudy Day”
when
Time cron “* * 9-20 ? * * *”
then
if (LocalWeatherAndForecast_Current_Cloudiness.state < 90) {
GosundPlug05_Switch.sendCommand(OFF)
}
end

I’ve been trying to learn via the OpenHAB documentation and the community forums but I’m getting nowhere fast.

Thanks in advance

Hi Brian,

How have you defined your items LocalWeatherAndForecast_Current_Cloudiness and GosundPlug05_Switch?

If LocalWeatherAndForecast_Current_Cloudiness is Number:Dimensionless, as per PaperUI or defined in text files via the OpenWeatherMap binding docs, you should use

if (LocalWeatherAndForecast_Current_Cloudiness.state | "%" < 90) {
…

for the comparison.

A better approach is to trigger the rule when the cloudiness Item changes. Then in the rule check the time.

I have almost exactly this rule in my config but I’m using Jython rules.

from core.rules import rule
from core.triggers import when

@rule("Is Cloudy", description="Generates an event when it's cloudy or not",
      tags=["weather"])
@when("Item vCloudiness changed")
def is_cloudy(event):
    """Sets a switch to ON when cloudiness gets above 50%."""

    newState = "ON" if items["vCloudiness"] > QuantityType(u"50.0 %") else "OFF"
    sendCommandCheckFirst("vIsCloudy", newState)

@rule("Cloudy Lights",
      description="Turns ON or OFF some lights when it is cloudy during the day",
      tags=["lights"])
@when("Item vIsCloudy changed")
@when("Item TimeOfDay changed")
def cloudy_lights(event):
    """When it's day time, cloudy, and someone is home, turn on the weather
    lights.
    """

    # If it's not DAY or cloudy isn't set, exit.
    if (items["TimeOfDay"] != StringType("DAY") or
        isinstance(items["vIsCloudy"], UnDefType)):
        return

    # If no one is home, turn OFF any lights that are on.
    if items["gPresent"] == OFF:
        [event.sendCommand(light, "OFF") for light in ir.getItem("gLights_ON_WEATHER").members if light.state == ON]
        return

    # Someone is home and it's DAY time, turn ON/OFF the lights based on the cloudiness.
    if event.itemName == "TimeOfDay":
        sleep(0.5)

    cloudy_lights.log.info("It is {} and cloudy changed: {}"
                           .format(items["TimeOfDay"], items["vIsCloudy"]))

    for light in [light for light in ir.getItem("gLights_ON_WEATHER").members if get_key_value(light.name, "Flags", "override") != ON]:
        if items[light.name] != items["vIsCloudy"]:
            events.sendCommand(light, items["vIsCloudy"])

TimeOfDay is defined and populated based on [Deprecated] Design Pattern: Time Of Day. There is a reusable library you can download and use at https://github.com/rkoshak/openhab-rules-tools/tree/main/ephem_tod. No coding required.

Notice how I separated the calculation of whether or not it’s cloudy from the rule that acts on it. That lets me have other rule react when it’s cloudy too and I can see whether or not it’s cloud with a simple switch on the sitemap. Also notice how I check whether or not it’s the right time of day to adjust the lights when it becomes cloud.

finally, that last for loop gets at some Item metadata to tell whether or not the light is overridden or not. You can’t do Item metadata from Rules DSL so you could track that information in a Map in the Rule instead. See Design Pattern: Manual Trigger Detection for more on how lights get overridden (i.e. if manually turned on or off they are no longer controlled by the cloudiness until the next day).

Almost. I’m pretty sure it’s:

if(LocalWeatherAndForecast_Current_Cloudiness.state < 90 | %%)

I’m not positive about the double %% though. You need to convert the 90 to a quantity type. The state already is a quantity type.

Thanks @rlkoshak - that order is what I actually meant to write :wink: late here

if (LocalWeatherAndForecast_Current_Cloudiness.state < 90 | "%" ) {
…

Not too sure about the single or double % either, as I only have other units active here for quantity type conversions, but think with the quotes the sigle % should be fine.

This worked!

Thanks to both of you.

Rich: I’ve read several of your posts. It will be a while before I’m at your level. A long while… Thanks!

Glad this got it working for you, but as Rich also suggested, it might be better to change the rule trigger to when LocalWeatherAndForecast_Current_Cloudiness only actually changed, instead of polling it every minute with a cron job, especially since you probably don’t have the refreshInterval set for every minute in your OpenWeatherMap Thing, and even if you do, it might stay the same value for a longer period.

And then put the time of day condition into the if evaluation as well.

So

rule “Test Cloudy Day”
when
   Item LocalWeatherAndForecast_Current_Cloudiness changed
then
   if (LocalWeatherAndForecast_Current_Cloudiness.state < 90 | "%" && now.getHourOfDay >= 9 && now.getHourOfDay <= 20 )

What about setting the cron function to every 15 minutes? I don’t need single minute resolution for this rule.

Was still editing while you replied. Did you see the time evaluation in the if condition?

Now the GosundPlug05_Switch only gets triggered when LocalWeatherAndForecast_Current_Cloudiness actually changed, when it’s smaller than 90 and if the time is between 9 and 20 hours. The change update interval being ruled by your refreshInterval set for the OpenWeatherMap Thing.

This also means that the rule gets triggered as soon as LocalWeatherAndForecast_Current_Cloudiness changes. With a 15 minute cron job you might have the cron job triggering 1 minute before the OpenWeatherMap refresh, and will have to wait another 14 minutes for the LocalWeatherAndForecast_Current_Cloudiness change to be picked up by the next cron trigger :wink:

I was making the assumption the rule looking at the cron function as the first gate “when”, i.e. at every 15 minutes, between 9am and 8pm. At those points in time, OpenHAB would “lookup” the cloudiness state and then perform the action based on the “if-then” statement. I think I understand your reasoning on the triggers and timing but I need baby steps before I’m walking and running.

I have much more MS Excel experience than VS code. Sounds like I have much to learn.

Here’s what I have coded now:

rule “Rock Lamps Cloudy Day”
when
Time cron “* 0/15 8-20 ? * * *”
then
if (LocalWeatherAndForecast_Current_Cloudiness.state > 75 | “%” ) {
GosundPlug03_Switch.sendCommand(ON)
GosundPlug04_Switch.sendCommand(ON)
else (LocalWeatherAndForecast_Current_Cloudiness.state < 75 | “%” ) {
GosundPlug03_Switch.sendCommand(OFF)
GosundPlug04_Switch.sendCommand(OFF)
}
end

I rolled the logic into my “live” environment, so the item commands have changed.

The “lookup” only happens in the time interval that you have specified as the Refresh Interval in your OpenWeatherMap Account Thing. So even if you had a cron job every minute, but the refresh interval is 30 minutes, any OpenWeatherMap items will only be updated from the OpenWeatherMap server every 30 minutes. Same with a 15 minute, or any other interval cron job. As mentioned before, the intervals could also be very much out of sync. That is why I suggested having the rule triggered by the actual change of LocalWeatherAndForecast_Current_Cloudiness whenever it gets “looked up”
and has changed to its previous state.

should be

} else if (LocalWeatherAndForecast_Current_Cloudiness.state < 75 | “%” ) {

Also, what happens when LocalWeatherAndForecast_Current_Cloudiness.state is exactly 75?

Nothing in your above case, as you only provisioned for <75 and >75, but NOT == 75, so either one of them should be <=75 OR >=75 :slight_smile:

Which also made me just realise the hickup I made with my example before, where I stated

now.getHourOfDay >= 9 && now.getHourOfDay <= 20

which would be true until 20:59, so … && now.getHourOfDay <= 19 would get you a lot closer to your desired 20:00 hours with it triggering until 19:59 :wink:

So with your new conditions I would suggest

rule “Test Cloudy Day”
when
   Item LocalWeatherAndForecast_Current_Cloudiness changed
then
   if (now.getHourOfDay >= 8 && now.getHourOfDay <= 19 ) {
	   if (LocalWeatherAndForecast_Current_Cloudiness.state >= 75 | “%” ) {
			GosundPlug03_Switch.sendCommand(ON)
			GosundPlug04_Switch.sendCommand(ON)
		} else if (LocalWeatherAndForecast_Current_Cloudiness.state < 75 | “%” ) {
			GosundPlug03_Switch.sendCommand(OFF)
			GosundPlug04_Switch.sendCommand(OFF)
		}
   }
end

Have a look and see what your OpenWeatherMap Account Thing Refresh Interval is, you can also monitor your log to see whenever LocalWeatherAndForecast_Current_Cloudiness changes.

What happens if at 7:55 am, the cloudiness state is above 75% and never changes all day?

I’m guessing this logic would never trigger.

Now you are starting to think a little more like how openHAB works. It’s event driven.

There are two ways you can deal with this without running a rule once a minute to do basically nothing most of the time.

  1. trigger the rule at the start time you care about and on changes to cloudiness, you’d use a cron trigger along the lines of “0 0 8 * * * *”.

  2. trigger the rule on updates to the cloudiness Item, not just changes. Every time the OpenWeatherMap binding pulls down the conditions the Item will be updated.

Another condition to consider, what should happen at 20:00?

When setting up a rule for polling you are trying to emulate a state driven system. openHAB doesn’t have that. It has an event driven system. So you as the rules developer should approach rules from that perspective. Under what events should certain things happen?

This rule potentially cares about the following events:

  • time becomes 08:00
  • time becomes 20:00
  • cloudiness changed

So trigger the rule for all three states and in the rule is where you check for state.

Yes, in case LocalWeatherAndForecast_Current_Cloudiness never changes at all this would not trigger between 8 and 19:59. For the start and end times cron jobs can be incorporated into the rule.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.