230 lines
9.6 KiB
YAML
230 lines
9.6 KiB
YAML
#:########################################################################################:#
|
|
# 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 }}"
|