Anyone with Solar Panels might be interested in this…
I’ve created, helped by AI, a few Template sensors that calculate the full sun ideal output throughout the day that I can overlay on actual output. It’s not perfect but close - and I’d be happy others to suggest improvements to the templates. Anyway this is what I’ve done…
This only works for a set of panels all orientated the same way. The first sensor calculates the reduced output factor due to the angle of incidence (AOI). You can create multiples of this sensor for each set of panels.
sensor.house_solar_aoi_factor
Unit of Measurement - %
The Template
{% set deg2rad = pi/180 %}
{% set sun_azi = state_attr('sun.sun', 'azimuth') | int %}
{% set sun_ele = state_attr('sun.sun', 'elevation') | int %}
{% set sun_x = sin(sun_azi*deg2rad)*cos(sun_ele*deg2rad) %}
{% set sun_y = cos(sun_azi*deg2rad)*cos(sun_ele*deg2rad) %}
{% set sun_z = sin(sun_ele*deg2rad) %}
{% set win_azi = 210 %}
{% set win_ele = 35 %}
{% set win_x = sin(win_azi*deg2rad)*sin(win_ele*deg2rad) %}
{% set win_y = cos(win_azi*deg2rad)*sin(win_ele*deg2rad) %}
{% set win_z = cos(win_ele*deg2rad) %}
{% set dot = sun_x*win_x + sun_y*win_y + sun_z*win_z %}
{% set aoi_perf = dot*100 if dot > 0 else 0 %}
{{ aoi_perf if is_state('sun.sun', 'above_horizon') else 0 }}
Adjust your azimuth (my 210) and elevation (my 35) angles accordingly.
The next sensor calculates the effect of atmosphaeric attenuation based on the sun’s elevation.
sensor.atmospheric_attenuation
The Template
{% set deg2rad = pi/180 %}
{% set el = state_attr('sun.sun', 'elevation') | int %}
{% if el > 0 %}
{% set f=0.7**(((1/sin(deg2rad*el))**0.678)-1) %}
{{ f }}
{% else %}
{{ 0 }}
{% endif %}
This third sensor calculates the power factored from diffuse or scattered sunlight.
sensor.diffuse_solar_factor
The Template
{% set sun_elevation = state_attr('sun.sun', 'elevation') %}
{% set is_day = sun_elevation > 0 %}
{% set diffuse_factor = (0.15 * (sun_elevation / 90)) if is_day else 0 %}
{{ (diffuse_factor|round(2))}}
Finally, these are pulled together into the sensor that shows what would be generated under full sun conditions for 1 set of panels…
sensor.full_sun_potential
Unit of Measurement - W
Device Class - Power
State Class - Measurement
The Template
{{((states('sensor.house_solar_aoi_factor')|float(0)*
states('sensor.atmospheric_attenuation')|float(0) * 6750/100) +
(states('sensor.diffuse_solar_factor')|float(0) * 6750))|round(0)}}
Amend the 6750s here to whatever your rated peak output is in W.
Enjoy
