Hours of Daylight

I wanted to do this in NodeRed hooked into HA rather than using the HA scrape - just for the hell of it really, I use NodeRed hooked into HA via the NR companion (home-assistant-websocket) but sure people can adjust accordingly.

Here is the flow - the URL is coded into the triggers (I’ve mangled my location - but left the long lat in the URL so it’s obvious where it goes) - just thought may be useful if anyone stumbles on this thread in the future.

[{"id":"71c2975b48b5dda9","type":"inject","z":"babcd6f0d89239b1","name":"AstroData Trigger","props":[{"p":"url","v":"https://www.timeanddate.com/astronomy/@50.0000000,-0.8000000","vt":"str"},{"p":"timestamp","v":"","vt":"date"}],"repeat":"","crontab":"00 01 * * *","once":false,"onceDelay":0.1,"topic":"","x":130,"y":260,"wires":[["397d944e8e0e381a"]]},{"id":"397d944e8e0e381a","type":"http request","z":"babcd6f0d89239b1","name":"Get Page","method":"GET","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":180,"y":200,"wires":[["86ff838afb194ddf","02e8d453e2f9f0f1"]]},{"id":"02e8d453e2f9f0f1","type":"html","z":"babcd6f0d89239b1","name":"Daylight Times","property":"payload","outproperty":"payload","tag":"table[id=lm-key]>tbody>tr[id=lm-leg-4]","ret":"html","as":"single","x":400,"y":200,"wires":[["fc056fb3333bd74f"]]},{"id":"fc056fb3333bd74f","type":"function","z":"babcd6f0d89239b1","name":"Handle String","func":"function extract_target(s) {\n    let r = {};\n    const extRegexp = /(\\d\\d:\\d\\d)/g;\n    const m = [...s.matchAll(extRegexp)];\n\n    if (m.length) {\n        r['start'] = m[0][1];\n        r['end'] = m[1][1];\n    }\n    return r;\n}\n\nmsg.payload = extract_target(msg.payload[0]);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":200,"wires":[["3b583fb66759cb20"]]},{"id":"86ff838afb194ddf","type":"html","z":"babcd6f0d89239b1","name":"Daylight Length","property":"payload","outproperty":"payload","tag":"div[id=cs-dl]","ret":"html","as":"single","x":400,"y":240,"wires":[["9a2d6c8687b13174"]]},{"id":"9a2d6c8687b13174","type":"function","z":"babcd6f0d89239b1","name":"Handle String","func":"function extract_target(s) {\n    let r = {};\n    const extRegexp = /<span id=\"cs-daylength\">([^\\(]+)\\(.*?<p>([^\\(]+)/g;\n    const m = [...s.matchAll(extRegexp)][0].map( e => e.trim() );\n    const t = m.shift();\n    let H = 0;\n    let M = 0;\n    let S = 0;\n    \n    if (m.length == 2) {\n        if (/\\d+h/.test(m[0])) {\n            H = /(\\d+)h/.exec(m[0])[1];\n        }\n        if (/\\d+m/.test(m[0])) {\n            M = /(\\d+)m/.exec(m[0])[1];\n        }\n        if (/\\d+s/.test(m[0])) {\n            S = /(\\d+)s/.exec(m[0])[1];\n        }\n        r['duration'] = (parseInt(H)*60*60 + parseInt(M)*60 + parseInt(S));\n        r['human_length'] = m[0];\n        r['human_delta'] = m[1];\n    }\n    return r;\n}\n\nmsg.payload = extract_target(msg.payload[0]);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":240,"wires":[["3b583fb66759cb20"]]},{"id":"3b583fb66759cb20","type":"merge","z":"babcd6f0d89239b1","name":"","timeout":"","x":830,"y":220,"wires":[["d46b3948f9bb5704"]]},{"id":"d46b3948f9bb5704","type":"function","z":"babcd6f0d89239b1","name":"Blend","func":"let np = {};\nfor (let ml1 in msg.payload) {\n    for (let ml2 in msg.payload[ml1].payload) {\n        np[ml2] = (msg.payload[ml1].payload[ml2]);\n    }\n}\n\n// Preserve some values\nmsg['timestamp'] = msg.payload[0].timestamp;\nmsg['url'] = msg.payload[0].url;\nmsg['statusCode'] = msg.payload[0].statusCode;\n\nmsg.payload = np;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":220,"wires":[["41cfaa3b97ad3766"]]},{"id":"41cfaa3b97ad3766","type":"ha-entity","z":"babcd6f0d89239b1","name":"AstroData Daylight","server":"2d3371bf08f58b58","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"AstroData Daylight"},{"property":"device_class","value":"sensor"},{"property":"icon","value":"mdi:sun-clock"},{"property":"unit_of_measurement","value":"seconds"},{"property":"state_class","value":"total"},{"property":"last_reset","value":""}],"state":"payload.duration","stateType":"msg","attributes":[{"property":"start_daylight","value":"payload.start","valueType":"msg"},{"property":"end_daylight","value":"payload.end","valueType":"msg"},{"property":"text_daylight_length","value":"payload.human_length","valueType":"msg"},{"property":"text_daylight_delta","value":"payload.human_delta","valueType":"msg"},{"property":"updated","value":"timestamp","valueType":"msg"},{"property":"url","value":"url","valueType":"msg"},{"property":"statusCode","value":"statusCode","valueType":"msg"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":1170,"y":220,"wires":[[]]},{"id":"3b428d8ac24a63d7","type":"inject","z":"babcd6f0d89239b1","name":"AstroData Trigger","props":[{"p":"url","v":"https://www.timeanddate.com/astronomy/@50.0000000,-0.8000000","vt":"str"},{"p":"timestamp","v":"","vt":"date"}],"repeat":"","crontab":"00 06 * * *","once":false,"onceDelay":0.1,"topic":"","x":130,"y":140,"wires":[["397d944e8e0e381a"]]},{"id":"2d3371bf08f58b58","type":"server","name":"HA","version":2,"addon":false,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"}]

Seems it’s no more working from today :(… I guess they changed the design of the webpage…

Why are yiu using scrape anyway? I use the sun2 custom component

Ho I will look for it :slight_smile: in HACS ?

Ok found it & installed

1 Like

Selectors as follows:

Moon: div[id=qlook]
Daylight Times: table[id=lm-key]>tbody>tr[id=lm-leg-4]
Daylight Length: div[id=cs-dl]

I’ve installed the Sun2 custom HACS component (really great work, makes this much easier than I expected it to be!)

My only question is how to change the output format of the sensors. If I just display them as entities in Lovelace I get this info for sensor.sunrise, sensor.sunset, and sensor.daylight. I’d prefer them to be in HH:MM format rather than “X hours ago/In X hours” or “time as a decimal value”

Screen Shot 2023-02-02 at 10.44.06 AM

(these are type: custom:mushroom-chips-card)

EDIT: It was as simple as a template card instead of an entity card:

{{ as_timestamp(states('sensor.sunrise')) |  timestamp_custom("%I:%M %p") }}

I am using your code. And it works like a charm. But the icon_template: mdi:sun is not working. The sensor has no icon. And I don’t understand, what is the problem here. Do you have a solution for that?

My code:

  - platform: template
    sensors:
      daylight:
        friendly_name: 'Daylight'
        icon_template: mdi:sun
        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) }}

Edit:
Found the error. The icon mdi:sun not exists! So I used mdi:sun-clock instead.

1 Like

For some reason I can’t find this HACS-integration within HA.
Is it this repository?

Try mdi:weather-sunny I think it changed a long time ago. This is an old thread.

1 Like

Yes and you can add that repo to HACS manually

1 Like

Thanks!

For some reason I can’t. The ADD Button is grey. And I don’t know why. I added custom repositories already before… Strange.

Bildschirmfoto 2023-03-06 um 19.53.12

maybe try clearing cache?

I read most of this thread in detail, I’m looking to get the number of minutes of daylight remaining in the day if it already light?
For example,
if its 2am and dark I want it to say 0,
if its noon and sunset is at 6pm I want it to say 360mins, or 6h 0Mins (I think I can work with either).
If its 7pm and sunset was 6pm I want it to say 0.
Is there any easy way to do this?

{% set next_setting = state_attr('sun.sun', 'next_setting') | as_datetime %}
{% set next_rising = state_attr('sun.sun', 'next_rising') | as_datetime %}
{% set midnight = today_at() + timedelta(days=1) %}
{% if next_rising <= midnight or next_setting >= midnight %}
  {# before sunrise or after sunset #}
  {{ timedelta(seconds=0) }}
{% else %}
  {# daytime #}
  {{ next_setting - now() }}
{% endif %}

nice!
Ive always used this, based on the CC SUn2 by Phil Brucker:

{% set nw = now() %}
{% set sr = state_attr('sensor.zon_rising','today') %}
{%- set ss = state_attr('sensor.zon_setting','today') %}
{%- if nw < sr %} {{- ((ss - sr).total_seconds()/60)|int}}
{%- elif nw < ss %} {{- ((ss - nw).total_seconds()/60)|int}}
{%- else %} 0
{% endif %}

which returns in minutes, but that is not a true issue, just posting for the different approach

btw, you can just add it in Dashboard using the relative option (if that is what you want, and dont need the number in other backend logic)

  - type: attribute
    entity: sun.sun
    attribute: next_setting
    format: relative

though it is not as exact, but rounded