Enhanced Sun component

for me it was just the section I quoted…so only had to sun.py to its own folder in custom_components and renamed to …/sun/__init __.py as per your post.
Automations stayed as they were before and are working (based off sunset anyway)

Well, FWIW, I just updated my development checkout of the homeassistant code to the latest dev version (0.89.0.dev0), and added my sun.py to <config>/custom_components/sun.py and restarted. It works fine. The only message is the warning about using a custom version of the component. I even added an automation that uses a sun trigger and restarted. Still no problem. So not sure why you would have to move it to custom_components/sun/__init__.py.

In another thread (I think; I’m getting a little confused after this 0.88 update!!) @DavidFW1960 also said categorically that he did nothing with his sun.py and everything is working fine.

Mine seems to be working with no changes too but I only upgraded a few hours ago…

That was this thread…

In response to @pnbruckner, I’ll have a look around and and try your suggestions. Maybe I’ll just remove it and start again.

I think I only have one sunset automation which turns on some lights at sunset. I’ll have a look.

Sorry!
It’s been a hectic day :slight_smile:
(it’s my only excuse…)

I just did some more testing, and this time I did see the message about sun.automation:

Unable to prepare setup for platform sun.automation: Platform not found.
3:18 PM setup.py (ERROR)
Unable to find platform sun. Search path was limited to path of component: custom_components
3:18 PM loader.py (ERROR)
Error loading custom_components.sun.automation. Make sure all dependencies are installed
3:18 PM loader.py (ERROR)```

It seems I could only get this to happen when I created an automation that used a sun trigger via the Automation Editor. After restarting I did not see the error again (even though the automation was in automations.yaml.)

At one point I even got a persistent notification related to it. But I don’t remember exactly how I got that to happen, and I couldn’t reproduce it.

Not sure what to make of all of this.

This for me as well. I do have sun based automations and as I already said I have not changed a thing. I asked Balloob about this change in the context of 0.88 and ‘the great migration’ and he told me that sun.py is ok and does not need to be moved. I also get a warning about using a custom component for sun but I have ALWAYS had that warning.

FWIW, my automation was created manually as the automations editor sucks when you are using multiple and/or conditions…

Ok, I have some strange behaviour which might be related to the sun component…

I have an automation which turns on a light when it is dark. The sensor* that decides if it is dark uses the sun component.

Every time I start HA the light comes on. The automation is very simple and I can see no other reason than something is at odds with sun and 0.88.1

  - alias: Hall light on when dark
    initial_state: on
    trigger:
      - platform: state
        entity_id: binary_sensor.dark_hall
        to: 'on'

      - platform: homeassistant
        event: start

    condition:
      # Check it is dark (for when triggered by HA restart)
      - condition: state
        entity_id: binary_sensor.dark_hall
        state: 'on'

      # Check it is after 8am
      - condition: template
        value_template: "{{ states('sensor.time') > '08:00' }}"

    action:
      - service: homeassistant.turn_on
        entity_id: switch.hall_light

And here is the sensor

  - platform: template
    sensors:
      brightness:
        friendly_name: 'Outside Brightness'
        value_template: >-
          {%- set elevation = state_attr('sun.sun','elevation') | float %}
          {%- set cloud_coverage = states('sensor.dark_sky_cloud_coverage') | float %}
          {%- set cloud_factor = (1 - (0.75 * ( cloud_coverage / 100) ** 3 )) %}
          {%- set min_elevation = -6 %}     {# set this to official sun elevation for end of twighlight #}
          {%- set max_elevation = 62 %}     {# set this to the maximum noon sun elevation (minimum is 15 degrees) #}
          {%- set adjusted_elevation = elevation - min_elevation %}
          {%- set adjusted_elevation = [adjusted_elevation,0] | max %}
          {%- set adjusted_elevation = [adjusted_elevation,max_elevation - min_elevation] | min %}
          {%- set adjusted_elevation = adjusted_elevation / (max_elevation - min_elevation) %}
          {%- set adjusted_elevation = adjusted_elevation * 100 %}
          {%- set brightness = adjusted_elevation * cloud_factor %}
          {{ brightness | round }}
        unit_of_measurement: '%'
        device_class: 'illuminance'

*sorry @pnbruckner this seemed to work better for me than your illuminance sensor. Possibly that is because it uses the DarkSky cloud coverage percentage value rather than your values mapped to the icon? Although it is true to say that there are times when DS reports 100% cloud coverage (possibly as some kind of default value) when it is clearly not. (And I miss your ramping of values around dawn and dusk).

Maybe I’ve misread your example but I don’t see where the template sensor is used in the automation.

The template sensor’s friendly_name is ‘Outside Brightness’ and its entity_id is sensor.brightness.

  - platform: template
    sensors:
      brightness:
        friendly_name: 'Outside Brightness'

The automation does not refer to sensor.brightness. I assume there must be a configuration for binary_sensor.dark_hall that uses sensor.brightness?

As for sensor.brightness, what if the sun component is not available at the time the calculation is performed? What happens here to this line?

{%- set elevation = state_attr('sun.sun','elevation') | float %}
  • I believe it will set elevation to zero which will cause the calculation to report a very low brightness.
  • A low brightness value will cause binary_sensor.dark_hall to indicate it is dark.
  • If it is dark, and after 8:00 AM, the automation’s action will be executed (hall light turns on).
1 Like

Just about to make some of the same comments as @123. Specifically, how is binary_sensory.dark_hall defined? And have you looked in home-assistant.log to see what the values of that sensor, and sensor.brightness, are when the automation is triggered? (Look for the corresponding state_changed events just prior to the automation triggering.) And you could also see what the state of sun.sun is as well. All the details to answer your questions are probably sitting there for you to look at.

I suspect sun.sun will be initialized by the time this template sensor is processed. But this is a good point about other things that go into it, especially Dark Sky. One way to deal with this is to use a delayed homeassistant start event. I use this:

- alias: Delayed Startup
  trigger:
    - platform: homeassistant
      event: start
  action:
    - delay: 15
    - event: DELAYED_HOMEASSISTANT_START

Then I use that event instead of the homeassistant start event directly.

Additional comments (you didn’t ask for :wink:):

Why not change:

      - condition: template
        value_template: "{{ states('sensor.time') > '08:00' }}"

to:

      - condition: time
        after: '08:00:00'

Maybe this is why you asked for a new max_elevation attribute:

{%- set max_elevation = 62 %}     {# set this to the maximum noon sun elevation (minimum is 15 degrees) #}

:slight_smile:

1 Like

Can you explain why this works?

"{{ states('sensor.time') > '08:00' }}"

There is something going on here that I don’t understand. How can sensor.time’s state be compared to a string? Is there some sort of implicit type conversion happening?

Because, like the states of all entities, sensor.time’s state is a string. However, I would never do this because it depends on string comparisons which can sometimes give unexpected results. In this particular case, it probably works ok though.

I wouldn’t be surprised. My sensor uses an algorithm that someone else came up with that I used on SmartThings before moving to HA. I’ve given up on it, too. First because WeatherUnderground’s API is going away (if it hasn’t already), and neither Dark Sky nor YR seem to be as accurate as WU. Second because I finally broke down and bought an Aeotec MultiSensor 6 which is way better for accurate, real time sensing of the outside light level (and the PIR sensor comes in handy, too.)

1 Like

Thanks!

That’s what I assumed was happening (string comparison) … which makes me wonder why one would use greater than to compare strings in this situation? It’s actually doing a lexical order comparison (i.e. where “b” is greater than “a”) which seems like a roundabout way to compare two time values!

One of those situations where “it won’t fail if you use it just right”. :slight_smile:

@123 (and to some extent @pnbruckner but you’ll get specific comments in a minute :slight_smile: )
Yes, binary_sensor.dark_hall does use sensor.brightness, as do other binary_sensors for other rooms with each room having it’s own threshold above which it is considered dark.

Your explanation makes sense and may be the answer (notwithstanding @pnbruckner’s comment).

I only recently added the HA start trigger and as I mostly restart HA when it is dark the behaviour has always appeared to have been as I expected.

@pnbruckner This is an interesting idea, I might look into using this.

As for your un-asked for comments, consider there being a standing invitation for comments! The time condition must be throwback to some weird ideas I had when I first started with HA. I will be changing this immediately, and yes I think that might be why I asked but I am not now sure if a max elevation that changes during the year is appropriate for that sensor.

Thanks to both of you.

2 Likes

+1

I’ve been using two physical light sensors (not Aeotec but hard-wired sensors) for many years to calculate darkness (one is indoors and the other outdoors).

Many weeks ago, I discovered the illuminance sensor, based on Dark Sky values, and decided to give it a try. I compared the graph produced by the illuminance sensor to the graph from my outdoor light sensor. Conclusion: the illuminance sensor is better than nothing but not nearly as good as using a local, physical light sensor.

2 Likes

@pnbruckner, @123,

The use of

value_template: "{{ states('sensor.time') > '08:00' }}"

was a definite aberration of which I am slightly embarrassed but with Python still being a little alien to me I have to admit that I definitely struggle with dates and times.

I am guessing you would both also shudder at this, :roll_eyes:

{% if states('sensor.time') > '12:00' %}

which is a form I have used quite a few times in my templates. Can you suggest a better alternative? Unless you particularly want to, an explanation isn’t necessary, given the right syntax I can go away and look it up.

Thanks :slight_smile:

{% if now().hour >= 12 %}

Not exactly the same, but close enough. Or you could do:

{% set n = now() %}
{% if n.hour > 12 or n.hour == 12 and (n.minute or n.second or n.microsecond) %}

Also, the usual warnings about automatic entity extraction.

EDIT: Actually to be closest to what you had:

{% set n = now() %}
{% if n.hour > 12 or n.hour == 12 and n.minute %}
1 Like

It works the way you are using it … but it is working for reasons that are not exactly what they appear to be.

This statement:

{% if states('sensor.time') > '12:00' %}

is not really comparing one time to another or even one number to another. It’s comparing one string to another. So it’s like this:

{% if 'rat' > 'cat' %}

That example seems to make less sense yet it is valid and will evaluate to true. Why? Because the letter r is higher in the alphabet than the letter c (specifically, its character-code is higher). You can prove it to yourself using the Template Editor:

{% if 'rat' > 'cat' %}
YES
{% else %}
NO
{% endif %}

Change ‘rat’ to ‘bat’ and the result will be NO.

This is what’s really happening when you’re comparing sensor.time's state to '12:00'. It works but only because the data happens to be “just right”. :slight_smile:

1 Like