Based on feedback on my posts here and here I have made a template sensor that can automatically control your blinds or sunscreen based on where the sun is in the sky.
Thanks to @basbrus you can now import the blueprint without having to setup anything yourself by clicking this button:
The control method uses the solar elevation and azimuth angles calculated by the HA sun platform as inputs to calculate the optimal shade height h.
Please note currently only vertical sunscreens will work with this method. I am looking at making it also work with sunscreens at any tilt angle, but it will require some modifications to the formula.
Method
The method is based on the shading control strategy III (SC-III) explained in [1] developed by Prof. Athanasios Tzempelikos. The general idea is to avoid sun glare, which is when the sun directly hits your eyes which causes discomfort, while still maximizing the amount of natural light.

[1] Comparative control strategies for roller shades with respect to daylighting and energy performance
The formula is pretty simple:
h = (d / cos(γ)) * tan(α)
Where:
- h: the height of the open part of the window in meters
- d: distance between the window and the working area (the area you want shaded) in meters
-
γ: the surface solar azimuth in degrees. This is the difference in degrees between the direction of the window and where the sun is in the sky. (or: γ =
window_azimuth
-sun_azimuth
). We getsun_azimuth
from HA sun platform. - α: the solar elevation angle in degrees. We get this from HA sun platform.
For illustration of sun azimuth and elevation:
Finding the window azimuth (what direction your window points)
You can follow the steps by forecast.solar, it works quite well. I will also put the steps here for your convenience:
- Go to Open Street Map Compass
- Click Draw single leg route
- Find your location and zoom in as far as possible
- Click Show compass
- Move and rotate the compass in place, north is always at the top of the map
- Get your azimuth (upper right corner), for me abt.
172°
Template code
Template code can be found below:
- platform: template
sensors:
blinds_height_perc:
friendly_name: Solar blinds height percentage
unit_of_measurement: '%'
value_template: >
{% set deg2rad = pi/180 %}
{%- macro norm(x, min, max) %}
{{ (x - min) / (max - min) }}
{%- endmacro %}
{%- macro h2perc(x) %}
{{ 100 * float(norm(x, h_min, h_max)) }}
{%- endmacro %}
{%- macro clipv(x, x_min, x_max) %}
{{ max(min(x, x_max), x_min) }}
{%- endmacro %}
{% set win_azi = 136 %}
{% set d = 0.5 %}
{% set h_max = 1.96 %}
{% set h_min = 0 %}
{% set fov = deg2rad * 90 %}
{% set sun_azi = state_attr('sun.sun', 'azimuth') %}
{% set sun_ele = state_attr('sun.sun', 'elevation') %}
{% set def_h = 0.6 * h_max %}
{% set alpha = deg2rad * sun_ele %}
{% set gamma = deg2rad * (win_azi - sun_azi) %}
{% set h = (d / cos(gamma)) * tan(alpha) %}
{% if (alpha > 0) and (gamma | abs < fov) %}
{{ clipv(h2perc(h) | round(0) | int , 0, 100) }}
{% else %}
{{ clipv(h2perc(def_h) | round(0) | int , 0, 100) }}
{% endif %}
First, we define two macros. One is used to normalize a number in range [0,1] and the second converts the blind height h to the cover position [0,100].
We then define some constants:
-
win_azi
: can be found by the method explained in the above section. -
d
: is the distance from the window you want the beginning of the shadow to fall. I set it to 0.5 meters but you should probably play around a bit with this since it depends on your situation. -
h_max
: is the height of your window in meters (or actually the maximum height of your blinds, but for most people this will be the same number ofcourse) -
h_min
: is the minimum height in meters when the blinds are fully open. This will be 0 in most cases. -
fov
: field of view you want to enable control. This is relative to the window. A fov of 90 degrees means control is enabled anytime the sun is in front of the window (90 degrees to the right, 90 degrees to the left = 180 degrees total or half a circle). You can decrease this number if you have for example a lot of trees/houses to your left and right.
Then finally we calculate the optimal height h
, normalize it, and calculate the percentage the blind should open/close.
Control automation
The automation is quite simple. It’s actually the same one as in the HA Solar Tracker post.
alias: control_blind
description: ""
trigger:
- platform: state
entity_id:
- sensor.blinds_height_perc
condition: []
action:
- service: cover.set_cover_position
target:
entity_id: cover.sun_screen_control
data:
position: "{{ states('sensor.blinds_height_perc') | int(0) }}"
mode: single
There are definitely some improvements possible here. For example, on a very dark day with little daylight we might want to open the blinds completely to maximize the amount of natural light. This can easily be added in the automation but I currently have no way of testing it myself.
Based on the paper [1] it seems that a minimum value of 500 lux should always be followed since otherwise it becomes too dark. So perhaps someone with automatic blinds and a light sensor can add this?
PVLib simulation
I made a small PVLib simulation to see what the controller would do during a short winter and a long summer day: