Templating a sensor to see if my partner will be home for dinner this week

Hi everyone! I always have issues with templating in Home Assistant so I thought I would check with the community to see if this was possible. I have my google calendars populating in Home assistant, and I want to know each day, if there is an entry in a specific calendar between 5pm and 6pm. Can this be done done via the template feature?

EDIT: I was able to partially get this working, but I understand this correctly, this will only tell me if the next calendar entry takes place during 5pm.

  - platform: template
    sensors:
      partner_availability:
        friendly_name: "Partner Availability"
        value_template: >-
          {% if states.calendar.work.attributes.start_time %}
            {% set start_time = as_timestamp(states.calendar.work.attributes.start_time) %}
            {% set end_time = as_timestamp(states.calendar.work.attributes.end_time) %}
            {% if start_time <= today_at().timestamp() + (60 * 60 * 17) <= end_time %}
             Not Available
            {% else %}
              Available
            {% endif %}
          {% else %}
            Available
          {% endif %}

That’s mostly correct. However, if the calendar has overlapping events (including all-day events) it will be unreliable using state-based templates.

Switch to the current template sensor configuration method to take advantage of the trigger-based sensor ability. The offset of the Calendar trigger will set the lead time you get, so you may want to set a couple similar triggers with different offsets to cover situations where your partner adds events closer to 5pm.

template:
  - trigger:
    automation:
  trigger:
    - platform: calendar
      event: start
      entity_id: calendar.work
      offset: "-06:00:00"
    - platform: calendar
      event: start
      entity_id: calendar.work
      offset: "-01:00:00"
    sensor:
      - name: Partner Availability
        state: >
          {% set start = trigger.calendar_event.start | as_datetime %}
          {% set end = trigger.calendar_event.end | as_datetime %}
          {{ 'Not Available' if (start <= today_at('17:00') <= end) else 'Available' }}

Thanks @Didgeridrew, I wasn’t able to get this working quite how I wanted in Homeassistant as a template sensor, but I was able to get it working in Node-Red so I thought I would share it in-case someone else wants to know how I solved it.

[{"id":"fc9674ca9474fa8b","type":"tab","label":"Dinner Avaliability","disabled":false,"info":"","env":[]},{"id":"900a5190cb211baa","type":"ical-upcoming","z":"fc9674ca9474fa8b","confignode":"a16f6a40e0f07d2a","timeout":"8","timeoutUnits":"hours","cron":"","name":"","offsettype":"","offset":"","offsetUnitstype":"","offsetUnits":"","eventtypes":"events","eventtypestype":"eventtypes","calendar":"","calendartype":"str","triggertype":"trigger","trigger":"always","timezone":"america/halifax","timezonetype":"str","dateformat":"{ \"timeStyle\": \"short\", \"dateStyle\": \"short\" }","dateformattype":"json","language":"en","languagetype":"language","filterProperty":"summary","filterPropertytype":"filterProperty","filterOperator":"between","filterOperatortype":"filterOperator","filtertype":"str","filter2type":"str","filter2":"","filter":"","checkall":false,"endpreview":"","endpreviewUnits":"","previewtype":"num","preview":"6","previewUnitstype":"previewUnits","previewUnits":"days","pastviewtype":"num","pastview":"1","pastviewUnits":"days","pastviewUnitstype":"pastviewUnits","x":210,"y":420,"wires":[["b6b0281249b850e9"]]},{"id":"30e599fad31db760","type":"ha-binary-sensor","z":"fc9674ca9474fa8b","name":"","entityConfig":"8994804a1c05733e","version":0,"state":"payload","stateType":"msg","attributes":[{"property":"Busy_this_week","value":"days","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":760,"y":420,"wires":[[]]},{"id":"b6b0281249b850e9","type":"function","z":"fc9674ca9474fa8b","name":"Check calendar for dinner avalibility","func":"const dinnerStart = \"17:15:00\";\nconst dinnerEnd = \"17:45:00\";\nconst daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\nlet daysAway = new Set();\nlet today = new Date();\nlet todayDinnerStart = new Date(`${today.toISOString().split(\"T\")[0]}T${dinnerStart}`);\nlet todayDinnerEnd = new Date(`${today.toISOString().split(\"T\")[0]}T${dinnerEnd}`);\nlet homeForDinnerToday = true;\n\nmsg.payload.forEach(event => {\n    let eventStart = new Date(event.eventStart);\n    let eventEnd = new Date(event.eventEnd);\n\n    if ((eventStart <= todayDinnerStart && eventEnd >= todayDinnerStart) ||\n        (eventStart >= todayDinnerStart && eventStart <= todayDinnerEnd)) {\n        homeForDinnerToday = false;\n    }\n\n    let currentEventDay = new Date(eventStart);\n    while (currentEventDay <= eventEnd) {\n        let currentEventDayDinnerStart = new Date(`${currentEventDay.toISOString().split(\"T\")[0]}T${dinnerStart}`);\n        let currentEventDayDinnerEnd = new Date(`${currentEventDay.toISOString().split(\"T\")[0]}T${dinnerEnd}`);\n\n        if ((eventStart <= currentEventDayDinnerStart && eventEnd >= currentEventDayDinnerStart) ||\n            (eventStart >= currentEventDayDinnerStart && eventStart <= currentEventDayDinnerEnd)) {\n            let day = daysOfWeek[currentEventDay.getDay()];\n            daysAway.add(day);\n        }\n        currentEventDay.setDate(currentEventDay.getDate() + 1);\n    }\n});\n\nmsg.days = Array.from(daysAway);\nmsg.payload = homeForDinnerToday ? \"on\" : \"off\";\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":420,"wires":[["30e599fad31db760"]]},{"id":"a16f6a40e0f07d2a","type":"ical-config","url":"https://calendar.google.com/calendar/ical/77bd7411371cba2a1ce932bf1a4899f97194e5bcd5a5810de5762b53913a0aed%40group.calendar.google.com/private-1356a10c80823848bbc0bc8c20861eed/basic.ics","caldav":"","caltype":"ical","name":"Ryan Work","replacedates":false,"usecache":false,"username":"","password":"","calendar":"","pastWeeks":"0","futureWeeks":"4"},{"id":"8994804a1c05733e","type":"ha-entity-config","server":"3ac99007.0ca72","deviceConfig":"","name":"Ryan is here for dinner","version":"6","entityType":"binary_sensor","haConfig":[{"property":"name","value":"Ryan4Dinner"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":"occupancy"}],"resend":true,"debugEnabled":false},{"id":"3ac99007.0ca72","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Once this is configured it will create a binary sensor that is off, if the person has an entry in their calendar that will put them away during dinner time and then it will also have an attribute “days” that will indicate which of the next 7 days the person will miss dinner.