Yet Another Solar Calculator

Just wanted to pass along my take on a solar calculator… I use this mostly to manage blinds as the sun moves throughout the seasons. This solution is comprised of 3 parts: helpers, a script and automation events. This is mostly to keep discrete building blocks that are easy to use if I change methods in the future.

The Helpers are numbers (0-360) hold input values for each surface:

The python_script calculates the angle of incidence on a surface and updates a helper:

# lifted from pysolar - https://github.com/pingswept/pysolar/blob/4bb54dfe6e9ab79ea1a6a24bffb3e46cbeadc918/pysolar/solar.py
def get_incident_angle(obj_azm, obj_alt=90.0):
    tza_rad = math.radians(90.0 - solar_alt)
    slope_rad = math.radians(obj_alt)
    so_rad = math.radians((180 + obj_azm) % 360)
    taa_rad = math.radians(solar_azm)

    return math.degrees(
        math.acos(
            math.cos(tza_rad)
            * math.cos(slope_rad)
            + math.sin(slope_rad)
            * math.sin(tza_rad)
            * math.cos(taa_rad - math.pi - so_rad)
        )
    )

# expected input parameters
solar_azm = data.get('azimuth', None)
solar_alt = data.get('elevation', None)
obj_angle = data.get('angle', None)
entity_id = data.get('entity_id', None)

solar_aoi = get_incident_angle(obj_angle)

# update the helper value
logger.info('Update AOI %s => %d°', entity_id, solar_aoi)
hass.services.call('input_number', 'set_value', {
    "value": solar_aoi,
    "entity_id": entity_id,
}, False)

An automation, which calls the script every minute. This requires parameters with the sun’s azimuth & elevation as well as the angle of the object to compare and an input_number helper for the result. Of course, the sun’s values could be derived another way, such as a fixed time during the day.

alias: Sun - Calculate AOI
description: ''
trigger:
  - platform: time_pattern
    hours: '*'
    minutes: '*'
    seconds: '0'
condition: []
action:
  - service: python_script.solar_aoi
    data_template:
      elevation: |
        {{ states.sun.sun.attributes.elevation }}
      azimuth: |
        {{ states.sun.sun.attributes.azimuth }}
      angle: 240
      entity_id: input_number.solar_aoi_west_wall
mode: single

And of course the automations, which trigger on changes in the helpers:

alias: Sun - Afternoon - West Wall
description: ''
trigger:
  - platform: numeric_state
    entity_id: input_number.solar_aoi_west_wall
    below: '60'
condition: []
action:
  - device_id: b363fe5b059011eb9bd889653556d50b
    domain: cover
    entity_id: cover.office_blinds
    type: set_position
    position: 50
mode: single

To help find the best incident angle for taking action, I use the history for each helper to find out what the angle was at the time I wanted the blinds to close.

2 Likes