Hours of Daylight

I have the following configured and it works for displaying sunrise and sunset times.

sensor:
  - platform: template
    sensors:
      nextsunrise:
        friendly_name: 'Next Sunrise'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_rising) | timestamp_custom(' %I:%M%p') | replace(" 0", "") }}
        icon_template: mdi:weather-sunset-up
      nextsunset:
        friendly_name: 'Next Sunset'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_setting) | timestamp_custom(' %I:%M%p') | replace(" 0", "") }}
        icon_template: mdi:weather-sunset-down

I’d like to be able to use these times to display the hours of daylight but I just can’t get the template to do any math. It’s also complicated that after sunrise (and sunset) the next sunrise (sunset) will be for the next day. I can subtract the 2 values from each other and it seems to give a result in seconds (and can be + or - depending on if you are before sunset and after sunrise etc)

Is there any way I can do this? Or is there some component?

3 Likes

Do you mean total hours of daylight for the current day, or hours of daylight remaining in the current day?

total for current day.

Well, the easiest thing to do is to assume today’s sunrise and sunset are approximately the same as tomorrow’s sunrise and sunset. (The only time this probably isn’t true is when switching between DST and not.) So, these basic calculations might work for you:

{% set nr = as_timestamp(state_attr('sun.sun','next_rising')) %}
{% set ns = as_timestamp(state_attr('sun.sun','next_setting')) %}
{% if nr > ns %}
  {% set nr = nr - 60*60*24 %}
{% endif %}
{{ nr|timestamp_local }}
{{ ns|timestamp_local }}
{{ (ns - nr) / (60*60) }}

When I run this in the Template Editor, I get:

2018-07-11 05:29:16
2018-07-11 20:28:00
14.97888888888889

The idea is, before sunrise, the two values will be for today, so they can be used as is. But after sunrise (and before sunset), the sunrise value will go to tomorrow, and will be after the sunset value. In this case, just subtract a day from the sunrise value as a reasonable approximation. Then after sunset, both values will be for tomorrow, so again (as an approximation), just use them as is.

If that’s not good enough, then I think using an automation to record the values of next_rising and next_setting sometime after midnight, and then using those recorded values, might work.

2 Likes

Nice… what if I want hours:minutes? and yeah I knew i’d have to use tomorrow for today… not a problem.

{% set nr = as_timestamp(state_attr('sun.sun','next_rising')) %}
{% set ns = as_timestamp(state_attr('sun.sun','next_setting')) %}
{% if nr > ns %}
  {% set nr = nr - 60*60*24 %}
{% endif %}
{{ (ns - nr)|timestamp_custom('%H:%M',false) }}
3 Likes

Gives me 10:05 in the template editor which is correct. (But different to the first one)

That’s weird. When I did both ways, I got 14.98 and 14:58, which are the same.

oh of course…it’s winter here duh! I didn’t make a note of the first one but I’m sure you’re right… my mistake.

No problem. Yeah, 10 hours? I figured you must be somewhere in the southern hemisphere. :smile:

So I am trying to configure this sensor thus:

sensor:
  - platform: template
    sensors:
      daylight:
        friendly_name: 'Daylight'
          value_template: >
            {% set nr = as_timestamp(state_attr('sun.sun','next_rising')) %}
            {% set ns = as_timestamp(state_attr('sun.sun','next_setting')) %}
            {% if nr > ns %}
              {% set nr = nr - 60*60*24 %}
            {% endif %}
            {{ (ns - nr)|timestamp_custom('%H:%M',false) }}
          icon_template: mdi:sun

But I get a validation error:
Error loading /config/configuration.yaml: while parsing a block mapping
in “/config/packages/timetides.yaml”, line 24, column 9
expected , but found ‘’
in “/config/packages/timetides.yaml”, line 25, column 11

Line 24 is the friendly name…

2 Likes

I believe you’re indenting value_template and icon_template too much. They should be at the same indentation level as friendly_name.

1 Like

Ha! You’re right. Yaml is picky lol. Validates now and restarting HA…

And that did it! Thanks!

1 Like

I have been using your nice daylight sensor for some days. Noticed for my location that the calculations are becoming inaccurate, for where I live in the galaxy, up north. One day to another, can have up to 30 minutes daylight time difference.
daylight

Think I have tried coding every possibility (except the correct solution), and my test coding manipulating datetime in “Developer Tool->Templates” somehow works. But not in production.

Looks like the sensors are doing something at the right time of the night, but no sensor value are saved.
sunrisetoday

Trying to grab the sunrise/set data some minutes before solar midnight -(in the middle of sun set/rise). This way, HA have the sun rise and set for the next day. For more accurate daylight calculation.
Anyone, where do I go wrong with my code?

####################################################
# SUN RISE/SET & DAYLIGHT TIME TODAY               #
####################################################

  - platform: template
    sensors:
      sunrise_today:
        friendly_name: "Sun Rise Today"
        unit_of_measurement: 'Time'
        value_template: >-
          {% set nw = as_timestamp(now()) %}
          {% set mn = as_timestamp(state_attr('sun.sun','next_midnight')) - (2*60) %}
          {% if nw |timestamp_custom('%Y%m%d:%H:%M') == mn |timestamp_custom('%Y%m%d:%H:%M') %}
          {{ as_timestamp(state_attr('sun.sun','next_rising')) |timestamp_custom('%H:%M') }}
          {% endif %}
        icon_template: mdi:weather-sunset-up

      sunset_today:
        friendly_name: "Sun Set Today"
        unit_of_measurement: 'Time'
        value_template: >-
          {% set nw = as_timestamp(now()) %}
          {% set mn = as_timestamp(state_attr('sun.sun','next_midnight')) - (2*60) %}
          {% if nw |timestamp_custom('%H:%M') == mn |timestamp_custom('%H:%M') %}
          {{ as_timestamp(state_attr('sun.sun','next_setting')) |timestamp_custom('%H:%M') }}
          {% endif %}
        icon_template: mdi:weather-sunset-down

      daylight_time_today:
        friendly_name: 'Daylight Today'
        unit_of_measurement: 'Hours'
        value_template: >-
          {% set nw = as_timestamp(now()) %}
          {% set mn = as_timestamp(state_attr('sun.sun','next_midnight')) - (2*60) %}
          {% if nw |timestamp_custom('%H:%M') == mn |timestamp_custom('%H:%M') %}
          {{ (as_timestamp(state_attr('sun.sun','next_setting')) - as_timestamp(state_attr('sun.sun','next_rising'))) |timestamp_custom('%H:%M,false') }}
          {% endif %}
        icon_template: mdi:weather-sunny
1 Like

I think you need an automation and a couple of input_datetime’s to do this. I.e., have an automation that triggers just after midnight and the actions record the values of sunrise & sunset to input_datetime’s. Then use those in your template sensors. This is where I would have gone in my previous answers if using tomorrow’s values for today weren’t close enough.

I can help you write this if you like, but it will have to wait until tomorrow.

1 Like

Appriciate your response.

I have made some changes to manipulate the timestamp. I’ll know tomorrow if it works. Will tell you so.

I’d be interested in that…

Once it’s past sunrise, sun.sun’s next_rising attribute changes to the next day’s sunrise. So from sunrise to midnight you no longer have the time for today’s sunrise. You can do all you want with the template sensor and that won’t change. You have to record today’s sunrise before it disappears. Same thing goes with sunset. Given standard components I don’t see how you’ll be able to avoid that fact. But, if you can figure out a way, I’d also be interested in seeing how you did it. :slight_smile:

I think I have the logic working. Don’t like to put code out there not totally verified working, but please test it out, and tweak the code if you can add some to it.

The code saves sunrise and setting values, at midnight. This way displaying the values the entire day.
The sensors will start displaying values after the first midnight.

####################################################
# SUN RISE/SET & DAYLIGHT TIME TODAY               #
####################################################

  - platform: template
    sensors:
      sunrise_today:
        friendly_name: "Sun Rise Today"
        unit_of_measurement: 'Time'
        value_template: >-
          {% set nw = as_timestamp(now()) |timestamp_custom('%Y%m%d%H%M') |int %}
          {% set mn = as_timestamp(now()) |timestamp_custom('%Y%m%d0000') |int %}
          {% if nw == mn %}
          {{ as_timestamp(state_attr('sun.sun','next_rising'))|timestamp_custom('%H:%M') }}
          {% else %}
          {{ states('sensor.sunrise_today') }}
          {% endif %}
        icon_template: mdi:weather-sunset-up

      sunset_today:
        friendly_name: "Sun Set Today"
        unit_of_measurement: 'Time'
        value_template: >-
          {% set nw = as_timestamp(now()) |timestamp_custom('%Y%m%d%H%M') |int %}
          {% set mn = as_timestamp(now()) |timestamp_custom('%Y%m%d0000') |int %}
          {% if nw == mn %}
          {{ as_timestamp(state_attr('sun.sun','next_setting')) |timestamp_custom('%H:%M') }}
          {% else %}
          {{ states('sensor.sunset_today') }}
          {% endif %}
        icon_template: mdi:weather-sunset-down

      daylight_time_today:
        friendly_name: 'Daylight Today'
        unit_of_measurement: 'Hours'
        value_template: >-
          {% set nw = as_timestamp(now()) |timestamp_custom('%Y%m%d%H%M') |int %}
          {% set mn = as_timestamp(now()) |timestamp_custom('%Y%m%d0000') |int %}
          {% if nw == mn %}
          {{ (as_timestamp(state_attr('sun.sun','next_setting')) - as_timestamp(state_attr('sun.sun','next_rising'))) |timestamp_custom('%H:%M',false) }}
          {% else %}
          {{ states('sensor.daylight_time_today') }}
          {% endif %}
        icon_template: mdi:weather-sunny

I wonder did that work?

Funny, thinking about this, I’d really like to know the length of daylight hours for yesterday, today and today.

Had a bit of an internet trawl and found this site https://sunrise-sunset.org/api

Can send a request like this: https://api.sunrise-sunset.org/json?lat=36.7201600&lng=-4.4203400&date=today&formatted=0 where you can also do yesterday and tomorrow.

It spits out something like this:
{“results”:{“sunrise”:“2018-07-25T05:18:21+00:00”,“sunset”:“2018-07-25T19:30:05+00:00”,“solar_noon”:“2018-07-25T12:24:13+00:00”,“day_length”:51104,“civil_twilight_begin”:“2018-07-25T04:49:21+00:00”,“civil_twilight_end”:“2018-07-25T19:59:06+00:00”,“nautical_twilight_begin”:“2018-07-25T04:13:45+00:00”,“nautical_twilight_end”:“2018-07-25T20:34:42+00:00”,“astronomical_twilight_begin”:“2018-07-25T03:35:04+00:00”,“astronomical_twilight_end”:“2018-07-25T21:13:22+00:00”},“status”:“OK”}

So I’m going to have a play and see if I can use it. Times are UTC so need to be time shifted for your timezone…

Tried this in the template tool:
{% set my_test_json = {“results”:{“sunrise”:“2018-07-25T05:18:21+00:00”,“sunset”:“2018-07-25T19:30:05+00:00”,“solar_noon”:“2018-07-25T12:24:13+00:00”,“day_length”:51104,“civil_twilight_begin”:“2018-07-25T04:49:21+00:00”,“civil_twilight_end”:“2018-07-25T19:59:06+00:00”,“nautical_twilight_begin”:“2018-07-25T04:13:45+00:00”,“nautical_twilight_end”:“2018-07-25T20:34:42+00:00”,“astronomical_twilight_begin”:“2018-07-25T03:35:04+00:00”,“astronomical_twilight_end”:“2018-07-25T21:13:22+00:00”},“status”:“OK”} %}

The sunrise is {{ my_test_json.results.sunrise | timestamp_custom(’ %I:%M%p’) }}

But it’s not reformatting the time…

2 Likes