Last active
September 13, 2024 14:40
-
-
Save cayblood/98fdb085dc83377f41f24cdebab0ae6c to your computer and use it in GitHub Desktop.
Calculates when to lower exterior solar blinds
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'] | |
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 = { | |
485: [402], # office east | |
486: [403], # office south | |
487: [404], # laundry | |
488: [405,406], # sam south | |
491: [407], # annie south | |
492: [408], # annie west | |
494: [410], # primary west | |
493: [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"] | |
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) | |
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(-111.63855869671522, 40.25241886212485, 0) | |
utcoffset = -6 * u.hour # Mountain 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 > 8.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 | |
if w.temperature('fahrenheit')['temp'] > 35: | |
if w.wind(unit='beaufort')['speed'] < 6: | |
if w.clouds < 101: | |
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', '272d')): # back (skip degrees 270-271 because they are so oblique) | |
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