Help with Template Sensor (Hours until Sun Rise/Set)

I’ve got this template sensor which is working… OK… but seems to be out by an hour (due to time zones?)

I think I just need to subtract 1 hour dependant on the timezone (Daylight saving time)

# Next sunrise or sun set
- platform: template
  sensors:
    sun_rise_or_set:
       value_template: >-
             {% if is_state("sun.sun", "above_horizon") -%}
              {{ (as_timestamp(state_attr('sun.sun', 'next_setting')) - as_timestamp(now())) | timestamp_custom('%Hh %Mm %Ss') }}
             {%- else -%}
              {{ (as_timestamp(state_attr('sun.sun', 'next_rising')) - as_timestamp(now())) | timestamp_custom('%Hh %Mm %Ss') }}
             {%- endif %}
       icon_template: >-
          {% if is_state("binary_sensor.sun_up", "on") %}
            mdi:weather-sunset-up
          {% else %}
            mdi:weather-sunset-down
          {% endif %}   
{% set next = iif(is_state('sun.sun', 'above_horizon'), state_attr('sun.sun', 'next_setting'), state_attr('sun.sun', 'next_rising')) %}
{{ (next | as_datetime - now()).seconds | timestamp_custom('%Hh %Mm %Ss', False) }}
1 Like

As always, works flawlessly @petro, many thanks!

Quick question, I’m struggling with the ‘IDs’ for custom sensors which sends me here This entity does not have a unique ID? - Home Assistant

Is it possible to add IDs to these types of sensors?

I don’t think this is right, actually…
It’s now showing the next sun set, rather than sun rise…
image

I think there might be a small bug with above/below_horizon…?

state= above_horizon
elevation = -0.37

state = below_horizon
elevation = -0.98

This has now updated…
image

The template updates when the time updates on each minute and when the state of sun.sun updates.

Within the sun.sun, what defines the above/below horizon?

I might change the above to the elevation rather than “above/below” horizon…

no idea

It’s just a little weird that above shows it’s below horizon, but the state hasn’t yet updated… 4 minutes later, it does and changes to “below_horizon” … That is the root cause I believe.

Is it possible to check the attribute, if negetive=below, if positive=above?

If you just want the next sunrise or sunset, you don’t even need the above/below check. I just mimiced what you asked for.

This doesn’t care about the sun being up or down

{% set t = now() %}
{% set next = [ state_attr('sun.sun', 'next_rising'), state_attr('sun.sun', 'next_setting') ] | map('as_datetime') | reject('none') | sort %}
{% set next = next | reject('<', t) | list | first | default(t) %}
{{ (next - t).seconds | timestamp_custom('%Hh %Mm %Ss', False) }}
1 Like

You’re right, awesome!
Thanks again!!

Keep in mind, it doesn’t update on the second. It updates on the minute and when the attributes change. So there may be momentary times when it’s not 100% in sync because the sunrise/sets occur within the minute.

Also keep in mind that the sun sensor only has the current day’s sunset and sunrise and if you have past one of those points and not yet past midnight, then the calculations are made on the wrong times.
If you are close to equator, then this might not mean much, but if you instead are closer to one of the poles, then it can be some minutes off at peak times.

So… the best solution for all time zones is…

Use Sun2 instead of the builtin sun sensor.

Edit: Looks like the builtin sun can actually do it here. Maybe it was just the automations that caused issues when the before sunrise and after sunset was used as a trigger. Well, I still stick to Sun2 :slight_smile:

Hmm I’m not sure.
I’m wanting to keep it as simple as possible…

All i want is…
If sun down - show time till next rise (with icon)
If sun up - show time until next sun set (with icon)

The original code I had worked fine but just didn’t accommodate for different time zones (BST)

Made an amendment to the original code and just subtracted 60mins off the time…

             {% if is_state("sun.sun", "above_horizon") -%}
              {{ (as_timestamp(state_attr('sun.sun', 'next_setting')) - as_timestamp(now())-3600) | timestamp_custom('%Hh %Mm %Ss') }}
             {%- else -%}
              {{ (as_timestamp(state_attr('sun.sun', 'next_rising')) - as_timestamp(now())-3600) | timestamp_custom('%Hh %Mm %Ss') }}
             {%- endif %}

You’re going to have the same issue you had with my first post… my second template fixes it. That’s the one you should be using as it will be the most accurate.

1 Like

To be more clear with the warnings I posted, they will all have the caveats that are listed in this thread. It’s how templates work, it’s not the template that’s the problem.

Templates with now in them only update on the minute. Templates also only update when referenced entities update.

All templates posted here, yours, mine, etc will all have the same problems you see. The second template I posted will be the most accurate and will not require extra math when dst changes

1 Like

I have no idea what’s happening here haha…

I have another sensor that is looking at the “above_horizon” which works fine…
As soon as the “sun set time” hits, this sensor triggers (as it controls my lights automations)

But weirdly, when I want the above (which is a similar IF statement) - there’s a little lag before the sensor actually updates.

So at the minute of sunrise/set, this sensor updates instantly…

- platform: template
  sensors:
    sun_up:
       value_template: >-
         {{ is_state("sun.sun", "above_horizon") }}
       icon_template: >-
          {% if is_state("binary_sensor.sun_up", "on") %}
            mdi:weather-sunset-up
          {% else %}
            mdi:weather-sunset-down
          {% endif %}   

For some weird reason, this appears to have a several minute lag before it updated

{% set t = now() %}
{% set next = [ state_attr('sun.sun', 'next_rising'), state_attr('sun.sun', 'next_setting') ] | map('as_datetime') | reject('none') | sort %}
{% set next = next | reject('<', t) | list | first | default(t) %}
{{ (next - t).seconds | timestamp_custom('%Hh %Mm %Ss', False) }}