Is there a NR equivalent of the HA Automation 'calendar trigger'?

if this is the case then they are probably stored as attributes. On a day with an all day event look at the entity in devtools.

Also check the integration page to make sure that it doesn’t create additional entities.

Ya, Dev Tools only shows the all-day entry. And nothing extra in Integrations. When I added the calendar, it added a Calendar in the sidebar. I’m assuming the Automations are somehow interfacing directly with that.

If I’m correct, this seems to be the first thing that Automations can do that NR can’t (at least not without adding some new type of node).

See Calendar - Home Assistant for details on calendar automations. Don’t use the entity which has severe limitations and instead use automations.

Right, but I’m asking for an NR equivalent.

1 Like

You may consider using a template binary sensor that uses the triggers and automation to set the state.

e.g. Google Calendar allday event offset - #2 by allenporter – then you have an entity that actually has correct state.

Apologies if I’m not being clear. An all day entry overwrites the entire calendar entity for that day. That means there are no hourly events listed in the entity if there is an all day event. So its impossible to just trigger it off the calendar entity.

The Automations appear to be doing something else.

Allenporter isn’t suggesting to use the calendar entity, he’s saying tomakr an entity by using the trigger in a trigger-based template entity. The trigger based ones can use any trigger you can use in an automation (including the calendar one) and then set the state of the sensor from it’s details. So you can make entities that capture the state of particular hourly events in your calendar even when there’s an all day one and use that entity in NR or wherever.

Besides that I’m not aware of another way to trigger off events from NR. Although if you want to check for particular events at a particular time you can use the API node coupled with an inject node to do so. Call GET /api/calendars/<calendar entity_id> to get all events from a particular calendar between a start and end time and then process that data as you see fit. That’s what I used to do, I had a flow that ran every morning to find birthday/anniversary events and one that ran at night to find my first meeting in the morning and set my alarm.

But that’s the thing, there’s only a single entity to create the template off of, and during an all-day event there’s only one thing in it.

Am I not explaining this correctly, or am I missing something very basic here?

Yes you’re missing something basic. Again no one is talking about using the state of the calendar entity. Read the doc on trigger based template entities. You would make something that looks more like this:

template:
  - trigger:
      - platform: calendar
        # Possible values: start, end
        event: start
        # The calendar entity_id
        entity_id: calendar.light_schedule
        # Optional time offset
        offset: "-00:05:00"
      - platform: calendar
        event: end
        entity_id: calendar.light_schedule
    binary_sensor:
      - name: light on
        state: "{{ trigger.event == 'start'}}"

Notice how I am not looking at the actual state of the calendar entity. Instead I am using the calendar trigger to make a new entity. The entire event is available in the trigger object so capture any details you need in your flows in the state and attributes of the entity.

Oh! Now I think I see.

Create a trigger template that turns on/off some binary sensor, which NR can then watch? It’s not pretty, but yes, I think that could work.

edit: Now that I think about it, if I’m going to do that, I might as well just use Automations instead of NR for this. Oh well. :frowning:

Yes this particular task is currently easier in automations. It’s a new type of trigger so there’s not really an NR equivalent. A new node would need to be developed in the HA-NR package, just like how device and tag nodes were added after those new types of triggers were added to HA. I would recommend submitting a feature request here if you want it. It can certainly be done there’s just not really a workaround in this case.

Well other then polling the calendar API like I described above. Either at particular times or repeatedly on a schedule. I would guess that’s the closest pure NR option right now.

2 Likes

Can you not see the trigger on the event bus? Wouldn’t you be able to catch it with an events all node and switch. The way I read the Example:Calendar Event Light Schedule, it seems an event is fired. It’s specifically listening for start and end.

  action:
    - if:
        - "{{ trigger.event == 'start' }}"

I don’t think so, not in this case. The relevant bit is here I believe:

From the looks of it it seems this trigger actually polls the calendar of interest every UPDATE_INTERVAL to collect events. Then it sets itself up to trigger whatever created it when the event start/end + offset is reached. There is no firing or listening on the actual event bus in that code from what I can see.

Of course given that behavior that means it can actually be replicated pretty easily. Basically what I described above:

  1. Set up an inject node to fire every x minutes
  2. Make a call to GET /api/calendars/<calendar entity_id> to collect events in the near future
  3. Wait and trigger flows or fire events when start+offset or end+offset is reached

EDIT:

This isn’t referring to an actual event on the event bus btw. When a trigger fires in creates a trigger object capturing some of the details of the trigger. That way if an automation has multiple triggers you can determine which one went off and get to additional details about it. It’s only available in the automation though and its not necessarily from an event. Here’s what trigger has for a calendar type trigger.

1 Like

Any idea what that might look like in NR? I read through the REST API docs, which seem to suggest all I need for authorization is a long lived token used as a bearer token. I tried using the API node in NR, but the instructions are sparse. So instead I tried using the http request node, but I’m getting an unauthorized error when attempting to GET any data from the calendar entity.

Actually I just realized I still have my “Get Calendar Events” subflow. Takes a calendar ID, a start datetime and an offset to calculate end datetime from the start. There’s also an option to add an offset to the start datetime although I kind of forget why I needed that lol. Returns you all the events in that range.

There’s no polling bit right now but that can be added. If you add the inject into this subflow along with a few more options this could just become a calendar trigger node. Also the calendar input on the subflow is a select right now. I removed most of my calendars but you’ll have to add your own or make it a text box.

[{"id":"a48f1f89.a998e","type":"subflow","name":"Get calendar events","info":"","category":"","in":[{"x":60,"y":100,"wires":[{"id":"47dfe4f7.46fdd4"}]}],"out":[{"x":440,"y":100,"wires":[{"id":"54ea5735.83108","port":0}]}],"env":[{"name":"calendar","type":"str","value":"family","ui":{"icon":"font-awesome/fa-calendar","label":{"en-US":"Calendar"},"type":"select","opts":{"opts":[{"l":{"en-US":"Family"},"v":"family"},{"l":{"en-US":"Holidays"},"v":"holidays_in_united_states"},{"l":{"en-US":"HA Devs"},"v":"home_assistant_devs"}]}}},{"name":"start_add","type":"json","value":"{\"years\":0,\"quarters\":0,\"months\":0,\"weeks\":0,\"days\":0,\"hours\":0,\"minutes\":0,\"seconds\":0,\"milliseconds\":0}","ui":{"label":{"en-US":"Add for start"},"type":"input","opts":{"types":["json","env"]}}},{"name":"start_set","type":"json","value":"{\"hour\":0,\"minute\":0,\"second\":0,\"millisecond\":0}","ui":{"label":{"en-US":"Set for start"},"type":"input","opts":{"types":["json","env"]}}},{"name":"end_add","type":"json","value":"{\"hours\":0,\"minutes\":0,\"seconds\":0,\"milliseconds\":1}","ui":{"label":{"en-US":"Add for end"},"type":"input","opts":{"types":["json","env"]}}}],"meta":{},"color":"#41BDF5","icon":"font-awesome/fa-calendar","status":{"x":240,"y":180,"wires":[{"id":"79d548ec.eaa548","port":0}]}},{"id":"47dfe4f7.46fdd4","type":"change","z":"a48f1f89.a998e","name":"Set params","rules":[{"t":"set","p":"start_add","pt":"msg","to":"$exists(start_add) ? start_add : $env('start_add')","tot":"jsonata"},{"t":"set","p":"end_add","pt":"msg","to":"$exists(end_add) ? end_add : $env('end_add')","tot":"jsonata"},{"t":"set","p":"params","pt":"msg","to":"(\t    $start_add := start_add; $end_add := end_add;\t    $start := $moment().add($env('start_add')).set($env('start_set'));\t    $format := 'YYYY-MM-DDTHH:mm:ssZ';\t    {\t        \"start\": $start.format($format),\t        \"end\": $start.add($end_add).format($format)     \t    } \t)","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"calendar","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":170,"y":100,"wires":[["54ea5735.83108"]]},{"id":"54ea5735.83108","type":"ha-api","z":"a48f1f89.a998e","name":"Get events","server":"","version":1,"debugenabled":false,"protocol":"http","method":"get","path":"/calendars/calendar.{{ topic }}?start={{ params.start }}&end={{ params.end }}","data":"null","dataType":"json","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":330,"y":100,"wires":[[]]},{"id":"79d548ec.eaa548","type":"status","z":"a48f1f89.a998e","name":"","scope":null,"x":120,"y":180,"wires":[[]]}]

Oh also the reason all the date inputs are objects is because they are passed to momentjs. I set the default to the complete object with all the options so hopefully its pretty straightforward, all fields are optional though. Look here for more info on each.

1 Like

I’m not really sure I understand how to use your subflow (never used any at all), but I was able to copy/edit your API node to return calendar data, so that’s a start!

edit: After reading a little, it doesn’t seem like your subflow returns calendar data. I assume you tested this before posting it right? I’m sure I’m doing something wrong, but would just like to confirm.

Yea I’ve used it for like a year at least. I just imported what I posted and it seems to work?
Screen Shot 2022-07-25 at 5.07.44 PM

Did you change the calendar input and add your calendars like I said? It was only looking for what came after calendar. in the entity ID currently btw.

Yes, I changed it to a text box and entered my calendar name (after the ‘calendar.’ part of the entity). Weird. I’ll look at it again today.

I’ve found this thread very useful in my attempts to trigger a node-RED flow from calendars. I was using the ical sensor method but this trigger template might hold more promise now that calendars are more tightly integrated with the core.

Here is my current (experimental) template code, which defines a sensor whose state is the ‘name’ of the next calendar event, and which has attributes defining the calendar entry. The ‘start’ attribute indicates whether it’s triggered by the start - offset of the event (true) or the end of the event (false).

The id and idx attributes seem to come through as 0 for start and 1 for end. Probably some redundancy here.

template:
  - trigger:
      - platform: calendar
        event: start
        entity_id: calendar.mycal
        offset: "-00:05:00"
      - platform: calendar
        event: end
        entity_id: calendar.mycal
    sensor:
      - name: next calendar event
        state: "{{ trigger.calendar_event.summary }}"
        attributes:
          start: "{{ trigger.event == 'start' }}"
          start_time: "{{ trigger.calendar_event.start }}"
          end_time: "{{ trigger.calendar_event.end }}"
          description: "{{ trigger.calendar_event.description }}"
          location: "{{ trigger.calendar_event.location }}"
          summary: "{{ trigger.calendar_event.summary }} "
          all_day: "{{ trigger.calendar_event.all_day }}"
          id: "{{ trigger.id }}"
          idx: "{{ trigger.idx }}"

image

I use node-RED for all but the most trivial automations and this state change is easily picked up with a state_changed node. The payload is the ‘name’ of the calendar entry and the data object contains the listed attributes.

5 Likes