Can I test in ui while loop if calendar event is active?

The title shows it all. It seems, that I can test for event but if I want conditionally keep doing something until event ends, does not seem possible. If I am in while loop, there is no condition related to local calendar events.

No…
A properly formated code shows more than that title.

I am trying to use UI. So if there is no option, then tehre is no code. Sorry, forgot to mention this.

General pattern of loop while looks like this…

sequence:
  - repeat:
      while:
        - condition: state
          entity_id: calendar.ai_assistant_calendar
          state: "on"
      sequence: []

Calendar entity is on if an event is active you can also add a condition to check what the event subject etc is.

Key is don’t use devices use entity states. Devices don’t survive replacement entities do - just rename new ent to match old.

All that said you’ll still need a trigger on when same changes to start the mess and don’t so it if you expect a wait more than say a few minutes because wait doesn’t survive interrupt or restart.

So what are YOU ACTUALLY trying to do so some can help construct it.

Show as YAML, then copy that and paste it here using the </> button in the reply editor in this forum.

You have access to the same tools as are available in any action sequence. If the calendar never has overlapping events, you can use a basic State condition as Nathan showed above. Otherwise,you will need to use the calendar.get_events action inside the loop to query the calendar and then a Template condition to parse the response.

Thanks. Got it working :slight_smile:

I was too fast. The automation starts, but while loop never sees Calendar event as on, even history shows it is on. So while loop is exited directly.

If all you are doing in the loop is waiting, don’t use a loop.

Set up a second trigger for when the event ends, branch your actions using If/Then or Choose so the event starting turns on the Shelly and the event ending turns it off. If you need something a little more resilient, add a trigger for HA restart as well so the calendar is checked and the Shelly can be turned on/off.

1 Like

This is the reason why we should not help people of they do not post their code from the start.
Just ask for the code instead.
It happens over and over again, people refuse to post their code and when some still try to help out it still does not work because we do not know the scope of the asked question.

Please, stop answering if they do not post their code or do some effort to meet the list of what is a good question.

Situation is now simplified to see, if the while loop is working. In the loop there will be more actions and condition. So the problem remains, why while loop is not triggering?

And first question was that I could not find right option from ui. How I can post a code of something I do not have? I can code a bit, but want to use ui for this. I created code to create events for most expensive and cheap 15 min intervals and that works exactly like I want it to work. Now I want to use ui to utilize them.

Just do like everyone else.
Create the code in UI and switch to yaml, copy paste.
Explain what you are trying to do.
Use the FAQ as a base How to help us help you - or How to ask a good question - Configuration - Home Assistant Community

Well there is the code:

alias: WaterheatingLowNightUsedValue
description: ""
triggers:
  - trigger: calendar
    entity_id: calendar.cheap_hours
    event: start
    offset: "0:0:0"
conditions: []
actions:
  - type: turn_on
    device_id: af7121eceb8dde0303ddf54eb6fbfc8e
    entity_id: 0e342bc67057f0f029c413adb9ef5921
    domain: switch
  - repeat:
      while:
        - condition: state
          entity_id: calendar.cheap_hours
          state: "on"
      sequence:
        - delay:
            hours: 0
            minutes: 15
            seconds: 0
            milliseconds: 0
  - type: turn_off
    device_id: af7121eceb8dde0303ddf54eb6fbfc8e
    entity_id: 0e342bc67057f0f029c413adb9ef5921
    domain: switch
mode: single

Reoelvant part is this:

 - repeat:
      while:
        - condition: state
          entity_id: calendar.cheap_hours
          state: "on"

I know that event exists, but while does not trigger. From logs I can see, that wait is newer run.

Having long waiting automations are bound to not work.
They are never a good idea.

You have a calendar start event when you turn on something.
So why not just set up a calendar end event to turn off?

That means the automation won’t wait and has a much higher success rate

Because they invented payment that takes the third most expensive hour of month and you pay nicely if it is big. So I want to make sure, that my water heater is never running whole hour. I had condition if hourly consumption > x stop else heat for 15 min and check again. Could not find any other way to heat whole cheap time but keep hourly consumption under limit.

Time slot may be from 15 min 3 hours.

Download and post the debug trace so we can see what happened during the run of the automation.


Regarding the automation… I think you need to rethink the concept. There is nothing in the current automation that would “make sure, that my water heater is never running whole hour”. When working properly, the while loop would allow the heater to remain on through the whole calendar event’s time span.

You might want to consider a History Stats sensor. That can track how long the water heater has been running in the last hour.

I recreated calendar and tried to use unitl loop. It may work. Waiting until tomorrow to be sure. But this is what I am using now:

alias: WaterheatingLowNightUsedValue
description: ""
triggers:
  - trigger: calendar
    entity_id: calendar.cheap_hours
    event: start
    offset: "0:0:0"
conditions: []
actions:
  - repeat:
      until:
        - condition: state
          entity_id: calendar.cheap_hours
          state: "off"
      sequence:
        - if:
            - condition: numeric_state
              entity_id: sensor.ams_me_houruse
              below: 1.5
          then:
            - type: turn_on
              device_id: af7121eceb8dde0303ddf54eb6fbfc8e
              entity_id: 0e342bc67057f0f029c413adb9ef5921
              domain: switch
            - delay:
                hours: 0
                minutes: 15
                seconds: 0
                milliseconds: 0
          else:
            - type: turn_off
              device_id: af7121eceb8dde0303ddf54eb6fbfc8e
              entity_id: 0e342bc67057f0f029c413adb9ef5921
              domain: switch
            - delay:
                hours: 0
                minutes: 15
                seconds: 0
                milliseconds: 0
        - type: turn_off
          device_id: af7121eceb8dde0303ddf54eb6fbfc8e
          entity_id: 0e342bc67057f0f029c413adb9ef5921
          domain: switch
mode: single

It looks like it could work, but I’ll wait until tomorrow to be sure.

And If you are interested how I’ll create calendar events it here:

automation:
  - alias: "Create Calendar Events for Cheapest 15 min intervals"
    description: "Creates calendar event(s) for the cheapest 15-minute intervals (00-07 and 23-24) today from Nordpool."
    mode: single

    trigger:
      - platform: time
        at: "00:15:00"  # after Nordpool updates prices

    variables:
      entity_id: sensor.nordpool_kwh_fi_eur_2_50_0255     # <-- your Nordpool sensor
      calendar_entity: calendar.cheap_hours           # <-- your Local Calendar entity

    action:
      ########################################################
      # Build hour->price lists from raw_* attributes
      ########################################################
      - variables:
          today_price_pairs: >
            {% set ns = namespace(pairs=[]) %}
            {% set items = state_attr(entity_id, 'raw_today') or [] %}
            {% for item in items %}
              {% set h = as_datetime(item.start).hour %}
              {% if 00 <= h <= 7 or h >= 22 %}
                {# how many entries already recorded for this hour #}
                {% set count_in_h = (ns.pairs | selectattr('hour','eq',h) | list | count) %}
                {% if count_in_h < 4 %}
                  {% set m = count_in_h * 15 %}
                  {% set q = h * 4 + count_in_h %}
                  {% set ns.pairs = ns.pairs + [{'hour': h, 'minute': m, 'qidx': q, 'price': item.value}] %}
                {% endif %}
              {% endif %}
            {% endfor %}
            {{ ns.pairs }}

      ######################################################
      # Top selection (cheapest 15-minute slots)
      ######################################################
      - variables:
          top_today_pairs: >
            {% set sorted_pairs = today_price_pairs | sort(attribute='price') %}
            {{ sorted_pairs[:12] }}

      ######################################################
      # Merge consecutive 15-minute slots into ranges
      # and debug-print the ranges to the logbook
      ######################################################
      - variables:
          qidx_list: "{{ top_today_pairs | map(attribute='qidx') | list }}"
          merged_ranges: >
            {% set q = top_today_pairs | map(attribute='qidx') | list %}
            {{ symmetric_difference(q, q | map('add', 1) | list) | sort | batch(2) | list }}

      ######################################################
      # Create calendar events for each merged range
      # Also log the final start/end datetimes for verification
      ######################################################
      - repeat:
          for_each: "{{ merged_ranges }}"
          sequence:
            - variables:
                _start_q: "{{ repeat.item[0] }}"
                _end_q: "{{ repeat.item[1] }}"
                _start_h: "{{ _start_q // 4 }}"
                _start_m: "{{ (_start_q % 4) * 15 }}"
                _end_h: "{{ _end_q // 4 }}"
                _end_m: "{{ (_end_q % 4) * 15 }}"
                _end_h_adj: "{{ 23 if (_end_h | int == 24 and _end_m | int == 0) else _end_h }}"
                _end_m_adj: "{{ 59 if (_end_h | int == 24 and _end_m | int == 0) else _end_m }}"
                start_date_time: "{{ today_at('%02d:%02d' | format(_start_h | int, _start_m | int)) | as_timestamp | timestamp_local }}"
                end_date_time: "{{ today_at('%02d:%02d' | format(_end_h_adj | int, _end_m_adj | int)) | as_timestamp | timestamp_local }}"
                end_adjusted: "{{ (_end_h | int == 24 and _end_m | int == 0) }}"
                original_end_str: "{{ '%02d:%02d' | format(_end_h | int, _end_m | int) }}"

            - service: calendar.create_event
              target:
                entity_id: "{{ calendar_entity }}"
              data:
                summary: "Cheapest 15-min Intervals (Today)"
                start_date_time: "{{ start_date_time }}"
                end_date_time: "{{ end_date_time }}"

Another automation with long delay. :disappointed:
Anyway there is a good macro you can use to get the cheapest hours. Cheapest Energy Hours - Jinja macro for dynamic energy prices

You may also want to keep an eye on: