Enhanced Sun component

Ok, I see.

Yes, you could change _ELEV_RND to 0.1 instead of 0.5, but I think that would be overkill.

I would do it a different way. First I’d define two binary sensors:

binary_sensor:
- platform: sun2
  monitored_conditions:
  - elevation: -5
  - elevation: 5

Now create an automation that is triggered when binary_sensor.above_5_0 goes off. Have the action be a repeat loop that increases the brightness on each loop. Include in the loop a delay that uses a template to calculate the delay based on how much time will elapse until binary_sensor.above_minus_5_0 changes to off by using its next_change attribute.

So basically when binary_sensor.above_5_0 changes to off (and triggers the automation), binary_sensor.above_minus_5_0 will still be on, and its next_change attribute will indicate when it will change to off. So the difference between that time and now() is how much time will elapse between the sun being +5 and -5 degrees. You can then, say, divide that time by 10, where the automation increases the bulb’s brightness each time (by 10%.)

Let me know if you can’t work out the automation and I can give it a shot.

EDIT:

Here’s what I was thinking regarding the automation:

automation:
  - trigger:
      - platform: state
        entity_id: binary_sensor.above_5_0
        to: 'off'
    action:
      - variables:
          steps: 10
          light: light.LIGHT
          time: >
            {{ (state_attr('binary_sensor.above_minus_5_0', 'next_change') - now())
               .total_seconds() }}
      - repeat:
          count: "{{ steps - 1 }}"
          sequence:
            - service: light.turn_on
              data:
                entity_id: "{{ light }}"
                brightness_step_pct: "{{ 100 / steps }}"
            - delay: "{{ time / (steps - 1) }}"
      - service: light.turn_on
        data:
          entity_id: "{{ light }}"
          brightness_pct: 100

Great idea! Thanks!!!

Hi Phil,

looking for a binary sensor on the solar noon (to trigger automations) I was wondering if we could create that with your integration. However, adding the solar_noon to the config throws an error, so guess not :wink:

would you know how to create that, or would you be willing to add it to the integrations options?
thanks!

How did you try to add it?

You can add solar_noon for a “regular” sensor. Then you could use that to trigger an automation, either directly, or via a template binary sensor that indicates when the current time is after solar noon.

A yes of course, I’ll create a template trigger.

I did add the regular solar_noon sensor, but tried that too in the binary_sensor configuration. Only later realizing that a binary on the solar_noon would only be on for 1 second a day. That is the moment I need the trigger, but it might not be very useful otherwise.

would you pin point it to the exact moment?

{{states('sensor.time') == as_timestamp(states('sensor.astral_solar_noon'))|timestamp_custom('%H:%M')}}

or prefer the relational

{{as_timestamp(now()) > as_timestamp(states('sensor.astral_solar_noon'))}}

Btw, how would I be able to use the sensor directly as you say ? We never know when that will be?

By using it directly I meant in a template trigger, as opposed to creating a template binary sensor from it and then using that in a state trigger.

How about:

trigger:
  platform: template
  value_template: >
    {% set noon = state_attr('sensor.astral_solar_noon', 'today') %}
    {{ noon is not none and now() > noon }}
1 Like

yes, that would do it, much better.

the binary sensor template I made above would have triggered twice probably, but this will only fire once, so I can use it in an automation that should trigger on date change, and at solar noon.
If you have an extra spare moment, might I ask you to check the challenge I need this for?

not in a hurry, but I’d appreciate your expertise in the matter

Sorry, I’m not sure I’m following you here. The template trigger I suggested will only fire once a day, when it changes from False to True, which happens when the current time surpasses the day’s solar noon. At midnight the solar noon sensor will update and the template will change from evaluating as True to False, which will not cause the trigger to fire.

BTW, you can change > to >=, which is slightly more appropriate, but in practice probably won’t have much of an effect.

Um, I read it briefly, but I couldn’t easily wrap my head around what you’re trying to do. If the question is, how to cause something to happen at change of day, why not have an automation with a time trigger that triggers at 00:00:00, with appropriate conditions?

yes, thats what I was trying to say, and what was the benefit over it compared to a binary template sensor I made, which triggers twice a day (and needs the extra to: 'on' because of that)

no it wasn’t the issue of triggering at daystart…
the challenge was/is to check whether the conditionas are met for the pond pumps to alternate (opposed to both of them being always on)

they need to be alternating either when it is below 6 degrees, or when the sun is down. And survive restarts.

an automation with a ‘while’ construct I made at first doesn’t survive restarts, so now I use these 3 small automations:
1 to set alternating mode, and turn-off 1 switch (so the next automation only needs a toggle service, triggered by the binary sensor checking the temperature and daylight condition
2 to actually toggle, and is triggered by the day change and your noon template (needed in longer periods of cold)
3 to leave alternating mode and turn on both of them again

btw, your suggestion to use
state_attr('sensor.astral_solar_noon', 'today') works fine, and I am trying to understand why it is better than using states('sensor.astral_solar_noon') which renders the same result, only without the T.

Having seen several other issues with that resulting in incorrect frontend representation of the timestamp, we had to cure that adding .isoformat(), making it a true datetime.datetime object

I ask because the states show the attributes With the T…

while the templates show:

and yes, adding that to the {{state_attr('sensor.astral_solar_noon','today')}} results in the correct time with the T

      solar_noon:
        value_template: >
          {{states('sensor.astral_solar_noon')}}
        device_class: timestamp
      solar_noon_today:
        value_template: >
          {{state_attr('sensor.astral_solar_noon','today')}}
        device_class: timestamp
      solar_noon_today_iso:
        value_template: >
          {{state_attr('sensor.astral_solar_noon','today').isoformat()}}
        device_class: timestamp

in frontend (atop is the astral sensor from your integration):

Because that is not the only difference. The today attribute is a Python datetime object, just like what is returned by the now() function, so they can be compared directly. The state, however, is, of course, like all states, a string, which is more difficult to compare to a Python datetime object. (I.e., you need to use as_timestamp(), etc.)

Regarding the rest of your comment, the state will always show as it is, because it’s a string. It doesn’t need any further formatting when displayed. However, how a Python datetime object (attribute) is displayed depends on how/where it’s being displayed. But, no matter how it’s displayed, it’s still a Python datetime object and can be used as such. (And, yeah, by “datetime” I mean “datetime.datetime”.)

thanks Phil, ive adapted it all, and working fine now.

I do need your assistance on a couple of template sensors calculating the remains daylights time. Before I used the extra attributes your now archived Sun integration added to the core sun.sun and the templates.

      daylight_remaining_min:
        friendly_name: Daylight remaining minutes
        value_template: >
          {{((as_timestamp(state_attr('sun.sun','next_setting')) - now().timestamp())/60)|int}}
        unit_of_measurement: min

      daylight_remaining_hm:
        friendly_name: 'Daylight remaining hh:mm'
        value_template: >
          {{(as_timestamp(state_attr('sun.sun','next_setting')) - now().timestamp())
             |timestamp_custom('%H:%M',false)}}

because I had checked these during daytime only thus far, I hadn’t noticed they show strange states in the evening, when there of course is no more remaining daylight at all… still:

It is a bit silly to show20 hours of remaining daylight, at 23:07 ? Of course it simply calculates the time until the next setting… which would make it only a naming issue, unless I miss something you did I the archived integration.

Im struggling to make that a more adaptive sensor, showing 0 when the sun is down, (no more remaining daylight that day, or on the next day until sunrise, showing the true remaining daylight calculated from that days sunrise tilll sunset…

{% if is_state('sun.sun','above_horizon') %}
{{((as_timestamp(state_attr('sun.sun','next_setting')) - now().timestamp())/60)|int}}
{% else %} 
{{state_attr('sensor.astral_daylight','tomorrow')}}
{% endif %}

would this pass the correct day changes? I need to use the new Sun enhanced integration’ ‘astral’ sensors

{{state_attr('sensor.astral_daylight','tomorrow')}} and {{state_attr('sensor.astral_daylight','today')}} in a better way.

Use the sunset option for sun2. Then:

{{ [0, (state_attr('sensor.astral_sunset', 'today') - now()).total_seconds()]|max }}

That is in seconds. If you want it shown elsewise, then adjust accordingly.

EDIT: Actually, I need to also take into account if it’s before sunrise, so…

EDIT 2: Ok, try this on for size:

{% set nw = now() %}
{% set sr = state_attr('sensor.astral_sunrise', 'today') %}
{% set ss = state_attr('sensor.astral_sunset', 'today') %}
{% if nw < sr %}
  {{ (ss - sr).total_seconds() }}
{% elif nw < ss %}
  {{ (ss - nw).total_seconds() }}
{% else %}
  0
{% endif %}
1 Like

thanks Phil,
making that use aH:M:S format:

{% set nw = now() %}
{% set sr = state_attr('sensor.astral_sunrise', 'today') %}
{% set ss = state_attr('sensor.astral_sunset', 'today') %}
{% if nw < sr %}
  {{ (ss - sr).total_seconds()|timestamp_custom('%-H:%M:%S',false) }}
{% elif nw < ss %}
  {{ (ss - nw).total_seconds()|timestamp_custom('%-H:%M:%S',false) }}
{% else %}
  0
{% endif %}

will see what happens tonight…

If that’s what you want, then no need to convert to seconds and reformat. Just let it use the default datetime.timedelta display format:

{% set nw = now().replace(microsecond=0) %}
{% set sr = state_attr('sensor.astral_sunrise', 'today') %}
{% set ss = state_attr('sensor.astral_sunset', 'today') %}
{% if nw < sr %}
  {{ ss - sr }}
{% elif nw < ss %}
  {{ ss - nw }}
{% else %}
  0:00:00
{% endif %}
1 Like

And knowing how you like everything “guarded” :wink:

{% set nw = now().replace(microsecond=0) %}
{% set sr = state_attr('sensor.astral_sunrise', 'today') %}
{% set ss = state_attr('sensor.astral_sunset', 'today') %}
{% if sr is none or ss is none %}
  unknown
{% elif nw < sr %}
  {{ ss - sr }}
{% elif nw < ss %}
  {{ ss - nw }}
{% else %}
  0:00:00
{% endif %}
2 Likes

Right, need guards! Haha, thanks. Glad you helped me out.

still, this is not as expected, or maybe I should say, as intended? it is utterly dark right now, and definitely before sunrise, and yet is shows the remaining daylight. One could philosophize on the correctness of that (it is after all the remaining time of daylight for today), yet I would have hoped your words

would have accounted for this?

guess I was looking for:

{% if sr is none or ss is none %}
  unknown
{% elif sr < nw < ss %}
  {{ ss - nw }}
{% else %}
  0
{% endif %}

Exactly. That’s what I intended and what I thought you wanted. If something else, then adjust accordingly. Your last template seems like it will do what you want.

getting back on the guard, what are your thoughts on the availability_template?

something like:

availability_template: >
  {% set sr = state_attr('sensor.astral_sunrise', 'today') %}
  {% set ss = state_attr('sensor.astral_sunset', 'today') %}
  {{ sr not is none and ss not is none }}

I ask because I have several automations triggering on comparable template (binary_)sensors, and these tend to trigger on reload of the template entities. Preventing that has been a struggle here and there, and either adding these conditions to the automation, or the availability_template to the template sensors is the advised way to go, though not always successful.

That looks reasonable. I did look briefly into what availability_template does when I first became aware of it, but I don’t remember the details. I think it basically just causes the entity’s state to change to 'unavailable' (when the template evaluates to something other than true.)

I’m guessing that is causing the entities to be deleted and recreated. Which means their states are changing from something to none, and then from none to something. I.e., if you had a state trigger set up to listen to a template sensor, when the template sensor is reloaded, you’ll get (possibly, depending on how you have to: & from: configured) two trigger events. The first with trigger.to_state is none, and the second with trigger.from_state is none. I don’t think availability_template will have any affect with respect to this.