Last active
June 5, 2022 04:11
-
-
Save cayblood/1607c70e73cbe745d0e8a541dfca2b7f to your computer and use it in GitHub Desktop.
Automates operation of our solar blinds using hubitat and MakerAPI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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