Getting Fancy with my Tower Timers - Separation of Behaviors

Alright, might bite off more than I can chew as they say but what the heck. Nothing risked nothing gained. Here is my use case…

We recently went through some very hot and low humidity days. I spent a good deal of time trying to dial in my tower timers (we grow in aeroponic towers that i use a rule to run a zwave controller for time on and off). I had to go in and change the setting in the rule manually which was a pain to dial in the right time on and off. Turned out 3 on and 10 off worked. Now we are going through rain/cooler/humid days and the time i had set is saturating the plants and causing issues. So let’s see if I can set this up so if certain weather conditions are met it will run different rules.

Researching it looks like the closest i can find is from @rlkoshak Design Pattern Separation of Behaviors.

I think I can work through that ok, but ideally i want to include more than just the cloudy part. ie i want to include the indoor temp and humidity as that plays as role in the timing settings as well. So i will have some if this and that stuff.

I am going to start with the just the cloudy part but will probably need some help determining how to add the other variables. If anyone thinks there is a better way, i am all ears…

I use the openweathermap binding so i am pulling in my items from there.

I created a switch following @rlkoshak example:

Switch      vlocalCurrentCloudiness       "Conditions are Cloudy [%s]" <clouds>	

Then this would be the code:

rule "Is it cloudy outside?"
when
	Item localCurrentCloudiness changed //this is from my openweathermap item
then
	logDebug(logName, "New weather conditions: " + localCurrentCloudiness.state.toString)
		    
	val isCloudy = transform("MAP", "weather.map", localCurrentCloudiness.state.toString) //i dont know where isCloudy comes from? Also, do i have to do the map stuff?
	val newState = if(isCloudy === null || isCloudy == "false") OFF else ON
		
	if(newState != vlocalCurrentCloudiness.state) logInfo(logName, "Setting isCloudy to " + newState.toString) 

	vlocalCurrentCloudiness.postUpdate(newState)
end

rule "Tower Timer Rule if Cloudy"
when
    Item Weather_Cloudy received command //I dont know where Weather_Cloudy comes from?
then
    if(vlocalCurrentCloudiness.state == ON) {
        // do stuff now that it is cloudy
		This would be the timer on and off when cloudy
    }
    else {
        // do stuff now that it isn't cloudy
		This would be the timer on and off when not
    }
end

Fun stuff! thanks!

Err, so what is this post supposed to be ?

If you’re looking for values such as humidity, temp, rain etc. - including forecasts -, you can also get them from the weather binding.

Just asking if i am on the right track and i am not sure how to set it up to check several types of values. I thought i would get it going with just the clouds and then see what it takes to add in the temp and humidity. I will be using the indoor temp and humidity values that i have in my items.

Adding more data is pretty simple. Add each Item you care about as a trigger to your “Tower timer Rule if Cloudy”, so that will be the temp and humidity. Then your if statements become a bit more complex as you have six or more possible combinations of states to deal with since the three values you care about are independent.

I highly recommend creating a table listing all the conditions and what should be done in those cases. For example, one row might be what to do it the temp is above 30 degrees C, humidity is above 50% and it’s cloudy and another would be temp is above 30 degree C, humidity is above 50%, and it is not cloudy.

Once you are happy with your table, you can translate that table to if statements.

if(vlocalCurremtTemp.state > 30 && vlocalCurrentHum.state > 50 && vlocalCurrentCloudiness.state == ON) {
    // do stuff
}
else if(vlocalCurremtTemp.state > 30 && vlocalCurrentHum.state > 50 && vlocalCurrentCloudiness.state == OFF) {
    // do stuff
}
...

There are other ways to structure this such as using nested if statements or switch statements but ultimately it’s going to be ugly. Apply Design Pattern: How to Structure a Rule as you build it an that will help with some of the complexity. But no matter how you go about it, it’s going to be ugly.

Thanks @rlkoshak! Yeah, i figured this would be interesting to say the least but very cool if i can pull it off. I think I will start with just the simple one condition rule and then go from there based on your suggestion. Baby steps.

Can you look at the code I pasted from your write up? I had a question on a few the items you have in there, ie, where they come from/what they do. I put comments in.

thanks!

isCloudy doesn’t come from anywhere. We are creating it as a variable on that line.

As for the map stuff, the original DP was written against Wunderground which didn’t provide a cloudiness as a percent value. So the Rule looks at the current conditions and uses the MAP transform to map the conditions to whether or not it is cloudy.

Because OpenWeatherMap provides cloudiness as a percent, the Rule I’m currently using is:

rule "Is it cloudy outside?"
when
  Item vCloudiness changed
then
  val newState = if(vCloudiness.state > 50) ON else OFF
  if(newState != vIsCloudy.state) vIsCloudy.sendCommand(newState)
end

This should be the Item that gets commanded by the cloudiness Rule. In my example above it’s vCloudiness.

I see now that the DP has an error when I last rewrote it I changed the names of the Items and apparently missed one. It’s also wrong in that it should sendCommand, or the Rule should be triggered on changed.

Let’s change it to work on changed. That will make the Rules:

rule "Is it cloudy outside?"
when
	Item localCurrentCloudiness changed //this is from my openweathermap item
then
  logDebug(logName, "New weather conditions: " + localCurrentCloudiness.state.toString)
		    
  val newState = if(vCloudiness.state > 50) ON else OFF
  if(newState != vIsCloudy.state) vIsCloudy.postUpdate(newState)
end

rule "Tower Timer Rule if Cloudy"
when
    Item vCloudiness changed
then
    if(vCloudiness.state == ON) {
        // do stuff now that it is cloudy
		This would be the timer on and off when cloudy
    }
    else {
        // do stuff now that it isn't cloudy
		This would be the timer on and off when not
    }
end

I’ll update the DP.

1 Like

Thanks so much @rlkoshak. I’ll work on this over the next couple of weeks and see what I can get working.

thanks!