#:########################################################################################:# # Package: Pet Feeding and Jobs Timing # File: pet_feeding_and_jobs.yaml # Version: v1.4.0 # Date: 2026-07-26 # # Purpose: # Provides legacy MQTT pet activity sensors and Jobs-derived timing sensors for # the Lounge dog-feeding and depooping gauges. # v1.2.0: Added input_datetime helpers and automations so the View Road Events # home-feed-card shows correct X minutes ago after HA restart. # # Behaviour: # - Dog feeding reports the newest valid morning or evening completion time. # - Dog depooping reports the weekly Jobs completion time. # - Invalid or unrestored Jobs attributes make a timing sensor unavailable # instead of exposing a numeric sentinel value. # # Version History: # - v1.4.0 (2026-07-26): Announce four physical job completions on the Sony # lounge TV and both Pushover devices. # - v1.3.0 (2026-07-26): Restore retained dog-fed and jobs-done activity # feed publishing when physical completion events are received. # - v1.2.0 (2026-07-24): Added persistent input_datetime timestamps for # home-feed-card so time-ago survives HA restart. # - v1.1.0 (2026-07-21): Reject invalid Jobs timing attributes and remove the # 999999-hour fallback from the dog-feeding gauge source. # - v1.0.0 (2026-07-21): Added Jobs-derived dog timing sensors for P010. #:########################################################################################:# #:######################################################################################:# # LEGACY MQTT PET ACTIVITY AND TIMING SENSORS #:######################################################################################:# mqtt: sensor: - unique_id: dog_fed_activity name: "Dog Fed" state_topic: "viewroad-status/activityfeed/dogfed" icon: mdi:dog - unique_id: depooped_activity name: "DePooped" state_topic: "viewroad-status/activityfeed/depooped" icon: mdi:emoticon-poop - unique_id: jobs_done_activity name: "Jobs Done" state_topic: "viewroad-status/activityfeed/jobsdone" icon: mdi:notebook - unique_id: hours_since_jobs_done name: "Hours Since Jobs Done" state_topic: "viewroad-tele/petfeeding/hoursSinceJobsDone" unit_of_measurement: "Hours" - unique_id: hours_since_zorro_fed name: "Hours Since Zorro Fed" state_topic: "viewroad-tele/petfeeding/hoursSinceDogFed" unit_of_measurement: "Hours" - unique_id: hours_since_depooped name: "Hours Since DePooped" state_topic: "viewroad-tele/petfeeding/hoursSinceDePooped" unit_of_measurement: "Hours" #:######################################################################################:# # JOBS-DERIVED LOUNGE GAUGE SENSORS #:######################################################################################:# template: - sensor: - name: "Jobs Tracker Hours Since Dog Fed" unique_id: "jobs_tracker_hours_since_dog_fed" device_class: duration state_class: measurement unit_of_measurement: "h" icon: "mdi:dog-side" availability: >- {% set morning = state_attr('sensor.jobs_tracker_dog_feeding_morning', 'hours_since_completed') %} {% set evening = state_attr('sensor.jobs_tracker_dog_feeding_evening', 'hours_since_completed') %} {{ is_number(morning) or is_number(evening) }} state: >- {% set morning = state_attr('sensor.jobs_tracker_dog_feeding_morning', 'hours_since_completed') %} {% set evening = state_attr('sensor.jobs_tracker_dog_feeding_evening', 'hours_since_completed') %} {% if is_number(morning) and is_number(evening) %} {{ [morning | float(0), evening | float(0)] | min | round(0) }} {% elif is_number(morning) %} {{ morning | float(0) | round(0) }} {% elif is_number(evening) %} {{ evening | float(0) | round(0) }} {% else %} {{ none }} {% endif %} - name: "Jobs Tracker Hours Since Dog Depooped" unique_id: "jobs_tracker_hours_since_dog_depooped" device_class: duration state_class: measurement unit_of_measurement: "h" icon: "mdi:emoticon-poop" availability: >- {% set hours = state_attr('sensor.jobs_tracker_dog_depooping', 'hours_since_completed') %} {{ is_number(hours) }} state: >- {% set hours = state_attr('sensor.jobs_tracker_dog_depooping', 'hours_since_completed') %} {{ hours | float(0) if is_number(hours) else none }} #:######################################################################################:# # PERSISTENT EVENT TIMESTAMPS (survive HA restart) #:######################################################################################:# # These input_datetime entities store the actual wall-clock time of the most recent # event. The home-feed-card uses last_changed for "X minutes ago". # Since input_datetime state is restored from the database after restart, # last_changed reflects the actual event time, not the restart time. # input_datetime entities created via HA API (not in YAML) #:######################################################################################:# # AUTOMATIONS: Update timestamps on event #:######################################################################################:# automation: - id: timestamp_dog_fed alias: "Timestamp - Dog Fed" mode: single triggers: - trigger: state entity_id: event.jobs_dog_fed_button_x14bt_action conditions: - condition: template value_template: >- {{ trigger.to_state.state not in ['unknown', 'unavailable'] }} actions: - action: input_datetime.set_datetime target: entity_id: input_datetime.dog_last_fed data: timestamp: "{{ as_timestamp(now()) }}" - action: mqtt.publish data: topic: "viewroad-status/activityfeed/dogfed" payload: "{{ now().strftime('%H:%M') }}" qos: 0 retain: true - id: timestamp_dog_depooped alias: "Timestamp - Dog Depooped" mode: single triggers: - trigger: state entity_id: event.jobs_dog_depooped_button_x15bt_action conditions: - condition: template value_template: >- {{ trigger.to_state.state not in ['unknown', 'unavailable'] }} actions: - action: input_datetime.set_datetime target: entity_id: input_datetime.dog_last_depooped data: timestamp: "{{ as_timestamp(now()) }}" - id: timestamp_jobs_done alias: "Timestamp - Any Job Completed" description: >- Updates the jobs-done timestamp whenever any tracked job completion event fires. This keeps the "Jobs Done" entry in the home-feed-card showing the time of the most recent job completion. mode: single triggers: - trigger: state entity_id: - event.jobs_dog_fed_button_x14bt_action - event.jobs_dog_depooped_button_x15bt_action - event.kitchen_jobs_kitchen_completed_buttons_button_1 - event.kitchen_jobs_kitchen_completed_buttons_button_2 conditions: - condition: template value_template: >- {{ trigger.to_state.state not in ['unknown', 'unavailable'] }} actions: - action: input_datetime.set_datetime target: entity_id: input_datetime.last_jobs_done data: timestamp: "{{ as_timestamp(now()) }}" - action: mqtt.publish data: topic: "viewroad-status/activityfeed/jobsdone" payload: "{{ now().strftime('%-I:%M %p') }}" qos: 0 retain: true - id: jobs_completion_announcements alias: "Jobs - Completion Announcements" description: >- Announces physical dog feeding, dog depooping, dishwasher and rubbish completion events on the lounge Sony TV and both Pushover devices. mode: queued max: 10 triggers: - trigger: state entity_id: - event.jobs_dog_fed_button_x14bt_action - event.jobs_dog_depooped_button_x15bt_action - event.kitchen_jobs_kitchen_completed_buttons_button_1 - event.kitchen_jobs_kitchen_completed_buttons_button_2 conditions: - condition: template value_template: >- {% set valid_state = trigger.to_state is not none and trigger.to_state.state not in ['unknown', 'unavailable'] %} {% set event_ts = as_timestamp(trigger.to_state.state, 0) if valid_state else 0 %} {% set event_age = as_timestamp(now()) - event_ts %} {{ valid_state and event_ts > 0 and event_age >= 0 and event_age <= 30 }} actions: - variables: completion_message: >- {% if trigger.entity_id == 'event.jobs_dog_fed_button_x14bt_action' %} Zorro has been fed {% elif trigger.entity_id == 'event.jobs_dog_depooped_button_x15bt_action' %} Zorro has been depooped {% elif trigger.entity_id == 'event.kitchen_jobs_kitchen_completed_buttons_button_1' %} Dishwasher has been emptied {% elif trigger.entity_id == 'event.kitchen_jobs_kitchen_completed_buttons_button_2' %} Rubbish has been removed {% else %} Job has been completed {% endif %} - action: script.view_road_announcement data: channels: "sony_tv_lounge, pushover_zorruno, pushover_kim" title: "Jobs Announcement" short_announcement: "{{ completion_message }}" long_announcement: "{{ completion_message }}"