I have more or less switched to using Home Assistant to automate things at the cabin. One of the things I’ve had to do is integrate the Etherrain/8 from QuickSmart into HomeAssistant by creating a new component and switch module. This is currently (as of this writing) on a branch waiting for release integration.
Now the next thing was to automate the irrigation. HomeAssistant’s automation scripts take a bit of getting used to.. It’s certainly not very intuitive but it is what it is.
First the automation, to water the front beds at 7 AM on Mon/Wed/Fri if the chance of rain is <60%:
- id: water_front_beds_on
alias: Start Watering Front Beds mon/wed/fri at 7AM
initial_state: on
trigger:
platform: time
hours: 7
minutes: 0
seconds: 0
condition:
condition: and
conditions:
- condition: state
entity_id: binary_sensor.rain_unlikely
state: 'on'
- condition: time
weekday:
- mon
- wed
- fri
action:
service: switch.turn_on
entity_id: switch.front_beds
So the next question is likely “where does rain_unlikely come from”? It’s here:
binary_sensor:
- platform: threshold
name: rain_unlikely
threshold: 59
type: lower
entity_id: sensor.environment_canada_pop
- platform: mqtt
state_topic: environment_canada/pop
name: environment_canada_pop
Essentially, an MQTT message with a percentage that is the “probability of precipitation”. But who generates this MQTT message? In fact, nobody really. This is just a placeholder sensor that holds the POP. But something must populate this. Well, here’s an Appdaemon script written in Python:
import appdaemon.appapi as appapi
import feedparser
import sys
import time
import datetime
class EnvCanada(appapi.AppDaemon):
def initialize(self):
if "locator" in self.args:
loc = self.args["locator"]
else:
loc = "ab-52" # Default to Calgary
if "hr" in self.args:
hr = int(self.args["hr"])
else:
hr = 4
if "ahead" in self.args:
add=int(self.args["ahead"])
else:
add = 0
myargs={}
myargs["loc"] = loc
myargs["add"] = add
myargs["module"] = self.args["module"]
# First run immediately
h = self.run_in(self.get_pop, 1, **myargs)
# Then schedule a runtime for the specified hour.
runtime = datetime.time(hr, 0, 0)
h = self.run_once(self.get_pop, runtime, **myargs)
def get_pop(self, args):
loc = args["loc"]
add = args["add"]
d=feedparser.parse('http://weather.gc.ca/rss/city/{0}_e.xml'.format(loc))
weekdays=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
today = (weekdays[time.localtime().tm_wday+add])
pop = 0
for entry in iter(d.entries):
if today in entry.title:
if "howers" in entry.title:
pop = 100
if "POP" in entry.title:
next=0
for word in iter(entry.title.split(" ")):
if next:
pop = int(word.rstrip("%"))
if word == "POP":
next=1
print("{0}: Got POP {1}".format(args["module"], pop))
self.set_state("sensor.environment_canada_pop", state = pop)
def terminate(self):
self.log("Terminating!", "INFO")
This essentially grabs the Atom feed from Environment Canada, looks for the word “Showers” or “showers” or “POP” and generates that percentage. It then reaches under the skirt of Home Assistant and populates the above mentioned ‘MQTT sensor’.. I really wish I could think of a better way to do that.
Just for the sake of completion; here is the AppDaemon configuration to get it all started:
EnvCanada:
module: environment_canada
class: EnvCanada
hr: 5
ahead: 0
locator: ab-53
The ‘ahead’ attribute is “how many days ahead to determine the POP. Ie: at 0, it returns todays probability of precipitation. At 1, it will return tomorrow’s. the ‘hr’ attribute is when AppDaemon should run this script. In this case, at 05:00AM. The ‘locator’ is the portion of the URL that specifies which Environment Canada weather location to use. ‘ab-53’ is Sundre Alberta.
Hope that helps someone.