Blind Up by human or by sunrise

Hello,

Here one of automation for a blind where I would like into one automation regroup all usecases.
I don’t like to split automation because it’s not seem more easy to me when both are running.

Your expertise is welcome for some help to achieve this.

It’s a draft automation where I’m still searching how to solve 2 blocking points:

alias: blind up
description: Execute once a day. On morning with human motion, action blind UP
OR in case of not at home, at sunrise in autumn and winter or at 8h00 in case of summer/spring , action blind up

# TRIGGER
trigger:
# human presence
  - type: motion
    platform: device
	device_id: blabla 
    entity_id: binary_sensor.hall_sensor_motion
	domain: binary_sensor
# sunrise 
  - platform: sun
    event: sunrise 
	
# CONDITION	
condition:
# Only this automation once a day
  - condition: template
    value_template: >-
      {{
      as_timestamp(state_attr('automation.blind_up','last_triggered'))|timestamp_custom('%d')
      != as_timestamp(now())|timestamp_custom('%d') }}

#
# Human presence section, sun trigger need to avoid this section
#-> Find a solution ???

#  motion need to be in a valid schedule for action
  - condition: or
    conditions:
      - condition: time
        weekday:
          - mon
          - tue
          - wed
          - thu
          - fri
        after: '7:00'
        before: '8:45'
      - condition: time
        weekday:
          - sat
          - sun
        after: '7:30'
        before: '9:00'
# motion need to be with sun , valid schedule may be during the night in winter 
  - condition: sun
    before: sunset
    after: sunrise
#
# In case of trigger with sunrise, to be in valuable time window, sunrise at 5:00 in summer but action should be near correct morning time, sun elevation is nok for spring and summer. 
#
#-> Find a solution to activate this condition only in the sunrise trigger case ???
# and the issue with srping/summer sunrise
  - condition: state
    entity_id: group.family
    state: not_home

# ACTION
# repeat in case of issue with zigbee connection
action:
  - repeat:
      count: '3'
      sequence:
        - choose:
            - conditions:
                - condition: device
                  device_id: blabla
                  domain: cover
                  entity_id: cover.ikea_store1
                  type: is_closed
              sequence:
                - service: cover.open_cover
                  target:
                    device_id: blabla
                - delay:
                    hours: 0
                    minutes: 2
                    seconds: 30
                    milliseconds: 0
          default: []
mode: single

May be I can rephrase like this as smaller example.
Automation would work in this direction:

Trigger A
Trigger B
Condition only for Trigger A
Condition only for Trigger B
Action

See here:

Build the trigger.platform into your existing condition templates.

Thank you Troon. I already look on this page but it’s not clear to me how to achieve this.
Also in the example, there is not condition into automation but trigger and action.

How can I see in condition if Trigger A (let say Sun) is selected by automation ?

condition:
  - condition: template
    value_template: "{{ trigger.event == 'sunrise' and states('group.family') == 'not_home' }}"

Conditions are AND by default, so you’d probably want to build that into a condition: or block with the Trigger B condition.

1 Like

Thank you Troon.

oh okay, trigger domain is the response from the automation hitself.
(That’s why in dev tools / template, I was receiving: UndefinedError: 'trigger' is undefined during my test)

Indeed, I would need to construct 2 or block in condition.
Seems that you mention that is not a perfect solution.
For you, what will be the place to build a condition but not in condition ?

It’s fine in the condition block, and makes logical sense to have it there. If you wanted to do different actions, then I’d put the trigger test in the action block, but that’s not what you’re asking.

You seem to want this:

  • Trigger on motion OR sunrise
  • Conditions:
    • if triggered by motion, sun needs to be up and it needs to be early morning (your schedule)
    • If triggered by sunrise, everyone needs to be out of the house

Is that correct? If not, be super-clear on what you want to happen, and I’m sure I (or someone else) can work it out.

@Troon I will try to be super clear :slight_smile:

  • Trigger on motion OR sunrise → correct

  • Conditions:

    • if triggered by motion, sun needs to be up and it needs to be early morning (your schedule)
      → correct and this part is almost done except the trigger event to implement.

    • If triggered by sunrise, everyone needs to be out of the house → correct but some extra condition:

  1. season spring & summer, sunrise comes at 05:00 → I would prefer opening at ± 8:xx with a kind of random for minute between 0-25 if I can find a way to do this.
  2. other season : at sunrise is OK

OK, so three triggers:

  • motion
  • sunrise
  • 08:00

and corresponding conditions:

  • if triggered by motion, sun is up and schedule condition is met
  • if triggered by sunrise, it must be at or after 08:00 and everyone must be out of the house
  • if triggered by 08:00, the sun must already be up and everyone must be out of the house

and an action sequence:

  • if it is 08:00 and everyone is out, delay a random amount up to 25 mins
  • open the cover

So here we go — I’m going to implement the above conditions as a single template with a separate block for your “once a day” requirement. Obviously totally untested:

trigger:
  - platform: state
    entity_id: binary_sensor.hall_sensor_motion
    to: 'on'

  - platform: sun
    event: sunrise

  - platform: time
    at: "08:00:00"

condition:
  - condition: template
    value_template: >-
      {% if trigger.platform == 'state' %}
        {{ states('sun.sun') == 'above_horizon' and
           (( now().weekday() in [0,1,2,3,4] and 
              '07:00' <= (now().time()|string)[0:5] <= '08:45') or
            ( now().weekday() in [5,6] and 
              '07:30' <= (now().time()|string)[0:5] <= '09:00')) }}
     {% elif trigger.platform == 'sun' %}
       {{ states('group.family') == 'not_home' and now().hour >= 8 }}
     {% else %}
       {{ states('group.family') == 'not_home' and
          states('sun.sun') == 'above_horizon' }}
     {% endif %}

  - condition: template
    value_template: >-
      {{  as_timestamp(state_attr('automation.blind_up','last_triggered'))|timestamp_custom('%d') !=
          as_timestamp(now())|timestamp_custom('%d') }}

action:
  - delay: >-
      {% if trigger.platform == 'time' %}
        {{ (range(26)|random()) * 60 }}
      {% else %}
        0
      {% endif %}
  - repeat:
      count: '3'
      sequence:
        - choose:
            - conditions:
                - condition: device
                  device_id: blabla
                  domain: cover
                  entity_id: cover.ikea_store1
                  type: is_closed
              sequence:
                - service: cover.open_cover
                  target:
                    device_id: blabla
                - delay:
                    hours: 0
                    minutes: 2
                    seconds: 30
                    milliseconds: 0
          default: []
mode: single
2 Likes

@Troon

OMG, already ! It is really impressive :grinning:
Thank you so much. I’m learning a lot with your approach & solution is found.
You are on another level of expertise.

I will decompose and study. Testing will be taken soon. (For not_home, I will need to take some vacations :slight_smile: )

By far the most important step is to break the requirements down into simple logical steps. The rest is easy, but obviously helped with experience. Probably the most complex bit of my solution is:

1        {{ states('sun.sun') == 'above_horizon' and
2          (( now().weekday() in [0,1,2,3,4] and 
3              '07:00' <= (now().time()|string)[0:5] <= '08:45') or
4           ( now().weekday() in [5,6] and 
5              '07:30' <= (now().time()|string)[0:5] <= '09:00')) }}

The first line is obvious enough.

The second and fourth lines do the same job. now().weekday() returns 0 for Monday through to 6 for Sunday. The [0,1,2,3,4] is a list representing Monday to Friday, so line 2 checks if it’s Monday to Friday; line 4 checks if it’s Saturday or Sunday.

Lines 3 and 5 also do the same job. now().time() returns a time with seconds and milliseconds like 16:02:32.057620 — I just want the 16:02 bit of that, which is what the string filter then the [0:5] slice gets you. Personally, I’d use sensor.time but I don’t know if you have configured that. That time is then compared to see if it is between the start and finish times you specified — properly-formatted hh:mm time strings can be compared like that.

  - delay: >-
      {% if trigger.platform == 'time' %}
        {{ (range(26)|random()) * 60 }}
      {% else %}
        0
      {% endif %}

The range() function generates a list (docs), and the random() filter (docs) picks an item from that list. Delay is in seconds, so I multiply by 60 to get minutes.

1 Like

@Troon
Great explanation.

About this

I will configure the time sensor.

Concerning this line:
'07:00' <= (now().time()|string)[0:5] <= '08:45'

I don’t know how to interpret. Strange that string comparison is working.
I would have thought about linux epoch () numbers but it seems to work here.

See the first bullet point under “General principles”: Date and time values are ordered from the largest to smallest unit of time: year, month (or week), day, hour, minute, second, and fraction of second. The lexicographical order of the representation thus corresponds to chronological order, except for date representations involving negative years or time offset. This allows dates to be naturally sorted by, for example, file systems.

You can say that "a" is smaller than "b" — and similarly that "07:00" is smaller than "07:30".

The strings must have a consistent format though: "10:00" is bigger than "07:00" but smaller than "7:00".

image

You can use UNIX timestamps instead if you want: I find the string method gives more compact and easier-to-read templates.

1 Like

Hello Troon,

Indeed, it’s more readable than epoch.
I’m curious, from where did you find all of these informations ? I was aware that timestamp use ISO 8601 because it’s mention in sensor documentation, but in the example, it’s directly from dev tools template area and it works.

About the testing: it works perfectly this morning. At sunrise 05:40, it’s triggered but invalid as foreseen by the condition.
And at motion, it’s again triggered with valid condition timeframe. First call service to deconz don’t react but the second call was doing the job to open blind :slight_smile:
At 8:00, the condition “once a day” report as true, then exit . :slight_smile:

I’m very happy of your help on this and I see the power of integrated automation

1 Like

Amazing automation. Thank you!
Is it possible to template the automation name to use this automation within a blueprint?

I didn’t write that bit — I copied it from the first post, and that was likely not the original use either. I also have no experience with blueprints, sorry.