Improve infrastructure and health telemetry

master
Carlo Costanzo 5 days ago
parent fc7ce35e04
commit 527089babb

@ -18,6 +18,9 @@
# 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.
# Notes: WHOIS days-until-expiration countdowns stay out of Activity; actionable domain alert changes remain visible.
# Notes: Dashboard aggregate issue counts stay out of Activity; underlying degraded-state changes remain visible.
# Notes: The SQL-backed sleep-score average stays out of Activity; source scores remain available in Health.
# Notes: Duplicati result helpers stay out of Activity; curated BACKUP entries carry verification outcomes.
######################################################################
exclude:
@ -84,6 +87,7 @@ 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.infra_dashboard_active_issue_count
- sensor.hvac_condenser_lines_days_since_cleaned
- sensor.front_office_lamp_voltage
- sensor.water_softener_salt_days_since_last_add
@ -99,6 +103,8 @@ exclude:
- input_text.water_softener_salt_recent_events
- counter.water_softener_salt_event_count
- sensor.water_softener_salt_last_summary
- input_datetime.infra_duplicati_backup_last_success
- input_text.infra_duplicati_backup_verification_status
# 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
@ -330,6 +336,7 @@ exclude:
- sensor.phyn_water_flowing
- sensor.sleepnumber_carlo_carlo_pressure
- sensor.sleepnumber_carlo_stacey_pressure
- sensor.sleep_score_14_day_averages
- sensor.small_garage_reflection_rate
- sensor.small_garage_status
- sensor.small_garage_time_in_state

@ -12,8 +12,10 @@
# Notes: Hosts run daily read-only APT pending checks plus Mon/Thu 12:00 APT jobs.
# Notes: All Docker hosts use America/New_York so staggered maintenance shares one local window.
# Notes: Reboots are handled directly on each host by apt_weekly.sh.
# Notes: Boot reports reuse the registered APT webhook and retry while Home Assistant starts.
# Notes: Reboot staggering: docker_14, docker_69, docker_17, docker_10.
# Notes: Per-host action-due helpers preserve overdue state across daily checks and HA restarts.
# Notes: Monitored workload count deduplicates Portainer `_container_2` companion entities.
# Notes: Container monitoring is dynamic with binary_sensor status preferred over switch state.
# Notes: Weekly Joanna reconcile checks discovered container switches vs configured group members.
# Notes: Includes Portainer stack status repairs, 20-minute Joanna dispatch for persistent container outages, and scheduled image prune.
@ -400,7 +402,15 @@ template:
unique_id: docker_monitored_container_count
icon: mdi:format-list-numbered
state: >-
{{ state_attr('sensor.docker_monitored_switch_inventory', 'entity_id') | default([], true) | count }}
{% set ns = namespace(keys=[]) %}
{% set monitored = state_attr('sensor.docker_monitored_switch_inventory', 'entity_id') | default([], true) %}
{% for switch_entity in monitored %}
{% set key = switch_entity | replace('switch.', '') | regex_replace('_container(?:_2)?$', '') %}
{% if key not in ns.keys %}
{% set ns.keys = ns.keys + [key] %}
{% endif %}
{% endfor %}
{{ ns.keys | count }}
- name: "Docker Monitored Unavailable Count"
unique_id: docker_monitored_unavailable_count

@ -10,9 +10,11 @@
# -------------------------------------------------------------------
# Related Issue: 1584
# Notes: Home dashboard consumes `infra_*` entities for exceptions-only alerts.
# Notes: WAN outages alert immediately at near-zero throughput or 90% packet loss; performance degradation requires 6 continuous hours below 300/300 Mbps, above 80 ms, above 5% loss, or unavailable telemetry.
# Notes: Nightly Duplicati verification runs at 08:00 after the 05:30 Duplicati job and docker_14 reboot window.
# Notes: Duplicati transport/API errors are logged only; repairs are reserved for proven failed or stale backups.
# Notes: Duplicati failure Repairs enable a recovery poll that clears the Repair after a later successful run.
# Notes: Duplicati verification persists its result and latest successful backup time for the Docker storage dashboard.
# Notes: Monthly HA log hygiene review requests Telegram + public-safe GitHub issue follow-up only; Joanna must wait for approval before any changes.
# Notes: Numeric WAN telemetry exposes state_class so recorder can keep long-term statistics.
# Notes: Docker host root disk usage uses Glances-backed normalized sensors; raw Glances sensors are recorder/logbook-filtered.
@ -22,6 +24,7 @@
# Notes: Promoted IoT DNS consistency compares primary/backup Pi-hole answers for reserved IoT host records.
# Notes: Garage compute health uses the same 145 F threshold as the existing temperature notification.
# Notes: Immediate website-down states create Repairs; the installed UptimeRobot integration exposes current state, not trend rollups.
# Notes: Dashboard aggregate issue count is live-only; its underlying degraded sensors retain actionable history.
######################################################################
input_text:
@ -40,11 +43,20 @@ input_text:
infra_pihole_iot_dns_health_band:
name: "Pi-hole IoT DNS health band"
max: 20
infra_duplicati_backup_verification_status:
name: "Duplicati backup verification status"
max: 20
input_boolean:
infra_duplicati_backup_repair_active:
name: "Duplicati backup repair active"
input_datetime:
infra_duplicati_backup_last_success:
name: "Duplicati backup last success"
has_date: true
has_time: true
command_line:
- sensor:
name: Infra WAN Packet Loss
@ -193,7 +205,6 @@ template:
- name: "Infra Dashboard Active Issue Count"
unique_id: infra_dashboard_active_issue_count
icon: mdi:alert-circle-check-outline
state_class: measurement
state: >-
{% set categories = [
'binary_sensor.infra_wan_quality_degraded',
@ -215,17 +226,55 @@ template:
{{ expand(categories) | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }}
- binary_sensor:
- name: "Infra WAN Quality Degraded"
unique_id: infra_wan_quality_degraded
- name: "Infra WAN Outage"
unique_id: infra_wan_outage
device_class: problem
state: >-
{% set loss_raw = states('sensor.infra_wan_packet_loss') %}
{% set download_raw = states('sensor.speedtest_download') %}
{% set upload_raw = states('sensor.speedtest_upload') %}
{% set invalid_values = ['unknown', 'unavailable', 'none', ''] %}
{% set loss = loss_raw | float(0) %}
{% set download = download_raw | float(0) %}
{% set upload = upload_raw | float(0) %}
{{ (loss_raw not in invalid_values and loss >= 90) or
(download_raw not in invalid_values and download <= 1) or
(upload_raw not in invalid_values and upload <= 1) }}
- name: "Infra WAN Sustained Degradation"
unique_id: infra_wan_sustained_degradation
device_class: problem
delay_on: "06:00:00"
delay_off: "00:30:00"
state: >-
{% set loss_raw = states('sensor.infra_wan_packet_loss') %}
{% set lat_raw = states('sensor.infra_wan_latency_ms') %}
{% set invalid = loss_raw in ['unknown', 'unavailable', 'none', ''] or
lat_raw in ['unknown', 'unavailable', 'none', ''] %}
{% set download_raw = states('sensor.speedtest_download') %}
{% set upload_raw = states('sensor.speedtest_upload') %}
{% set invalid_values = ['unknown', 'unavailable', 'none', ''] %}
{% set invalid = loss_raw in invalid_values or
lat_raw in invalid_values or
download_raw in invalid_values or
upload_raw in invalid_values %}
{% set loss = loss_raw | float(0) %}
{% set lat = lat_raw | float(0) %}
{{ invalid or loss > 5 or lat > 80 }}
{% set download = download_raw | float(0) %}
{% set upload = upload_raw | float(0) %}
{{ invalid or loss > 5 or lat > 80 or download < 300 or upload < 300 }}
- name: "Infra WAN Quality Degraded"
unique_id: infra_wan_quality_degraded
device_class: problem
state: >-
{{ is_state('binary_sensor.infra_wan_outage', 'on') or
is_state('binary_sensor.infra_wan_sustained_degradation', 'on') }}
attributes:
evaluation_window: "6 hours"
throughput_threshold_mbps: 300
latency_threshold_ms: 80
packet_loss_threshold_percent: 5
outage_throughput_mbps: 1
outage_packet_loss_percent: 90
- name: "Infra DNS Pihole Degraded"
unique_id: infra_dns_pihole_degraded
@ -992,8 +1041,24 @@ automation:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.infra_duplicati_backup_repair_active
- service: input_text.set_value
target:
entity_id: input_text.infra_duplicati_backup_verification_status
data:
value: "verified"
- service: input_datetime.set_datetime
target:
entity_id: input_datetime.infra_duplicati_backup_last_success
data:
timestamp: >-
{{ as_timestamp(verify_last_success.get('endedAt'), as_timestamp(now())) }}
- conditions: "{{ verify_transport_issue }}"
sequence:
- service: input_text.set_value
target:
entity_id: input_text.infra_duplicati_backup_verification_status
data:
value: "unverified"
- service: script.send_to_logbook
data:
topic: "BACKUP"
@ -1002,6 +1067,11 @@ automation:
status {{ verify_status }} with issue {{ verify_issue }}. No repair card was opened because
this is verifier transport state, not a confirmed backup failure.
default:
- service: input_text.set_value
target:
entity_id: input_text.infra_duplicati_backup_verification_status
data:
value: "failed"
- service: input_boolean.turn_on
target:
entity_id: input_boolean.infra_duplicati_backup_repair_active

@ -8,6 +8,8 @@
# -------------------------------------------------------------------
# Notes: Attribute audit found native zone metadata and active-run summaries, but no durable off-state last-run/duration attributes.
# Notes: Last-run sensors are trigger-based template sensors derived from zone on->off transitions; no input_* helpers are used.
# Video: https://youtu.be/a--1iTDWhSo
# Blog: https://www.vcloudinfo.com/2026/07/home-assistant-sprinkler-automation-rachio.html
######################################################################
template:

@ -15,6 +15,8 @@
# (helpers/automations) centralized in this file.
# Notes: `group.bed` is occupancy-only so dependent automations get a clean
# on/off state from the two in-bed binary sensors.
# Notes: The SQL summary averages each day's highest non-zero score over the
# latest 14 calendar days; source SleepIQ scores remain the history.
######################################################################
homeassistant:
customize_glob:
@ -34,6 +36,47 @@ sleepiq:
username: !secret sleepiq_username
password: !secret sleepiq_password
#-------------------------------------------
sql:
- name: Sleep Score 14 Day Averages
unique_id: sleep_score_14_day_averages
icon: mdi:sleep
unit_of_measurement: score
query: >-
SELECT
ROUND(AVG(CASE
WHEN daily.entity_id = 'sensor.sleepnumber_carlo_carlo_sleep_score'
THEN daily.daily_score END), 1) AS carlo,
ROUND(AVG(CASE
WHEN daily.entity_id = 'sensor.sleepnumber_carlo_stacey_sleep_score'
THEN daily.daily_score END), 1) AS stacey,
COUNT(CASE
WHEN daily.entity_id = 'sensor.sleepnumber_carlo_carlo_sleep_score'
THEN 1 END) AS carlo_nights,
COUNT(CASE
WHEN daily.entity_id = 'sensor.sleepnumber_carlo_stacey_sleep_score'
THEN 1 END) AS stacey_nights
FROM (
SELECT
states_meta.entity_id,
DATE(FROM_UNIXTIME(states.last_updated_ts)) AS score_day,
MAX(CAST(states.state AS DECIMAL(5,2))) AS daily_score
FROM states
INNER JOIN states_meta
ON states.metadata_id = states_meta.metadata_id
WHERE states_meta.entity_id IN (
'sensor.sleepnumber_carlo_carlo_sleep_score',
'sensor.sleepnumber_carlo_stacey_sleep_score'
)
AND DATE(FROM_UNIXTIME(states.last_updated_ts)) >=
CURDATE() - INTERVAL 13 DAY
AND CAST(states.state AS DECIMAL(5,2)) > 0
GROUP BY
states_meta.entity_id,
DATE(FROM_UNIXTIME(states.last_updated_ts))
) AS daily
column: carlo
# sensor:
# - platform: history_stats
# name: Carlo_sleep_hours

@ -3,72 +3,51 @@
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Speedtest Alerts - Log internet speed drops/restores to Activity feed
# Speedtest Alerts - Log sustained WAN degradation, outages, and recovery
# Related Issue: 1550
# Uses `script.send_to_logbook` + `sensor.activity_feed`.
# Uses the normalized WAN health sensors plus `script.send_to_logbook`.
# -------------------------------------------------------------------
# Notes: Brief Speedtest transitions do not create Activity entries; outages are immediate and performance degradation requires 6 continuous hours.
######################################################################
automation:
- alias: "Internet Speed is Slow (Logbook)"
- alias: "Internet WAN Degraded (Logbook)"
id: notify-carlo-slow-internet-speed
description: "Logs an Activity entry if download or upload speed falls below 300 Mbps."
description: "Logs an Activity entry for an immediate outage or sustained WAN degradation."
trigger:
- platform: numeric_state
entity_id: sensor.speedtest_download
below: 300
- platform: numeric_state
entity_id: sensor.speedtest_upload
below: 300
condition:
- condition: state
entity_id: group.bed
state: 'off'
- condition: template # Checks to make sure the system hasn't been restarted in the past 10 minutes
value_template: >-
{% set uptime = states('sensor.ha_uptime') | as_datetime %}
{% set now = now() %}
{{ (now - uptime).total_seconds() / 60 >= 10 }}
- platform: state
entity_id: binary_sensor.infra_wan_quality_degraded
from: 'off'
to: 'on'
action:
- service: script.send_to_logbook
data:
topic: "NETWORK"
message: >-
{% set outage = is_state('binary_sensor.infra_wan_outage', 'on') %}
Download: {{ states('sensor.speedtest_download') }} Mbps,
Upload: {{ states('sensor.speedtest_upload') }} Mbps.
One or both speeds are below 300 Mbps.
upload: {{ states('sensor.speedtest_upload') }} Mbps,
latency: {{ states('sensor.infra_wan_latency_ms') }} ms,
packet loss: {{ states('sensor.infra_wan_packet_loss') }}%.
{{ 'Immediate WAN outage detected.' if outage else 'WAN performance remained degraded for 6 hours.' }}
mode: single
- alias: "Internet Speed Restored (Logbook)"
- alias: "Internet WAN Restored (Logbook)"
id: notify-carlo-internet-speed-restored
description: "Logs an Activity entry when download and upload speeds are back above 300/300 Mbps."
description: "Logs an Activity entry when the normalized WAN alert clears."
trigger:
- platform: numeric_state
entity_id: sensor.speedtest_download
above: 300
- platform: numeric_state
entity_id: sensor.speedtest_upload
above: 300
condition:
- condition: numeric_state
entity_id: sensor.speedtest_download
above: 300
- condition: numeric_state
entity_id: sensor.speedtest_upload
above: 300
- condition: template # Checks to make sure the system hasn't been restarted in the past 10 minutes
value_template: >-
{% set uptime = states('sensor.ha_uptime') | as_datetime %}
{% set now = now() %}
{{ (now - uptime).total_seconds() / 60 >= 10 }}
- platform: state
entity_id: binary_sensor.infra_wan_quality_degraded
from: 'on'
to: 'off'
action:
- service: script.send_to_logbook
data:
topic: "NETWORK"
message: >-
Download: {{ states('sensor.speedtest_download') }} Mbps,
Upload: {{ states('sensor.speedtest_upload') }} Mbps.
Internet speeds are back to normal.
Upload: {{ states('sensor.speedtest_upload') }} Mbps,
latency: {{ states('sensor.infra_wan_latency_ms') }} ms,
packet loss: {{ states('sensor.infra_wan_packet_loss') }}%.
WAN alert cleared.
mode: single

@ -7,7 +7,7 @@
# Schedule delivery date and announce night-before + day-before garage door alerts.
# -------------------------------------------------------------------
# Related Issue: 541
# Notes: Set input_datetime.water_delivery_date on /lovelace/water (date only).
# Notes: Set input_datetime.water_delivery_date on /dashboard-infrastructure/home-water (date only).
# Notes: Night-before reminder fires at 5:30 PM; garage reminders fire on door open the day before delivery.
# Notes: Clear button sets delivery date to yesterday to disable reminders.
# Notes: Date helper changes are logged to Activity feed with source context.

@ -17,6 +17,8 @@
# 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.
# Notes: WHOIS days-until-expiration countdowns are live-only; actual expiry timestamps and alert-state changes remain durable.
# Notes: Dashboard aggregate issue counts are live-only; the underlying degraded-state sensors carry useful history.
# Notes: The SQL-backed sleep-score average is live-only; direct nightly scores keep the durable history.
######################################################################
db_url: !secret recorder_db_url
purge_keep_days: 180
@ -183,6 +185,7 @@ exclude:
entities:
- automation.update_garage_get_status
- automation.docker_telemetry_template_refresh
- sensor.infra_dashboard_active_issue_count
- sensor.hvac_condenser_lines_days_since_cleaned
- sensor.front_office_lamp_voltage
- sensor.water_softener_salt_days_since_last_add
@ -424,6 +427,7 @@ exclude:
- sensor.ha_uptime
- sensor.large_garage_door_since
- sensor.small_garage_door_since
- sensor.sleep_score_14_day_averages
- sensor.last_alexa
- sensor.lights_on_count
- sensor.low_battery

Loading…
Cancel
Save

Powered by TurnKey Linux.