initial commit

This commit is contained in:
root
2026-06-28 14:27:20 -04:00
commit ae0f1f559e
115 changed files with 30411 additions and 0 deletions
+315
View File
@@ -0,0 +1,315 @@
# =============================================================================
# LITTER BOX MONITORING - MQTT Sensors & Automations
# =============================================================================
# Receives analysis results from litter_box_analyzer.py via MQTT and
# exposes them as Home Assistant entities with notifications.
#
# MQTT topics (published by the Python analyzer):
# litter_box/status/cat_present -> ON/OFF
# litter_box/status/motion_detected -> ON/OFF
# litter_box/status/motion_score -> float
# litter_box/status/box_state -> open/closed/unknown
# litter_box/status/box_diff_score -> float
# litter_box/status/litter_box_stuck -> ON/OFF
# litter_box/status/needs_scooping -> ON/OFF
# litter_box/status/cleanliness_score -> 0-100
# litter_box/status/status_message -> text
# =============================================================================
# ---------------------------------------------------------------------------
# MQTT Binary Sensors
# ---------------------------------------------------------------------------
mqtt:
binary_sensor:
- name: "Litter Box - Cat Present"
unique_id: litter_box_cat_present
state_topic: "litter_box/status/cat_present"
payload_on: "ON"
payload_off: "OFF"
device_class: occupancy
icon: "mdi:cat"
- name: "Litter Box - Motion Detected"
unique_id: litter_box_motion_detected
state_topic: "litter_box/status/motion_detected"
payload_on: "ON"
payload_off: "OFF"
device_class: motion
icon: "mdi:motion-sensor"
- name: "Litter Box - Stuck Closed"
unique_id: litter_box_stuck_closed
state_topic: "litter_box/status/litter_box_stuck"
payload_on: "ON"
payload_off: "OFF"
device_class: problem
icon: "mdi:alert-circle"
- name: "Litter Box - Needs Scooping"
unique_id: litter_box_needs_scooping
state_topic: "litter_box/status/needs_scooping"
payload_on: "ON"
payload_off: "OFF"
device_class: problem
icon: "mdi:shovel"
# ---------------------------------------------------------------------------
# MQTT Numeric Sensors
# ---------------------------------------------------------------------------
sensor:
- name: "Litter Box - Motion Score"
unique_id: litter_box_motion_score
state_topic: "litter_box/status/motion_score"
unit_of_measurement: "%"
icon: "mdi:chart-bell-curve"
- name: "Litter Box - Cleanliness Score"
unique_id: litter_box_cleanliness_score
state_topic: "litter_box/status/cleanliness_score"
unit_of_measurement: "%"
icon: "mdi:star"
- name: "Litter Box - Box Diff Score"
unique_id: litter_box_box_diff_score
state_topic: "litter_box/status/box_diff_score"
icon: "mdi:compare"
# MQTT text/state sensors
- name: "Litter Box - Box State"
unique_id: litter_box_box_state
state_topic: "litter_box/status/box_state"
icon: "mdi:state-machine"
- name: "Litter Box - Status Message"
unique_id: litter_box_status_message
state_topic: "litter_box/status/status_message"
icon: "mdi:message-text"
# ---------------------------------------------------------------------------
# Helper Toggles (for notification cooldown tracking)
# ---------------------------------------------------------------------------
input_boolean:
litter_box_stuck_notified:
name: "Litter Box Stuck - Notification Sent"
icon: "mdi:bell-off"
litter_box_cat_notified:
name: "Litter Box Cat - Notification Cooldown"
icon: "mdi:cat"
litter_box_scoop_notified:
name: "Litter Box Scoop - Notification Cooldown"
icon: "mdi:shovel"
# ---------------------------------------------------------------------------
# Timers for cooldown resets
# ---------------------------------------------------------------------------
timer:
litter_box_cat_cooldown:
name: "Cat Visit Cooldown"
duration: "00:15:00"
restore: true
litter_box_scoop_cooldown:
name: "Scoop Reminder Cooldown"
duration: "04:00:00"
restore: true
# ---------------------------------------------------------------------------
# Automations
# ---------------------------------------------------------------------------
automation:
# --- Keep IR on at night so the camera can see the litter box ---
- id: litter_box_ir_on_at_sunset
alias: "Litter Box Camera - IR On At Sunset"
triggers:
- trigger: sun
event: sunset
actions:
- action: light.turn_on
target:
entity_id: light.litter_box_camera_ir_night_vision
mode: single
- id: litter_box_ir_off_at_sunrise
alias: "Litter Box Camera - IR Off At Sunrise"
triggers:
- trigger: sun
event: sunrise
actions:
- action: light.turn_off
target:
entity_id: light.litter_box_camera_ir_night_vision
mode: single
# --- Initialize ESPHome analysis entities so alerts can trigger from known off/clean states ---
- id: litter_box_initialize_analysis_status
alias: "Litter Box Camera - Initialize Analysis Status"
triggers:
- trigger: homeassistant
event: start
- trigger: time_pattern
minutes: "/30"
conditions:
- condition: template
value_template: >-
{{ states('binary_sensor.litter_box_camera_cat_present') in ['unknown', 'unavailable']
or states('binary_sensor.litter_box_camera_needs_scooping') in ['unknown', 'unavailable']
or states('binary_sensor.litter_box_camera_litter_level_low') in ['unknown', 'unavailable']
or states('sensor.litter_box_camera_cleanliness_score') in ['unknown', 'unavailable'] }}
actions:
- action: esphome.litter_box_cam_update_status
data:
cat_present: false
needs_scooping: false
litter_level_low: false
cleanliness_score: 100
mode: single
# --- Request a camera capture after IR turns on so analysis has a lit frame at night ---
- id: litter_box_capture_after_ir_on
alias: "Litter Box Camera - Capture After IR Turns On"
triggers:
- trigger: state
entity_id: light.litter_box_camera_ir_night_vision
to: "on"
actions:
- delay: "00:00:05"
- action: button.press
target:
entity_id: button.litter_box_camera_capture_now
mode: single
# --- Cat Detected Notification ---
- id: litter_box_cat_detected
alias: "Litter Box - Cat Detected Alert"
triggers:
- trigger: state
entity_id: binary_sensor.litter_box_camera_cat_present
from: "off"
to: "on"
conditions:
- condition: state
entity_id: input_boolean.litter_box_cat_notified
state: "off"
actions:
- action: input_boolean.turn_on
target:
entity_id: input_boolean.litter_box_cat_notified
- action: timer.start
target:
entity_id: timer.litter_box_cat_cooldown
- action: notify.mobile_app_joshuas_iphone_of_pain
data:
message: "🐱 A cat is using the litter box right now!"
title: "Litter Box Activity"
mode: single
# --- Reset cat notification cooldown ---
- id: litter_box_cat_cooldown_reset
alias: "Litter Box - Reset Cat Notification Cooldown"
triggers:
- trigger: event
event_type: timer.finished
event_data:
entity_id: timer.litter_box_cat_cooldown
actions:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.litter_box_cat_notified
mode: single
# --- Stuck Closed Alert (status text confirms rotated closed) ---
- id: litter_box_stuck_alert
alias: "Litter Box - Stuck Closed Alert"
initial_state: true
triggers:
- trigger: state
entity_id: sensor.litter_box_camera_status_message
conditions:
- condition: template
value_template: >-
{{ 'stuck' in states('sensor.litter_box_camera_status_message') | lower
or 'closed' in states('sensor.litter_box_camera_status_message') | lower }}
- condition: state
entity_id: input_boolean.litter_box_stuck_notified
state: "off"
actions:
- action: input_boolean.turn_on
target:
entity_id: input_boolean.litter_box_stuck_notified
- action: notify.mobile_app_joshuas_iphone_of_pain
data:
message: "⚠️ The litter box is STUCK ROTATED CLOSED! Visual state is 'closed' — check the mechanism."
title: "Litter Box STUCK CLOSED!"
- action: notify.mobile_app_pollys_iphone
data:
message: "⚠️ The litter box is STUCK ROTATED CLOSED! Visual state is 'closed' — check the mechanism."
title: "Litter Box STUCK CLOSED!"
- action: notify.mailgun_smtp
data:
message: "The litter box camera detects the box in a rotated/closed position. The mechanism may be stuck mid-cycle."
title: "Litter Box Stuck Closed!"
target: "joshua@cnjmail.com"
mode: single
# --- Reset stuck notification when status returns to normal/open ---
- id: litter_box_stuck_reset
alias: "Litter Box - Reset Stuck Notification on Open"
initial_state: true
triggers:
- trigger: state
entity_id: sensor.litter_box_camera_status_message
conditions:
- condition: template
value_template: >-
{{ states('sensor.litter_box_camera_status_message') | lower in ['ok', 'calibrated. monitoring started.', 'image sent for analysis']
or 'open' in states('sensor.litter_box_camera_status_message') | lower }}
- condition: state
entity_id: input_boolean.litter_box_stuck_notified
state: "on"
actions:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.litter_box_stuck_notified
mode: single
# --- Needs Scooping Alert ---
- id: litter_box_needs_scooping_alert
alias: "Litter Box - Needs Scooping Alert"
triggers:
- trigger: state
entity_id: binary_sensor.litter_box_camera_needs_scooping
from: "off"
to: "on"
conditions:
- condition: state
entity_id: input_boolean.litter_box_scoop_notified
state: "off"
actions:
- action: input_boolean.turn_on
target:
entity_id: input_boolean.litter_box_scoop_notified
- action: timer.start
target:
entity_id: timer.litter_box_scoop_cooldown
- action: notify.mobile_app_joshuas_iphone_of_pain
data:
message: "🧹 The litter box could use a scoop! Cleanliness: {{ states('sensor.litter_box_camera_cleanliness_score') }}%"
title: "Litter Box Needs Scooping"
mode: single
# --- Reset scoop notification cooldown ---
- id: litter_box_scoop_cooldown_reset
alias: "Litter Box - Reset Scoop Notification Cooldown"
triggers:
- trigger: event
event_type: timer.finished
event_data:
entity_id: timer.litter_box_scoop_cooldown
actions:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.litter_box_scoop_notified
mode: single