Turn on the light with motion sensor but during specific hours (based on sun rising and setting)

I have working automation that is turning the light when the motion sensor detects movement.

- alias: Turn on the light
  trigger:
    platform: state
    entity_id: binary_sensor.move_corridor
    to: 'on'
  condition:
    -  condition: template
       value_template: >
        {% set n = now() %}
        {% set n = (n.hour*60+n.minute)*60+n.second %}
        {% set ts_from = state_attr('input_datetime.light_from_time', 'timestamp') %}
        {% set ts_to = state_attr('input_datetime.light_to_time', 'timestamp') %}
        {{ n > ts_from or n < ts_to }}
  action:
    - service: homeassistant.turn_on
      entity_id: switch.light_corridor

Now Iā€™d like to remove two input_datetime and use sun.
The idea is to turn on the light between sun setting and rising (and of course if the motion sensor detects the movement)

here is my current not working code:

{% set offset_rising = 30 %}
{% set offset_setting = -20 %}
{% set rising= as_timestamp(states.sun.sun.attributes.next_rising) + (offset_rising *60) %}
{% set setting= as_timestamp(states.sun.sun.attributes.next_setting) + (offset_setting *60) %}
{{(rising) | timestamp_custom('%H:%M:%S') }}
{{(setting) | timestamp_custom('%H:%M:%S') }}


{% set n = now() %}
{% set n = (n.hour*60+n.minute)*60+n.second %}
{{rising}}
{{setting}}
{{n}}
{{ n > rising or n < setting}}

the problem is that rising and setting have full date in them, I need to get only time to be able to calculate the timestamp from hours, minutes and seconds.

How can I remove date from states.sun.sun.attributes.next_rising and calculate timestamp only for time?

Not entirely sure what youā€™re after, but hereā€™s more info: https://www.home-assistant.io/integrations/sun/

You might specifically be looking for above_horizon and below_horizon

i think this will do what you want. It uses the sunset/sunrise condition.

- alias: Turn on the light
  trigger:
    platform: state
    entity_id: binary_sensor.move_corridor
    to: 'on'
  condition:
    condition: or
    conditions:
      - condition: sun
        after: sunset
        after_offset: '-00:20:00'
      - condition: sun
        before: sunrise
        before_offset: '00:30:00'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.light_corridor

@123 This is almost perfect, but I want to allow setting the offset from the UI. Can I use a template for after and before offset?

Mark I looked at this, but when using above_horizon and below_horizon I wonā€™t be able to add any offset.
For example, I want my motion sensor to work between setting -0,5 hour and rising +0,5 hour.
Iā€™m trying to calculate timestamp from hours, minutes and seconds, but I canā€™t do that (donā€™t know how) from states.sun.sun.attributes.next_rising

You overlooked to mention that in your first post. In fact, your example shows hard-coded offsets.

No. The example I posted is incompatible with the new requirement. Youā€™re back to the challenge of creating a template.

Iā€™m able to calculate timestamp for current time:

{% set n = now() %}
{% set n = (n.hour*60+n.minute)*60+n.second %}

but I donā€™t know how to get time from states.sun.sun.attributes.next_rising

if I enter below code into template I get below result.

Template:

{% set n = now() %}
{% set s = states.sun.sun.attributes.next_setting %}
{{n}}  {{n.hour}}
{{s}}  {{s.hour}}

Result:

2019-11-06 14:08:51.478217+01:00  14
2019-11-06T15:10:47+00:00

Iā€™m able to get hour property from n, but not from s.

According to the docs (https://www.home-assistant.io/integrations/sun/) next_rising and next_setting contain date and time in UTC.
How can I convert those values to local time and then get hours, minutes and seconds for them?

I think I got something working:

{% set setting = states.sun.sun.attributes.next_setting %}
{{setting}}

{% set setting = strptime(states.sun.sun.attributes.next_setting, '%Y-%m-%dT%H:%M:%S%z') %}
{{setting}}
{{setting.hour}} {{setting.minute}} {{setting.second}}

but it is very ugly - I must use strptime with specific format.

At first, I thought that states.sun.sun.attributes.next_setting will return date and time (as written in docs), but it is returning a string. This is really weird. I get a string, that I must convert to datetime.
Iā€™m not sure if the value is in my current time zone, Iā€™ll check that and get gack with fully working code.

If there is a better way please let me know!

now() is a function that returns a datetime object.
The attributes of sun.sun are strings.

If you want the time of the sunā€™s next_rising, in local time (not UTC), you can do it like this (it produces a string):

{{ as_timestamp(states.sun.sun.attributes.next_setting) | timestamp_custom('%H:%M:%S', true) }}
1 Like

That was the piece I had missing.
Now the full template looks like this:

{% set offset_rising = 20 %}
{% set offset_setting = -30 %}

{% set n = now() %}
{% set n = as_timestamp(n) | timestamp_custom('%H:%M:%S', true)  %}

{% set rising = as_timestamp(states.sun.sun.attributes.next_rising) | timestamp_custom('%H:%M:%S', true) %}
{% set rising_offset = (as_timestamp(states.sun.sun.attributes.next_rising) + (offset_rising *60) ) | timestamp_custom('%H:%M:%S', true) %}


{% set setting = as_timestamp(states.sun.sun.attributes.next_setting) | timestamp_custom('%H:%M:%S', true) %}
{% set setting_offset = (as_timestamp(states.sun.sun.attributes.next_setting) + (offset_setting *60)) | timestamp_custom('%H:%M:%S', true) %}


now: {{n}}

rising: {{rising}}
rising+offset: {{rising_offset}}

setting: {{setting}}
setting+offset: {{setting_offset}}

active: {{ n < rising_offset or n > setting_offset}}

The idea is to have a motion sensor working from the sunset to sunrise, but with offsets, for example, start 30 minutes before sunset and end 20 minutes after sunrise. Those two offsets will be configurable from the UI, thatā€™s why I had to use a template.

A couple of things to considerā€¦

First, using adjustable offsets from sunrise and/or sunset typically implies youā€™re trying to compensate for the fact that it gets light/dark a different amount of time from sunrise/sunset during different times of the year. The usual way to solve that problem is to use the sunā€™s elevation instead of offsets from sunrise/sunset. See the sun elevation condition.

Next, if you do want to use a template to calculate offsets from sunrise/sunset, youā€™ll discover that the sunā€™s next_rising and next_setting attributes are not consistent throughout the day. In fact, they donā€™t indicate todayā€™s event, they indicate the next event. So in the beginning of the day next_rising, for example, will indicate when the sun next rises, which will be todayā€™s sunrise. However, once that time passes (i.e., once the sun has risen) it will be tomorrowā€™s sunrise. This often plays havoc with templates when used in automation triggers and/or conditions.

If you still want to calculate offsets from sunrise/sunset in templates, then you might be interested in my sun2 custom integration. It creates individual sensors for each sun related event of interest which change only at midnight and are therefore ā€œstableā€ throughout the day. E.g., here is what the sunrise sensor looks like:

Youā€™ll see that the sensorā€™s state is todayā€™s sunrise as an ISO formatted datetime string, and it has attributes for yesterday, today & tomorrow which are all Python datetime objects. So itā€™s very easy to compare to the current time, e.g.:

{{ (now() - state_attr('sensor.sunrise', 'today')).total_seconds() > blahblahblah }}
2 Likes

If youā€™re just looking for light levels outside - you could either setup a sensor outside to measure the actual levels - or if not that route you could also use @pnbrucknerā€™s illuminance sensor here: https://github.com/pnbruckner/ha-illuminance

Personally, I went the former route and setup a multi-sensor on the front porch. This has the added benefit of being able to turn on my front porch lights when thereā€™s motion and the light level is below a certain threshold.

Anyhow, Iā€™ve not use the illuminance sensor, but Phil might be better able to comment on it.

1 Like

@pnbruckner I want to add offsets because I have motion sensors in two rooms. One has more natural light than the other. Thatā€™s why I want to have an adjustment.

Iā€™ll try your integration. the idea is to have a motion sensor working between todayā€™s sun setting and tomorrowā€™s rising. Your integration updates ad midnight so if I make a rule like so:
now > today_sun_setting + adjustment && now < tommorow_sun_rising - adjustment
should work just fine :slight_smile: especially that yours is returning DateTime!

@Markus99 I was thinking about illuminance sensor, but I have wires in a very shaded place, so I still would have to add adjustments and I am a bit afraid of the moisture.
Right now I use Wemos with waterproof DS18B20 to measure outside temperature. Wemos is in a waterproof case, only DS18B20 is outside. I can add BH1750 but it must be put outside of the box. Wonā€™t it damage the sensor and the Wemos? How do you secure the multisensor from moisture and bad weather conditions?

I have a covered front porch and was able to find a spot, completely out of the elements (wind/rain) to mount a ZWave Zooz Multi-Sensor. Itā€™s still able to see motion at the front door and I just adjust the light levels (illiuminance) to compensate for it being under cover. FWIW, I also have an ZWave Aeotec MultiSensor 6 that I used inside the house - and both perform well. Hope this helps!

That Zooz sensor looks great, but I have no experience with ZWave, so I prefer WIFi and MQTT for now.
Iā€™m building sensors on my own (low budget), but Iā€™ll write those names down, so when I decide to give ZWave a try Iā€™ll order them. What USB Dongle do You use?

So now will always be < tomorrow_sun_rising, because now is always today. I think what youā€™re looking for is:

{% set sunset_offset = (...) * 60 %}
{% set sunrise_offset = (...) * 60 %}
{{ (now() - state_attr('sensor.sunset', 'today')).total_seconds() > sunset_offset or
   (now() - state_attr('sensor.sunrise', 'today')).total_seconds() > sunrise_offset }}

That is, now is either after sunset (and before midnight), or now is (after midnight and) before sunrise. A positive offset means after the event, and a negative offset means before the event.

Interesting. I have exactly the same setup, except I have my Zooz inside and my Aeotec outside. I bought the Zooz first and tried using that outside, but discovered it has a very limited dynamic range. It would saturate at 100 when the light level was still very low. So then I bought the Aeotec and found it works much better outside. It has a much larger dynamic range and almost never saturates, while still giving useful readings at very low light levels, too. Turns out the Zooz works pretty well for me inside. It still saturates often, but the limited dynamic range seems to be much better suited to the range of light levels inside.

Oh, and I had a similar issue with the PIR sensor. The Zooz was way too sensitive. It kept picking up cars driving by, even when I had it almost pointed at the ground, whereas the Aeotec works much better for this, too. Again, Zooz seems to work better inside and the Aeotec seems to handle the outside conditions better (although Iā€™m sure it would work well inside, too.)

I am currently using a SmartThing hub for my ZWave / Zigbee network. This isnā€™t ideally how Iā€™d like to be doing it - but I like the fact itā€™s not rebooting my ZWave network everytime HA has to reboot. Some will say this isnā€™t a big deal, so itā€™s just my personal preference I suppose.

I do also have an Aeon Labs ZWave Stick plugged into my NUC which has only a single device connected. I used this to reboot my home router when the modem <-> router loses its gigabit connection. I just havenā€™t bothered to move all my ZWve devices (30+) onto the NUC. More for lack of time, preference to not reset the ZWave network constantly than anything else - oh and I have a handful of Zigbee devices that Iā€™d have to leave on SmartThings at that + a large dose of ā€˜if it ainā€™t broke donā€™t fix itā€™.

@pnbruckner I installed my Aeotec sensor in our master bath first and have it mounted where I have a USB cable powering it to never worry about battery issues (toggles bath fan depending on humidity mostly). Found a great deal on the Zooz somewhere so bought it for kicks and ended up throwing it outside to do the front porch lights - but donā€™t do much else with it (and havenā€™t had the time to compare them - but love your thoughts on each).

@pnbruckner I know that this issue is a bit old, but somehow this does not give me peace.
Iā€™ve recently found your two PR (24912, 24810). Both add template support.
I started wondering: would it be possible to add after_offset_template and before_offset_template to sun integration. Or add support for templates in those two properties (without adding two extra properties)
What do You think?
Also maybe it would be useful to allow specifying hours, minutes and seconds in offset properties. So my automation would look like this:

 - alias: Turn on the light
   trigger:
     platform: state
     entity_id: binary_sensor.move_corridor
     to: 'on'
   condition:
    - condition: sun
      after: sunset
      after_offset:
        - minutes: "{{ states('input_number.minutes_offset')|int }}"
   action:
     - service: homeassistant.turn_on
       entity_id: switch.light_corridor

I can try implementing this (if this is even possible :stuck_out_tongue:) but Iā€™d like to know the opinion of someone who added similar functionality in other places.

I think adding template support to the before_offset and after_offset parameters of the sun condition would be reasonable and not difficult to implement. Though the problem would arise, I suspect, that people would then expect/want the same for the sun trigger, and that is more problematic.

The question becomes, why would you want to change the offsets? If it is because they need to change as the sunā€™s route changes throughout the year, then you get into the old argument that using the sunā€™s elevation (and maybe azimuth) make more sense than sunrise/sunset with variable offsets.