Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@cayblood
Last active June 5, 2022 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cayblood/1607c70e73cbe745d0e8a541dfca2b7f to your computer and use it in GitHub Desktop.
Save cayblood/1607c70e73cbe745d0e8a541dfca2b7f to your computer and use it in GitHub Desktop.
Automates operation of our solar blinds using hubitat and MakerAPI
#!/home/pi/home-automation/venv/bin/python
import os
import time as mytime
from pprint import pprint
from pyowm import OWM
from pyhubitat import MakerAPI
import astropy.units as u
from astropy.time import Time
from datetime import datetime
from astropy.coordinates import EarthLocation, AltAz
from astropy.coordinates import get_sun
OWM_KEY = os.environ['OWM_KEY']
HUB_TOKEN = os.environ['HUBITAT_TOKEN']
HUB_IP = os.environ['HUBITAT_IP']
HUB_APP_ID = os.environ['HUBITAT_APP_ID']
LATITUDE = float(os.environ['LATITUDE'])
LONGITUDE = float(os.environ['LONGITUDE'])
HUB_URL = f'https://{HUB_IP}/apps/api/{HUB_APP_ID}'
def filter_open_windows(blinds_to_lower):
filtered_blinds_to_lower = []
blind_to_sensor_mapping = {
371: [402], # office east
372: [403], # office south
373: [404], # laundry
376: [405, 406], # sam south
377: [407], # annie south
378: [408], # annie west
379: [410], # primary west
380: [409] # primary north
}
ph = MakerAPI(HUB_TOKEN, HUB_URL)
for blind in blinds_to_lower:
found_open_window = False
if blind in blind_to_sensor_mapping:
for sensor in blind_to_sensor_mapping[blind]:
device_details = ph.get_device_info(sensor)
mytime.sleep(2) # throttle API calls
current_state = next((elm['currentValue'] for elm in device_details['attributes'] if elm['name'] == 'contact'), None)
if current_state == 'open':
found_open_window = True
if not found_open_window:
filtered_blinds_to_lower.append(blind)
return filtered_blinds_to_lower
def set_blinds(blinds_to_lower):
ph = MakerAPI(HUB_TOKEN, HUB_URL)
devices = ph.list_devices()
blinds = [d for d in devices if d['name'] == "Somfy MyLink Shade"]
pprint(blinds)
directions = blinds_to_lower.split()
blind_ids_to_lower = []
for elm in [b for b in blinds for direction in directions if direction in b['label']]:
blind_ids_to_lower.append(int(elm['id']))
blind_ids = [int(elm['id']) for elm in blinds]
blind_ids_to_raise = list(set(blind_ids) - set(blind_ids_to_lower))
blind_ids_to_lower = filter_open_windows(blind_ids_to_lower)
pprint(blind_ids_to_raise)
pprint(blind_ids_to_lower)
for id in blind_ids_to_lower:
ph.send_command(id, 'close')
mytime.sleep(2) # throttle API calls
for id in blind_ids_to_raise:
ph.send_command(id, 'open')
mytime.sleep(2) # throttle API calls
# get sun angles etc at our location
briar_house = EarthLocation.from_geodetic(LONGITUDE, LATITUDE, 0)
utcoffset = -4 * u.hour # Eastern Daylight Time
time = Time(datetime.utcnow(), scale='utc', location=briar_house)
aaframe = AltAz(obstime=time, location=briar_house)
sun = get_sun(time)
sunaa = sun.transform_to(aaframe)
blinds_to_lower = ''
# if sun is up
if sunaa.alt > 5.0 * u.deg:
# determine sun's angle with house
house_angle = 145 * u.deg
front_angle = sunaa.az - house_angle
if front_angle < 0: front_angle = front_angle + 360 * u.deg
# get weather
owm = OWM(OWM_KEY)
mgr = owm.weather_manager()
observation = mgr.weather_at_place('Provo,UT,USA')
w = observation.weather
print(f"temperature = {w.temperature('fahrenheit')}")
print(f"wind = {w.wind(unit='beaufort')}")
print(f"clouds = {w.clouds}")
if w.temperature('fahrenheit')['temp'] > 50:
if w.wind(unit='beaufort')['speed'] <= 6:
if w.clouds < 80 or w.temperature('fahrenheit')['temp'] > 60:
blinds_to_lower = ''
if (front_angle.is_within_bounds('270d', '360d') or front_angle.is_within_bounds('0d', '90d')): # front
blinds_to_lower = 'South'
if (front_angle.is_within_bounds('0d', '180d')): # right
if len(blinds_to_lower) > 0: blinds_to_lower += ' '
blinds_to_lower += 'West'
if (front_angle.is_within_bounds('90d', '270d')): # back
if len(blinds_to_lower) > 0: blinds_to_lower += ' '
blinds_to_lower += 'North'
if (front_angle.is_within_bounds('180d', '360d')): # left
if len(blinds_to_lower) > 0: blinds_to_lower += ' '
blinds_to_lower += 'East'
set_blinds(blinds_to_lower)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment