Detecting direct sunlight using lux sensor... and others?

I have an Tempest weather station on the top of my house (out of any shadow of tree or similar) which amongst other things has lux and uv sensors.

However I’m having an hard time determining when there is actual direct sunlight versus cloudy and what not. An static lux value simply does not suffice, as direct sunlight lux varies through both year and day which makes an static value unreliable.

So I was wondering how people have solved this?

I intend to use this with an cover automation and only close the cover if direct sunlight

What about the UV sensor, could that help to detect direct sunlight? I don’t have such a sensor, but I would imagine it reacting to direct sunlight too.

It seems the uv measurement is just on an different scale of the lux value, so either one would just give the same “output”

Hmm yeah those graphs looks pretty similar. I wonder what they’d show if you used a torchlight on them. The UV sensor should stay pretty quiet in that case.

Anyway maybe you can put some kind of filter on top of the lux sensor, so it only maxes out in direct sunlight?

I’d admit that I don’t really know what I’m talking about as with the lux sensors I’m using, I have no difficulty detecting direct sunlight (they shoot up like crazy).

I’m struggling with the same issue here. I have an ecowitt weather station that gives me lux and uv. But uv is nothing else that a calculated value from the lux input. A simple lux threshold is not enough to differentiate between cloudy and sunny.
I’m thinking about some kind of simulated lux curve that would fit the current time and date as a reference for sunny and the actual reading of the sensor.
Also, the weather forecast integration could be utilized as reading “cloudy” or something.
@jkaberg did you have a solution yet?

Yeah so I did work some more on this, its not perfrect but better

“Seasonal Illuminace Treshhold” sensor template:

{%- set day_of_year = now().timetuple().tm_yday -%}
{%- set mid_summer = 172 -%}
{%- set summer_threshold = 32000 -%}
{%- set winter_threshold = 8000 -%}
{%- set day_factor = (cos((day_of_year - mid_summer) * 2 * 3.14159 / 365) + 1) / 2 -%}
{{ (summer_threshold - winter_threshold) * day_factor + winter_threshold }}

Then I have another “direct sunlight” sensor based on the previous, its not 100% but pretty close

{% set illuminance = states('sensor.st_00117532_belysningsstyrke') | float(0) %}
{% set threshold = states('sensor.seasonal_illuminance_threshold') | float(0) %}
{% set sun_elevation = states('sensor.sun_solar_elevation') | float(None) %}
{% set weather_condition = states('weather.hjem') | lower %}

{% set is_illuminance_valid = states('sensor.st_00117532_belysningsstyrke') not in ['unknown', 'unavailable'] %}
{% set is_threshold_valid = states('sensor.seasonal_illuminance_threshold') not in ['unknown', 'unavailable'] %}
{% set is_sun_elevation_valid = states('sensor.sun_solar_elevation') not in ['unknown', 'unavailable'] %}
{% set is_weather_condition_valid = weather_condition not in ['unknown', 'unavailable', ''] %}

{% if not (is_illuminance_valid and is_threshold_valid and is_sun_elevation_valid and is_weather_condition_valid) %}
  unavailable
{% else %}
  {% set is_daytime = sun_elevation > 0 %}
  {% set is_bright = illuminance > threshold %}
  {% set is_clear_or_partly_cloudy = weather_condition == 'sunny' or 
    (weather_condition in ['cloudy', 'partlycloudy'] and illuminance > threshold * 0.6) %}
  
  {{ is_daytime and is_bright and is_clear_or_partly_cloudy }}
{% endif %}
1 Like

Thanks, that comes closer to what I was looking for. I started to use a aqara Lux sensor (LUMI) to get the Sunny/PartlyCloudy/Cloudy results from a sensor, and I have the same issue. The Lux, on a bright sunny day is moving on a curve. So while it’s easy and good to rely on it from 10AM to 6-7PM, outside those time, the lux values are low, even if it’s sunny outside, due to the static position of the sensor.
Ideally, the Lux value should be corrected by a azimuth/elevation factor to compensate…
Still looking to find the maths to do that, but in the mean time, your sensor is doing great, I just merged the 2 in one

{%- set day_of_year = now().timetuple().tm_yday -%}
{%- set mid_summer = 172 -%}
{%- set summer_threshold = 32000 -%}
{%- set winter_threshold = 8000 -%}
{%- set day_factor = (cos((day_of_year - mid_summer) * 2 * 3.14159 / 365) + 1) / 2 -%}

{% set illuminance = states('sensor.aqara_lumi') | float(0) %}
{% set threshold = (summer_threshold - winter_threshold) * day_factor + winter_threshold %}
{% set sun_elevation = states('sensor.sun_solar_elevation') | float(None) %}
{% set weather_condition = states('weather.home') | lower %}

{% set is_illuminance_valid = states('sensor.aqara_lumi') not in ['unknown', 'unavailable'] %}

{% set is_sun_elevation_valid = states('sensor.sun_solar_elevation') not in ['unknown', 'unavailable'] %}
{% set is_weather_condition_valid = weather_condition not in ['unknown', 'unavailable', ''] %}

{% if not (is_illuminance_valid  and is_sun_elevation_valid and is_weather_condition_valid) %}
  unavailable
{% else %}
  {% set is_daytime = sun_elevation > 0 %}
  {% set is_bright = illuminance > threshold %}
  {% set is_clear_or_partly_cloudy = weather_condition == 'sunny' or 
    (weather_condition in ['cloudy', 'partlycloudy'] and illuminance > threshold * 0.6) %}
  
  {{ is_daytime and is_bright and is_clear_or_partly_cloudy }}
{% endif %}

This is an intriguing subject.
Another solution might be to try to sense the direct effect of the difference between direct sunlight and scattered sunlight.
With direct sunlight there are clearly and sharp defined shades, and with clouded skies the shades are much more soft if any.
What about this:

This are to identical lux sensors S1 and S2 on a distance X, with vertical bars and slits in front of it, also with a width of X and at a distance X.
When you measure the difference in lux between S1 and S2, I can imagine that with direct sunlight this difference is much larger then with diffuse sunlight, because with direct sunlight one of the sensors always gets more shade from the bars then the other.
This might be further improved when combining this with the azimuth attribute of the sun.sun sensor.

Yes, that might be a solution, but at the start and end of day, as the angle of sun will be low, the impact will be smaller and might become difficult to map

Yes, I agree.
However, I think that at the early start and late end of the day it might not be that useful any more to sense direct sunlight: this is more useful when the sun is burning fully.
And of course with a fixed setup you always have a maximum of 180 degrees azimuth, which isn’t enough for a full day anyhow.
Where I live it now is mid summer, and the maximum azimuth angle from dawn to dusk is currently like 265 degrees.

Anyhow, it also depends on the geometry, like the distances X and the distance Y between the sensors and the bars.
My sketch was just a first quick idea to show the principle, so the geometry has to be optimized to get the most effective range.
And rethinking this, with two sensors like this there are azimuth angles where direct sunlight will still give identical outputs on both sensors, for instance as shown with the added blue sun beam:

So this has to be taken into account as well in the software.
Or possibly it might be better to have three lux sensors?

An alternative / addition could be to use the current weather forecast (cloud cover %) to augment the lux sensor.

At least where I live if it’s sunny and cold outside I want the shades open.