Incident Angle of Sunlight

Hello. I think your graphs make sense, the azimuth of your windows differ by exactly 180 degrees. Indeed this sensor does not check whether the sun is up or down, if you want that you can easily add it. The sensor just gives a value, what you want to use it for is up to you.

1 Like

Thanks.
I replaced the last line of your code and I’m going to try to see the results.
{{ ((ang_sim * 100) | round(0)) if (sun_ele > 0) else 0 }}
it really doesn’t matter the value, each implementation must analyse the threshold that is needed for each window, and probably cross this with weather conditions ou sun intensity (I use my solar power production sensor to estimate outside luminosity) so I can do something like:
{{ ((ang_sim * 100 * states('sensor.calculated_outdoor_illuminance')|int(default=0)/10000) | round(0)) if (sun_ele > 0) else 0 }}
This sure helps! Thanks again!

Thanks a lot for sharing, Stefan!
I used to have FHEM running for my home automation and I had made myself a quite similar script in perl. Now I was trying to migrate it to Home Assistant but all this Jinja code and YAML indententation rules drove me crazy… :woozy_face:

Your script made my day as it did the job right out of the box, nice work!
Let me just ask one question for clarification. Our house has these ‘Velux’-type skylights installed in a roof with an angle of 45 degrees - so in my case the definition would be {% set win_ele = 45 %}, correct? (At least that would be my guess if I got the vector math right…)

Hi, good to hear. Yes 45 degrees elevation would be correct :slight_smile:

Thanks for your reply. I have tested the sensor script for a few days now and I noticed that it returns a certain amount of angular similarity even when the sun is on the opposite side of the house. (see log graph below)
grafik

Even though this looks perfectly correct form a mathematical perspective (as far as I can tell), it was not quite what I needed for controlling the covers. So I tried some modifications and ended up using your cos_sim value combined with some extra conditions. As the dot product returns negative values if the vectors are pointing in opposite directions (sun illuminating the other side of the house), I had to ‘cut the curves’ for these undesired values and for negative sun elevations. To achieve this, I replaced the two last lines of your code by this:

{{ ((cos_sim * 100) | round(0)) if (sun_ele > 0 and cos_sim > 0 ) else 0 }}

This is what the resulting graph looks like:
grafik

I think the curves now represent the percentage of sun exposure of the several facades quite nicely. For example, you can see how the exposure of the front side (blue line) decreases steadily from sunrise until around 11:30 when the sun fully lights the left face (purple line). From that moment on, the front side is facing the sun no more and exposure of the aft face (cyan line) begins to rise.
The lines representing the roof areas (yellow/brownish and blueish/violet) seem to work as well. They also intersect at 11:30, but due to the 45 degree roof tilt, the sun begins to light the aft roof already at 10 o’clock and continues to light the forward roof until around 13:45. This agrees well with the observations I made when tracking the actual sun exposure.

I am looking forward to getting an outdoor brightness sensor (as proposed in this previous post), I will then further refine the logic by taking sensor values into account as well. Thanks to y’all for your ideas and inspiration!

1 Like

Hi, thanks for sharing. Indeed I did not take into account from which side of the window the sun is hitting. Glad to see you found a way that works. Are you already using it to control your covers? Mind sharing that too?

Ps. this post nicely explains why I chose to calculate the angular similarity rather than the cosine similarity (which you are using now, I guess it also works fine): vector spaces - Cosine similarity vs angular distance - Mathematics Stack Exchange

came here because of your recent post in Dutch Domotics Discord…
this is some impressive templating you are doing here, or, even more, some impressive math.

Do I understand this correctly, in that I can use this on any window, by only adjusting the orientation of that window (mine are all perpendicular :wink: so don’t need any other consideration) ?

Seems quite a complex system compared to a simple and (always spot on) light sensor in all honestly, but I do like the mathematical approach, just like we have that for virtual daylight

That is a nice reference, I learned a lot of new stuff about angular functions now…
It’s been quite a while since my uni math courses, but I think I mostly understood the point that is made. I mainly ended up with the cosine similarity because it felt a bit more intuitive for me. (I like how a value of 1 translates to full exposure and values of zero or below indicate no exposure.) I can not tell for sure if the discussed loss of precision at low angles and the more differentiated weighing is relevant in terms of solar radiation. Most probably you would also have to take into account how much of it is absorbed/reflected across different angles to make things more precise.

But now I’m getting close to nit-picking and such detailed considerations are (most likely) beyond the scope of most of us here I guess. I don’t want to turn this into a maths/physics thread, let’s keep these discussions in the respective forums… At the end of the day, we’re just trying to automate these bloody covers, right? :wink:

I have way too many other things going on at the moment, so unfortunately I cannot spend as much time on home automation as I’d like to… Nevertheless I spend more time on it than my wife would like me to… :rofl:

So there is nothing to share so far, but I will keep an eye on this thread and come back if I’ve had time to make up some automation ideas. Might take a while though… :man_shrugging:

Basically yes. As the calculations just rely on window orientation (in terms of azimuth and elevation/tilt) and sun position, there’s nothing more you have to care about in the first place. Just give it a try and then make your own observations if the calculations match the real situation.

Of course there’s potential for further refinement from that starting point, e.g. taking into account the shadowing effects of trees or other buildings around your house. But that would be a topic for a new thread then, I guess… :grin:

It’s very complicated, but it could be done using for example the open source database of Open Topography. I’ve seen it used in some PV installation tools to calculate the forecasted production for example.

Hi Stefan,

thanks a lot for posting this - I’ve been trying to reuse your template for my particular setup but I might need a bit of help to make it actually work correctly - let me try to explain:

I have a “bioclimatic pergola” with movable roof slats:

I’m trying to set up an automation that will keep them perfectly aligned with the angle of the sun (same as in the photo) to minimize the amount of shade they are casting. In the photo I’m facing almost directly north (27 NW), with the east to my right. In the morning when the sun if effectively shining perpendicular to the slats all I need is to set their angle to the same elevation as the sun and I’m good however at noon when the sun is directly behind me (at azimuth 207) I need them to be vertical to minimize the shade while I no longer care about the sun’s elevation.

I’ve been trying to come up with a formula combining the azimuth and elevation of the sun to come up with the slat angle but no luck so far although I’m pretty sure it’s pretty basic trigonometry. If I use your sensor set to azimuth 207 and 0 elevation, I never get incidence of 1 however I assume that’s due to your setup working in 3 dimensions to the plane of the window…

Is there a simple way to (re)use what you come up with for this application? I feel like it should actually be a simpler version of the formula, not a more complicated one…

Thanks!

Hello @Plawa,

Interesting you should ask this. I am currently working on a very similar problem that involves tilting a solar panel towards the sun to optimize production. In general, to minimize the angle of incidence (AOI) with the sun you require knowledge of both solar azimuth and elevation. Luckily for us, HA has this information in the sun.sun integration.

This paper explains the technical details really well: Rotation Angle for the Optimum Tracking of One-Axis Trackers

I will post the details of my project, including all the maths and templates pretty soon, hopefully today. You can then look, or I can help you, to adapt it to your project.

1 Like

Hi Stefan, thanks for the link to the paper, that was exactly the bit I needed, specifically this formula:

R = tan-1 [ tan θz sin (γs - γa ) ]

Where
θz - Zenith (i.e. 90 - elevation)
γs - azimuth of the sun
γa - azimuth of the pergola

This is how I implemented it as a template sensor:

  - unique_id: pergola_slat_angle
    name: "Pergola Slat Angle"
    unit_of_measurement: "°"
    icon: mdi:angle-acute
    state: >
        {% set slat_azimuth = 207 %} 
        {% set min_slat_angle = 0 %}
        {% set max_slat_angle = 135 %}
        {% set deg2rad = pi/180 %}
        {% set sun_zenith = iif((state_attr('sun.sun', 'elevation') | float) < 0, 90, 90 - (state_attr('sun.sun', 'elevation') | float)) %}
        
        {% set ground_angle = (atan(tan(sun_zenith*deg2rad)*sin((sun_azimuth - slat_azimuth) * deg2rad))/deg2rad) | abs%}
        {% set over_axis = iif(sun_azimuth > slat_azimuth,-1,1) %}
        {% set slat_angle = (90 - ground_angle*over_axis) | round(0) %}
        {% set slat_angle = iif(slat_angle < min_slat_angle,min_slat_angle,slat_angle) %}
        {% set slat_angle = iif(slat_angle > max_slat_angle,max_slat_angle,slat_angle) %}
        {{slat_angle}}

I first calculate the offset from vertical, then adjust it pos/neg based on the position of the sun relative to the axis of the pergola and then constrain it within the set min/max angle.

This angle is the used by a script that sets the pergola to that desired angle however it first needs to be translated into % for the tilt service:

service: cover.set_cover_tilt_position
data:
  tilt_position: >-
    {% set min_angle = 0 %} 
    {% set max_angle = 135 %}
    {% set slat_percent = ((states('sensor.pergola_slat_angle') | int - min_angle)/(max_angle-min_angle)*100) |round(0)  %} 
    {{slat_percent}}
target:
  entity_id: cover.pergola_roof

It seems to work exactly as expected in all my simulated scenarios but I still need to run it through its paces on a sunny day…

Thanks for the nudge!

1 Like

Great to hear, looks very similar to how I implemented it for my project. Indeed the paper gives pretty much everything you need.

One tip, be careful with atan. Its range is limited between [-90, 90]. When you exceed it starts counting from 0 degrees again instead of 90. I suddenly remembered that when earlier today my solar panels started pointing away from the sun instead of tracking it…

As an alternative you could use atan2, which has a range of [-180, 180] :slight_smile:

ps, in your normalization formula under service: you are not subtracting min_angle from pergola_slat_angle. Doesn’t matter now because it’s 0 degrees anyway, but in case you might ever change it

Fixed the % calculation, thanks!

1 Like

Sorry for this possible off -topic, but do you actually have positionable solar panels? Must confess I never saw those for domestic use, and most certainly would be interested if you could provide a link to those.
thx

Sorry, it’s a DIY project. Homeassistjoenka (from DD discord) built the mechanics and electronics, I wrote the solar tracker software.

1 Like

btw I finally posted my project here: https://community.home-assistant.io/t/ha-solar-tracker/571372

1 Like

I wanted to let you all know I have made a new post with a much better control method:

Automatic blinds / sunscreen control based on sun platform