Improve HVAC and salt maintenance tracking

master
Carlo Costanzo 2 weeks ago
parent 959dda4717
commit 37bc1e44b7

@ -177,15 +177,28 @@
- temperature
vertical: false
features_position: bottom
- type: tile
- type: custom:mushroom-template-card
entity: climate.upstairs
show_entity_picture: false
hide_state: false
state_content:
- current_temperature
- temperature
vertical: false
features_position: bottom
primary: Upstairs
secondary: >-
{% set current = state_attr('climate.upstairs', 'current_temperature') %}
{% set target = state_attr('climate.upstairs', 'temperature') %}
{% set humidity = states('sensor.upstairs_humidity') %}
{% set current_text = ((current | float) | round(0) | int) ~ ' °F' if current is number else 'Current n/a' %}
{% set target_text = ((target | float) | round(0) | int) ~ ' °F' if target is number else 'Target n/a' %}
{% set humidity_text = ((humidity | float) | round(0) | int) ~ '% humidity' if is_number(humidity) else 'Humidity n/a' %}
{{ current_text }} · {{ target_text }} · {{ humidity_text }}
icon: mdi:thermostat
icon_color: >-
{% set mode = states('climate.upstairs') %}
{% if mode == 'cool' %}blue{% elif mode == 'heat' %}orange{% elif mode == 'off' %}grey{% else %}green{% endif %}
tap_action:
action: more-info
hold_action:
action: more-info
double_tap_action:
action: none
multiline_secondary: false
- type: custom:search-card
max_results: 10
- type: custom:mini-graph-card

@ -26,11 +26,25 @@
tap_action:
action: more-info
entity: script.reset_upstairs_filter
- type: tile
- type: custom:mushroom-template-card
primary: HVAC Condenser Lines
secondary: >-
{% set days = states('sensor.hvac_condenser_lines_days_since_cleaned') | int(0) -%}
{% set raw = states('input_datetime.hvac_condenser_lines_last_cleaned') -%}
{%- set when = as_datetime(raw).strftime('%b %d, %Y') | replace(' 0', ' ') if raw not in ['unknown', 'unavailable', 'none', ''] else 'unknown' -%}
{%- if days < 1 -%}Cleaned today{%- elif days == 1 -%}1 day since {{ when }}{%- else -%}{{ days }} days since {{ when }}{%- endif -%}
icon: mdi:calendar-clock
entity: input_datetime.hvac_condenser_lines_last_cleaned
icon_color: blue
tap_action:
action: more-info
entity: script.reset_hvac_condenser_lines_cleaned
hold_action:
action: none
double_tap_action:
action: none
layout: horizontal
fill_container: true
- type: custom:power-flow-card-plus
entities:
battery:
@ -127,4 +141,29 @@
action: none
layout: horizontal
fill_container: true
- type: custom:mushroom-template-card
primary: >-
{% set days = states('sensor.water_softener_salt_days_since_last_add') | float(0) -%}
{%- if days < 1 -%}Last refill: today{%- elif days == 1 -%}Last refill: 1 day ago{%- else -%}Last refill: {{ days | round(1) }} days ago{%- endif -%}
secondary: "{{ states('sensor.water_softener_salt_last_summary') }}"
icon: mdi:shaker
entity: sensor.water_softener_salt_days_since_last_add
icon_color: blue
tap_action:
action: navigate
navigation_path: /lovelace/salt-trends
hold_action:
action: more-info
double_tap_action:
action: none
layout: horizontal
fill_container: true
- type: tile
entity: sensor.water_softener_salt_average_days_between_refills
name: Salt typically lasts
tap_action:
action: navigate
navigation_path: /lovelace/salt-trends
hold_action:
action: more-info
- type: energy-water-graph

@ -0,0 +1,59 @@
######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Overview Subview - Salt Trends
# Year-scale water softener salt maintenance history.
# -------------------------------------------------------------------
# Notes: Linked from the Home Maintenance water view salt tiles.
# Notes: Uses native history graph cards because more-info dialogs do not expose a configurable default time window.
######################################################################
title: Salt Trends
path: salt-trends
subview: true
back_path: /lovelace/water
type: sections
max_columns: 2
sections:
- type: grid
column_span: 2
cards:
- type: heading
heading: Water Softener Salt
heading_style: title
- type: entities
title: Current Salt Maintenance
entities:
- entity: sensor.water_softener_salt_days_since_last_add
name: Days since last refill
- entity: sensor.water_softener_salt_average_days_between_refills
name: Typical duration
- entity: sensor.water_softener_salt_refill_count
name: Refills logged
- entity: sensor.water_softener_salt_total_added
name: Total salt logged
# Fallback card: native history graph is used because the more-info dialog
# does not support a configurable default history range.
- type: history-graph
title: Salt Typically Lasts - Last 365 Days
hours_to_show: 8760
entities:
- entity: sensor.water_softener_salt_average_days_between_refills
name: Days between refills
# Fallback card: same controlled yearly window for low-frequency salt events.
- type: history-graph
title: Salt Refills Logged - Last 365 Days
hours_to_show: 8760
entities:
- entity: sensor.water_softener_salt_refill_count
name: Refill count
# Fallback card: same controlled yearly window for low-frequency salt events.
- type: history-graph
title: Salt Logged Total - Last 365 Days
hours_to_show: 8760
entities:
- entity: sensor.water_softener_salt_total_added
name: Total lb
cards: []

@ -12,6 +12,9 @@
# Notes: Person/location changes and Life360 online status stay out of Activity; recorder keeps location history.
# Notes: Raw Portainer container/stack status telemetry is hidden; Docker aggregate outage sensors and curated DOCKER events remain.
# Notes: Mobile app phone telemetry stays out of Activity; phone notify services are unaffected.
# Notes: Water-softener salt helpers stay in recorder for restore/math; curated MAINTENANCE events and trend sensors are the visible signal.
# Notes: Rolling maintenance days-since sensors are live-only display helpers.
# Notes: TP-Link lamp voltage diagnostics stay out of Activity; recorder.yaml keeps them live-only.
######################################################################
exclude:
@ -78,6 +81,17 @@ exclude:
- automation.detect_lights_and_adjust_the_brightness_when_turned_on_based_on_time
- automation.docker_state_sync_repairs_dynamic
- automation.docker_telemetry_template_refresh
- sensor.hvac_condenser_lines_days_since_cleaned
- sensor.front_office_lamp_voltage
- sensor.water_softener_salt_days_since_last_add
- input_datetime.water_softener_salt_last_occurred_at
- input_number.water_softener_salt_last_amount_lb
- input_number.water_softener_salt_total_added_lb
- input_text.water_softener_salt_last_note
- input_text.water_softener_salt_recent_event_ids
- input_text.water_softener_salt_recent_events
- counter.water_softener_salt_event_count
- sensor.water_softener_salt_last_summary
# BEGIN generated Portainer recorder/logbook noise exclusions
# Portainer per-container/status plumbing is live-only; keep aggregate Docker outage sensors historically.
- binary_sensor.docker_container_alerts_snoozed

@ -7,7 +7,7 @@
# Thermostat helpers for upstairs/downstairs comfort.
# -------------------------------------------------------------------
# Related Issue: 1571, 273
# Notes: Filter due alerts use a 350h runtime threshold, 9-month hard limit, 3-day snooze, and Filter Changed push actions.
# Notes: Filter due alerts use 350h downstairs/450h upstairs runtime thresholds, a 9-month hard limit, 3-day snooze, and Filter Changed push actions.
# Notes: Condenser line cleanout uses a single 360-day reminder for both HVAC systems.
# Notes: The snooze notification pattern is also covered at https://youtu.be/y47KSflS1aw.
# Video: https://youtu.be/nScl2JxYSB8
@ -91,6 +91,21 @@ template:
- name: "Upstairs AC Cooling Numeric"
unique_id: upstairs_ac_cooling_numeric
state: "{{ 1 if is_state('binary_sensor.upstairs_ac_is_cooling', 'on') else 0 }}"
- name: "HVAC Condenser Lines Days Since Cleaned"
unique_id: hvac_condenser_lines_days_since_cleaned
unit_of_measurement: d
icon: mdi:calendar-clock
availability: >-
{% set raw = states('input_datetime.hvac_condenser_lines_last_cleaned') %}
{{ raw not in ['unknown', 'unavailable', 'none', ''] and as_timestamp(as_datetime(raw), default=none) is not none }}
state: >-
{% set raw = states('input_datetime.hvac_condenser_lines_last_cleaned') %}
{% set cleaned_ts = as_timestamp(as_datetime(raw), default=none) %}
{% if cleaned_ts is not none %}
{{ [((as_timestamp(now()) - cleaned_ts) / 86400) | int(0), 0] | max }}
{% else %}
0
{% endif %}
input_datetime:
downstairs_last_filter_change:
@ -334,7 +349,7 @@ script:
##############################################################################
automation:
- alias: Notify Climate Filter Change Due
description: Notify when HVAC filter runtime exceeds 350h or age reaches 9 months
description: Notify when HVAC filter runtime exceeds the location threshold or age reaches 9 months
trigger:
- platform: numeric_state
entity_id: sensor.downstairs_ac_runtime_since_last_filter_change
@ -345,7 +360,7 @@ automation:
id: downstairs_daily
- platform: numeric_state
entity_id: sensor.upstairs_ac_runtime_since_last_filter_change
above: 350
above: 450
id: upstairs_runtime
- platform: time
at: "09:10:00"
@ -357,15 +372,16 @@ automation:
last_filter_entity: "input_datetime.{{ location }}_last_filter_change"
snooze_entity: "input_datetime.{{ location }}_filter_snooze_until"
runtime_hours: "{{ states(runtime_sensor) | float(0) }}"
runtime_threshold_hours: "{{ 450 if location == 'upstairs' else 350 }}"
last_filter_ts: "{{ as_timestamp(states(last_filter_entity), 0) }}"
filter_age_days: "{{ ((as_timestamp(now()) - (last_filter_ts | float(0))) / 86400) | round(0) }}"
due_reason: >-
{% set runtime_due = runtime_hours | float(0) > 350 %}
{% set runtime_due = runtime_hours | float(0) > (runtime_threshold_hours | float(0)) %}
{% set age_due = (last_filter_ts | float(0)) == 0 or (filter_age_days | int(0)) >= 274 %}
{% if runtime_due and age_due %}
Runtime has exceeded 350h and the filter is {{ filter_age_days }} days old.
Runtime has exceeded {{ runtime_threshold_hours }}h and the filter is {{ filter_age_days }} days old.
{% elif runtime_due %}
Runtime has exceeded 350h.
Runtime has exceeded {{ runtime_threshold_hours }}h.
{% else %}
Filter age has reached the 9-month hard limit ({{ filter_age_days }} days).
{% endif %}
@ -373,7 +389,7 @@ automation:
- condition: template
value_template: >-
{{
(runtime_hours | float(0) > 350)
(runtime_hours | float(0) > (runtime_threshold_hours | float(0)))
or (last_filter_ts | float(0)) == 0
or (filter_age_days | int(0)) >= 274
}}

@ -8,8 +8,8 @@
# -------------------------------------------------------------------
# Notes: Webhook id is bearclaw_maintenance_log_v1 (Joanna -> HA contract).
# Notes: Duplicate event_id values are ignored to prevent double-count totals.
# Notes: Recent event history string format is "when|amount|note||...".
# Notes: Numeric refill interval sensors expose state_class for long-term trend rollups.
# Notes: Recent event history string format is "YYYY-MM-DD HH:MM:SS|amount|note||...".
# Notes: Long-term stats live on template sensors; helpers are internal state for restore/calculation.
######################################################################
input_number:
@ -65,7 +65,6 @@ template:
- name: "Water Softener Salt Days Since Last Add"
unique_id: water_softener_salt_days_since_last_add
unit_of_measurement: d
state_class: measurement
availability: >-
{% set raw = states('input_datetime.water_softener_salt_last_occurred_at') %}
{% if raw in ['unknown', 'unavailable', 'none', ''] %}
@ -107,7 +106,7 @@ template:
state: >-
{% set raw = states('input_text.water_softener_salt_recent_events') %}
{% if raw in ['unknown', 'unavailable', 'none', ''] %}
150
unknown
{% else %}
{% set entries = raw.split('||') %}
{% set ns = namespace(previous_ts=none, total_days=0, sample_count=0) %}
@ -128,10 +127,23 @@ template:
{% if ns.sample_count > 0 %}
{{ (ns.total_days / ns.sample_count) | round(1) }}
{% else %}
150
unknown
{% endif %}
{% endif %}
- name: "Water Softener Salt Refill Count"
unique_id: water_softener_salt_refill_count
icon: mdi:counter
state_class: total
state: "{{ states('counter.water_softener_salt_event_count') | int(0) }}"
- name: "Water Softener Salt Total Added"
unique_id: water_softener_salt_total_added
unit_of_measurement: lb
device_class: weight
state_class: total
state: "{{ states('input_number.water_softener_salt_total_added_lb') | float(0) | round(1) }}"
automation:
- alias: "Maintenance Log - Joanna Webhook Ingest"
id: 1c9fba4f-fef5-4da9-82d4-4049deff17cf
@ -216,7 +228,7 @@ automation:
note_value: >-
{% set text = raw_text if raw_text else 'Logged by Joanna webhook.' %}
{{ text | truncate(255, true, '') }}
recent_event_line: "{{ occurred_display }}|{{ effective_amount_lb | round(1) }} lb|{{ note_value }}"
recent_event_line: "{{ occurred_local_datetime }}|{{ effective_amount_lb | round(1) }} lb|{{ note_value }}"
next_recent_events: >-
{% set current = (states('input_text.water_softener_salt_recent_events')
| default('', true) | string).split('||') %}

@ -12,6 +12,8 @@
# Notes: Life360 trackers are explicitly included for map/history queries despite the broad device_tracker exclusion.
# Notes: Raw Portainer container/stack status telemetry is live-only; keep Docker aggregate outage sensors, Repairs, and curated logbook events instead.
# Notes: Mobile app phone telemetry is live-only; Life360 keeps location history and notify services remain available.
# Notes: Rolling maintenance days-since sensors are live-only; durable interval/count/total sensors carry the history.
# Notes: TP-Link lamp voltage diagnostics are live-only; useful energy/power sensors stay recorded.
######################################################################
db_url: !secret recorder_db_url
purge_keep_days: 180
@ -169,6 +171,9 @@ exclude:
entities:
- automation.update_garage_get_status
- automation.docker_telemetry_template_refresh
- sensor.hvac_condenser_lines_days_since_cleaned
- sensor.front_office_lamp_voltage
- sensor.water_softener_salt_days_since_last_add
# BEGIN generated Portainer recorder/logbook noise exclusions
# Portainer per-container/status plumbing is live-only; keep aggregate Docker outage sensors historically.
- binary_sensor.docker_container_alerts_snoozed

Loading…
Cancel
Save

Powered by TurnKey Linux.