Expand infrastructure telemetry dashboards

master
Carlo Costanzo 2 weeks ago
parent 6958370042
commit 8414b62809

@ -8,6 +8,7 @@
# -------------------------------------------------------------------
# Notes: Stable dashboard key/path remains `dashboard-infrastructure`; the user-facing name is Systems.
# Notes: Water, HVAC, and Vacuum are promoted production views; Health remains on Overview.
# Notes: Car combines live Tesla, tire-pressure, odometer, and read-only JuiceBox telemetry.
# Notes: Joanna dispatch telemetry view is available at `/dashboard-infrastructure/joanna`.
# Notes: Network combines WAN, dual Pi-hole, and website health; `/wan`, `/pihole`, and `/website-health` are detail subviews.
######################################################################

@ -0,0 +1,476 @@
######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Systems Partial - Car
# Read-only vehicle, tire, odometer, and JuiceBox charging summary.
# -------------------------------------------------------------------
# Related Issue: 1944
# Notes: No cards expose Tesla or JuiceBox controls.
# Notes: TeslaMate retains detailed drive, charge, and mileage history.
# Notes: Useful tiles use restored last-valid values without timestamp churn.
# Notes: Raw JuiceBox energy retains long-term history; power is session-only.
# Notes: The Tesla's Home location charge-current setting is intentionally 16 A.
# Notes: JuicePassProxy shows OFFLINE immediately and becomes a Systems fault
# after five continuous minutes; neither dashboard exposes writable controls.
######################################################################
# -------------------------------------------------------------------
# Vehicle health strip (mandatory first full-width wrapper)
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(6, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(2, minmax(0, 1fr))
cards:
- type: custom:button-card
template: bearstone_nav_back
name: Back to Systems
icon: mdi:arrow-left
view_layout:
grid-column: 1 / -1
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/home
- type: custom:button-card
template: bearstone_infra_kpi
entity: sensor.car_battery_last_known
name: Battery
icon: mdi:car-electric
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_kpi
entity: sensor.car_odometer_last_known
name: Odometer
icon: mdi:counter
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value)
? `${value.toLocaleString(undefined, {maximumFractionDigits: 0})} mi`
: 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_kpi
entity: sensor.car_charging_last_known
name: Charging
icon: mdi:ev-station
state_display: >
[[[
const raw = String(entity?.state ?? '').toUpperCase();
if (['UNKNOWN', 'UNAVAILABLE', ''].includes(raw)) return 'NO DATA';
const live = String(states['sensor.spaceship_charging']?.state ?? '').toLowerCase();
const prefix = ['unknown', 'unavailable', ''].includes(live) ? 'LAST ' : '';
return `${prefix}${raw}`;
]]]
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: sensor.car_tire_pressure_front_left_last_known
name: Tires
icon: mdi:car-tire-alert
variables:
status_severity: >
[[[
const ids = [
'sensor.car_tire_pressure_front_left_last_known',
'sensor.car_tire_pressure_front_right_last_known',
'sensor.car_tire_pressure_rear_left_last_known',
'sensor.car_tire_pressure_rear_right_last_known'
];
const values = ids.map((id) => Number(states[id]?.state)).filter(Number.isFinite);
if (values.length !== ids.length) return 'unknown';
return Math.min(...values) < 40 ? 'critical' : 'healthy';
]]]
state_display: >
[[[
const ids = [
'sensor.car_tire_pressure_front_left_last_known',
'sensor.car_tire_pressure_front_right_last_known',
'sensor.car_tire_pressure_rear_left_last_known',
'sensor.car_tire_pressure_rear_right_last_known'
];
const values = ids.map((id) => Number(states[id]?.state)).filter(Number.isFinite);
if (values.length !== ids.length) return 'NO DATA';
const minimum = Math.min(...values);
return `${minimum < 40 ? 'LOW' : 'MIN'} ${minimum.toFixed(1)} psi`;
]]]
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: sensor.juicebox_status_last_known
name: JuiceBox
icon: mdi:ev-plug-type1
variables:
status_severity: >
[[[
const raw = String(entity?.state ?? '').toLowerCase();
return ['unknown', 'unavailable', 'none', ''].includes(raw) ? 'unknown' : 'healthy';
]]]
state_display: >
[[[
const raw = String(entity?.state ?? '').toUpperCase();
if (['UNKNOWN', 'UNAVAILABLE', 'NONE', ''].includes(raw)) return 'WAITING';
const live = String(states['sensor.juicebox_status']?.state ?? '').toLowerCase();
const prefix = ['unknown', 'unavailable', 'none', ''].includes(live) ? 'LAST ' : '';
return `${prefix}${raw}`;
]]]
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: sensor.juicepassproxy_state
name: Proxy
icon: mdi:shield-check
variables:
status_severity: >
[[[
if (states['binary_sensor.juicepassproxy_monitoring_degraded']?.state === 'on') return 'critical';
const running = String(entity?.state ?? '').toLowerCase() === 'running';
const healthy = String(states['sensor.juicepassproxy_health']?.state ?? '').toLowerCase() === 'healthy';
return running && healthy ? 'healthy' : 'warning';
]]]
state_display: >
[[[
const running = String(entity?.state ?? '').toLowerCase() === 'running';
const healthy = String(states['sensor.juicepassproxy_health']?.state ?? '').toLowerCase() === 'healthy';
return running && healthy ? 'ONLINE' : 'OFFLINE';
]]]
# -------------------------------------------------------------------
# Current vehicle, tires, and charging telemetry
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(3, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(1, minmax(0, 1fr))
cards:
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Spaceship
icon: mdi:car-electric
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_location_last_known
name: Location
icon: mdi:map-marker
state_display: >
[[[ return String(entity?.state ?? 'NO DATA').replaceAll('_', ' ').toUpperCase(); ]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_battery_last_known
name: Battery
icon: mdi:battery-high
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_odometer_last_known
name: Odometer
icon: mdi:counter
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value)
? `${value.toLocaleString(undefined, {maximumFractionDigits: 0})} mi`
: 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_charge_cable_last_known
name: Charge Cable
icon: mdi:ev-plug-type1
state_display: >
[[[
const raw = String(entity?.state ?? '').toLowerCase();
if (['unknown', 'unavailable', ''].includes(raw)) return 'NO DATA';
return raw === 'on' ? 'CONNECTED' : 'DISCONNECTED';
]]]
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Tire Pressure
icon: mdi:car-tire-alert
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_tire_pressure_front_left_last_known
name: Front Left
icon: mdi:circle-double
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(1)} psi` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_tire_pressure_front_right_last_known
name: Front Right
icon: mdi:circle-double
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(1)} psi` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_tire_pressure_rear_left_last_known
name: Rear Left
icon: mdi:circle-double
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(1)} psi` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.car_tire_pressure_rear_right_last_known
name: Rear Right
icon: mdi:circle-double
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(1)} psi` : 'NO DATA';
]]]
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Charging Session
icon: mdi:battery-charging-high
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_session_energy_last_known
name: JuiceBox Session
icon: mdi:counter
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${(value / 1000).toFixed(2)} kWh` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_power_last_known
name: JuiceBox Power
icon: mdi:flash
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${(value / 1000).toFixed(1)} kW` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_current_last_known
name: JuiceBox Current
icon: mdi:current-ac
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(1)} A` : 'NO DATA';
]]]
# -------------------------------------------------------------------
# JuiceBox electrical detail
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(2, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(1, minmax(0, 1fr))
cards:
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: JuiceBox Electrical
icon: mdi:ev-station
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_voltage_last_known
name: Voltage
icon: mdi:sine-wave
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_frequency_last_known
name: Frequency
icon: mdi:waveform
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_power_factor_last_known
name: Power Factor
icon: mdi:chart-bell-curve-cumulative
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_temperature_last_known
name: Temperature
icon: mdi:thermometer
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: JuiceBox Capacity
icon: mdi:gauge
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_current_rating_last_known
name: Hardware Rating
icon: mdi:current-ac
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_current_rating_last_known
name: Stored Circuit Limit
icon: mdi:shield-check
state_display: 24 A
tap_action:
action: none
hold_action:
action: none
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_lifetime_energy_last_known
name: Lifetime Energy
icon: mdi:transmission-tower-export
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${(value / 1000).toFixed(1)} kWh` : 'NO DATA';
]]]
# -------------------------------------------------------------------
# Charging trends
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: minmax(0, 1fr)
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
cards:
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Energy Delivered - 30 Days
icon: mdi:chart-bar
- type: conditional
conditions:
- entity: sensor.juicebox_energy_lifetime
state_not: unavailable
card:
type: statistics-graph
chart_type: bar
days_to_show: 30
period: day
stat_types:
- change
entities:
- entity: sensor.juicebox_energy_lifetime
name: JuiceBox Energy
- type: conditional
conditions:
- entity: sensor.juicebox_energy_lifetime
state: unavailable
card:
type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.juicebox_status
name: Energy history starts with first report
icon: mdi:chart-timeline-variant-shimmer
state_display: PENDING

@ -6,7 +6,7 @@
# Systems Partial - operations summary
# House-system health strip, active issues, and datacenter status.
# -------------------------------------------------------------------
# Related Issue: 1890, 1817
# Related Issue: 1890, 1817, 1944
# Notes: The health ribbon mirrors the visible dashboard navigation order and labels.
# Notes: DNS and external-monitoring faults roll up under Network instead of duplicating it.
# Notes: Network trend panels live on Network so Overview stays focused on broad house status.
@ -16,6 +16,9 @@
# Notes: BearClaw scheduled-job warnings/errors roll up under Joanna and appear as an exceptions-only Active Issue row.
# Notes: Water and Systems surface normalized Rheem faults; telemetry-only loss renders amber.
# Notes: Back to Overview is the first control in the landing-view navigation strip.
# Notes: UPS health covers both Garage and Office NUT servers and drills into the shared UPS view.
# Notes: A JuicePassProxy outage becomes a critical Systems issue after five
# continuous minutes and drills into the Car view.
######################################################################
# -------------------------------------------------------------------
@ -74,9 +77,11 @@
critical_entity_ids:
- binary_sensor.infra_wan_critical
- binary_sensor.infra_dns_pihole_degraded
- binary_sensor.infra_ups_on_battery
- binary_sensor.infra_compute_degraded
- binary_sensor.infra_storage_degraded
- binary_sensor.infra_external_monitoring_degraded
- binary_sensor.juicepassproxy_monitoring_degraded
- binary_sensor.rheem_wh_active_alert
- binary_sensor.garage_phyn_leak_alert
@ -126,6 +131,37 @@
action: navigate
navigation_path: /dashboard-infrastructure/vacuum
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: sensor.car_battery_last_known
name: Car
icon: mdi:car-electric
variables:
status_severity: >
[[[
const tireIds = [
'sensor.car_tire_pressure_front_left_last_known',
'sensor.car_tire_pressure_front_right_last_known',
'sensor.car_tire_pressure_rear_left_last_known',
'sensor.car_tire_pressure_rear_right_last_known'
];
const battery = Number(entity?.state);
const tires = tireIds.map((id) => Number(states[id]?.state)).filter(Number.isFinite);
if (states['binary_sensor.juicepassproxy_monitoring_degraded']?.state === 'on') return 'critical';
if (!Number.isFinite(battery) || tires.length !== tireIds.length) return 'unknown';
return Math.min(...tires) < 40 ? 'critical' : 'healthy';
]]]
state_display: >
[[[
if (states['binary_sensor.juicepassproxy_monitoring_degraded']?.state === 'on') return 'PROXY OFFLINE';
const battery = Number(entity?.state);
if (!Number.isFinite(battery)) return 'NO DATA';
return `${battery.toFixed(0)}%`;
]]]
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/car
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: binary_sensor.infra_compute_degraded
@ -175,6 +211,19 @@
action: navigate
navigation_path: /dashboard-infrastructure/network
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: binary_sensor.infra_ups_on_battery
name: UPS Power
icon: mdi:battery-heart-variant
variables:
ok_state: 'off'
healthy_text: UTILITY POWER
alert_text: ON BATTERY
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/ups
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: binary_sensor.powerwall_status
@ -326,6 +375,24 @@
action: navigate
navigation_path: /dashboard-infrastructure/network
- type: custom:button-card
template: bearstone_infra_alert_row
entity: binary_sensor.infra_ups_on_battery
name: UPS running on battery
icon: mdi:battery-alert-variant-outline
variables:
alert_kind: binary_on
exception_detail: >
[[[
const garage = String(entity?.attributes?.garage_status ?? 'UNKNOWN').toUpperCase();
const office = String(entity?.attributes?.office_status ?? 'UNKNOWN').toUpperCase();
return `GARAGE ${garage} · OFFICE ${office}`;
]]]
state_display: ON BATTERY
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/ups
- type: custom:button-card
template: bearstone_infra_alert_row
entity: binary_sensor.garage_phyn_leak_alert
@ -454,6 +521,19 @@
action: navigate
navigation_path: /dashboard-infrastructure/joanna
- type: custom:button-card
template: bearstone_infra_alert_row
entity: binary_sensor.juicepassproxy_monitoring_degraded
name: JuiceBox charging monitor offline
icon: mdi:ev-station-off
variables:
alert_kind: binary_on
exception_detail: DO NOT CHARGE - CHECK OR UNPLUG THE TESLA
state_display: '[[[ return "OFFLINE"; ]]]'
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/car
- type: custom:button-card
template: bearstone_infra_alert_row
entity: binary_sensor.proxmox1_runtime_healthy
@ -710,46 +790,38 @@
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml
- type: custom:button-card
template: bearstone_infra_list_row_running
template: bearstone_infra_list_row
entity: sensor.garage_ups_status
name: UPS Status
name: Garage UPS
icon: mdi:battery-heart-variant
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_battery_charge
name: UPS Battery
icon: mdi:battery-70
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_battery_runtime
name: Runtime Remaining
icon: mdi:timer-outline
state_display: >
[[[
const seconds = Number(entity?.state);
if (!Number.isFinite(seconds)) return 'NO DATA';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
const charge = Number(states['sensor.garage_ups_battery_charge']?.state);
const seconds = Number(states['sensor.garage_ups_battery_runtime']?.state);
const battery = Number.isFinite(charge) ? `${charge.toFixed(0)}%` : 'NO BATTERY DATA';
const runtime = Number.isFinite(seconds) ? `${Math.floor(seconds / 60)}m` : 'NO RUNTIME';
return `${String(entity?.state ?? 'NO DATA').toUpperCase()} · ${battery} · ${runtime}`;
]]]
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/ups
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_status
name: On Battery
icon: mdi:battery-alert-variant-outline
entity: sensor.office_ups_eaton_550_status
name: Office Eaton 3S 550
icon: mdi:battery-heart-variant
state_display: >
[[[
const status = String(entity?.state ?? '').toUpperCase();
return status ? (status.includes('OB') ? 'YES' : 'NO') : 'NO DATA';
const charge = Number(states['sensor.office_ups_eaton_550_battery_charge']?.state);
const seconds = Number(states['sensor.office_ups_eaton_550_battery_runtime']?.state);
const battery = Number.isFinite(charge) ? `${charge.toFixed(0)}%` : 'NO BATTERY DATA';
const runtime = Number.isFinite(seconds) ? `${Math.floor(seconds / 60)}m` : 'NO RUNTIME';
return `${String(entity?.state ?? 'NO DATA').toUpperCase()} · ${battery} · ${runtime}`;
]]]
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/ups
- type: custom:vertical-stack-in-card
card_mod:

@ -0,0 +1,457 @@
######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Infrastructure Partial - UPS Power
# Garage and Office NUT status with current readings and trends.
# -------------------------------------------------------------------
# Notes: Raw NUT status data drives the shared on-battery rollup.
# Notes: All graphs use 24-hour windows and explicit threshold colors.
######################################################################
# -------------------------------------------------------------------
# Current UPS health (mandatory first full-width wrapper)
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(3, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(1, minmax(0, 1fr))
cards:
- type: custom:button-card
template: bearstone_nav_back
name: Back to Systems
icon: mdi:arrow-left
view_layout:
grid-column: 1 / -1
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/home
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: sensor.garage_ups_status
name: Garage UPS
icon: mdi:garage-variant
variables:
ok_state: Online
healthy_text: ONLINE
alert_text: CHECK
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: sensor.office_ups_eaton_550_status
name: Office Eaton 3S 550
icon: mdi:desk
variables:
ok_state: Online
healthy_text: ONLINE
alert_text: CHECK
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: binary_sensor.infra_ups_on_battery
name: Utility State
icon: mdi:transmission-tower
variables:
ok_state: 'off'
healthy_text: UTILITY POWER
alert_text: ON BATTERY
# -------------------------------------------------------------------
# Current readings
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(2, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(1, minmax(0, 1fr))
cards:
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Garage UPS
icon: mdi:garage-variant
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_status
name: Status
icon: mdi:battery-heart-variant
state_display: >
[[[ return String(entity?.state ?? 'NO DATA').toUpperCase(); ]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_battery_charge
name: Battery
icon: mdi:battery-high
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_battery_runtime
name: Runtime
icon: mdi:timer-outline
state_display: >
[[[
const seconds = Number(entity?.state);
if (!Number.isFinite(seconds)) return 'NO DATA';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_load
name: Load
icon: mdi:gauge
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_input_voltage
name: Input Voltage
icon: mdi:sine-wave
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)} V` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.garage_ups_output_voltage
name: Output Voltage
icon: mdi:flash-outline
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)} V` : 'NO DATA';
]]]
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Office Eaton 3S 550
icon: mdi:desk
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.office_ups_eaton_550_status
name: Status
icon: mdi:battery-heart-variant
state_display: >
[[[ return String(entity?.state ?? 'NO DATA').toUpperCase(); ]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.office_ups_eaton_550_battery_charge
name: Battery
icon: mdi:battery-high
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.office_ups_eaton_550_battery_runtime
name: Runtime
icon: mdi:timer-outline
state_display: >
[[[
const seconds = Number(entity?.state);
if (!Number.isFinite(seconds)) return 'NO DATA';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.office_ups_eaton_550_load
name: Load
icon: mdi:gauge
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)}%` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.office_ups_eaton_550_real_power
name: Real Power
icon: mdi:flash
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)} W` : 'NO DATA';
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.office_ups_eaton_550_output_voltage
name: Output Voltage
icon: mdi:flash-outline
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${value.toFixed(0)} V` : 'NO DATA';
]]]
# -------------------------------------------------------------------
# Battery and load trends
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(4, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(2, minmax(0, 1fr))
cards:
- type: custom:mini-graph-card
name: Garage Battery
icon: mdi:battery-high
hours_to_show: 24
points_per_hour: 2
line_width: 2
smoothing: true
height: 80
show:
legend: false
labels: false
name: true
icon: true
state: true
color_thresholds:
- value: 0
color: '#c0392b'
- value: 20
color: '#f39c12'
- value: 50
color: '#43a047'
entities:
- entity: sensor.garage_ups_battery_charge
name: Battery
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml
- type: custom:mini-graph-card
name: Office Battery
icon: mdi:battery-high
hours_to_show: 24
points_per_hour: 2
line_width: 2
smoothing: true
height: 80
show:
legend: false
labels: false
name: true
icon: true
state: true
color_thresholds:
- value: 0
color: '#c0392b'
- value: 20
color: '#f39c12'
- value: 50
color: '#43a047'
entities:
- entity: sensor.office_ups_eaton_550_battery_charge
name: Battery
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml
- type: custom:mini-graph-card
name: Garage Load
icon: mdi:gauge
hours_to_show: 24
points_per_hour: 2
line_width: 2
smoothing: true
height: 80
show:
legend: false
labels: false
name: true
icon: true
state: true
color_thresholds:
- value: 0
color: '#43a047'
- value: 60
color: '#f39c12'
- value: 85
color: '#c0392b'
entities:
- entity: sensor.garage_ups_load
name: Load
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml
- type: custom:mini-graph-card
name: Office Load
icon: mdi:gauge
hours_to_show: 24
points_per_hour: 2
line_width: 2
smoothing: true
height: 80
show:
legend: false
labels: false
name: true
icon: true
state: true
color_thresholds:
- value: 0
color: '#43a047'
- value: 60
color: '#f39c12'
- value: 85
color: '#c0392b'
entities:
- entity: sensor.office_ups_eaton_550_load
name: Load
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml
# -------------------------------------------------------------------
# Home Assistant power resilience dry run
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(1, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
cards:
- type: custom:vertical-stack-in-card
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
cards:
- type: custom:button-card
template: bearstone_infra_panel_header_icon
name: Power Resilience - Home Assistant
icon: mdi:home-assistant
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.power_resilience_recommended_stage
name: Recommended Stage
icon: mdi:signal
state_display: >
[[[ return String(entity?.state ?? 'NO DATA').replaceAll('_', ' '); ]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.power_resilience_recommended_stage
name: Control Owner
icon: mdi:brain
state_display: >
[[[
const owner = String(entity?.attributes?.control_owner ?? 'NO DATA');
const mode = String(entity?.attributes?.execution_mode ?? 'NO DATA');
return `${owner.toUpperCase()} / ${mode.replaceAll('_', ' ').toUpperCase()}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.power_resilience_recommended_stage
name: Safety State
icon: mdi:shield-lock-outline
state_display: >
[[[ return entity?.attributes?.actions_armed === true ? 'ACTIONS ARMED' : 'NO SHUTDOWN ACTIONS'; ]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.power_resilience_recommended_stage
name: Powerwall Inputs
icon: mdi:home-battery-outline
state_display: >
[[[
const grid = String(entity?.attributes?.grid_status ?? 'NO DATA').toUpperCase();
const charge = Number(entity?.attributes?.powerwall_charge);
return Number.isFinite(charge) ? `GRID ${grid} / ${charge.toFixed(0)}%` : `GRID ${grid} / NO DATA`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.power_resilience_recommended_stage
name: Outage Elapsed
icon: mdi:timer-sand
state_display: >
[[[
const seconds = Number(entity?.attributes?.outage_elapsed_seconds);
if (!Number.isFinite(seconds)) return 'NO DATA';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
]]]

@ -0,0 +1,23 @@
######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Systems View - Car
# Read-only Tesla, tire-pressure, mileage, and JuiceBox charging telemetry.
# -------------------------------------------------------------------
# Related Issue: 1944
# Notes: TeslaMate remains the source of truth for long-term vehicle history.
# Notes: JuiceBox cards stay unavailable until the charger sends real telemetry.
######################################################################
title: Car
path: car
type: sections
icon: mdi:car-electric
theme: default
max_columns: 4
dense_section_placement: true
badges: []
sections: !include /config/dashboards/infrastructure/partials/car_sections.yaml
cards: []

@ -0,0 +1,22 @@
######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Infrastructure View - UPS Power
# Garage and Office backup-power status, capacity, and recent trends.
# -------------------------------------------------------------------
# Notes: The Office Eaton 3S 550 is served by the headless office-pi NUT host.
# Notes: All graphs use a consistent 24-hour window.
######################################################################
title: UPS Power
path: ups
type: sections
icon: mdi:battery-heart-variant
theme: default
max_columns: 4
dense_section_placement: true
badges: []
sections: !include /config/dashboards/infrastructure/partials/ups_sections.yaml
cards: []

@ -7,6 +7,7 @@
# Full interactive Dreame map for zone, point, and room cleaning.
# -------------------------------------------------------------------
# Notes: Specialized map card is retained because native cards do not expose interactive vacuum-map cleaning.
# Notes: Use the saved BearStone map and its explicit calibration because the current-map camera can omit both.
# Notes: Panel view is intentional so the single interactive map can use the full available canvas.
######################################################################
@ -23,9 +24,27 @@ cards:
grid_options:
columns: full
map_source:
camera: camera.l10s_vacuum_map
camera: camera.l10s_vacuum_map_1
calibration_source:
camera: true
calibration_points:
- vacuum:
x: 0
y: 0
map:
x: 870
y: 1093
- vacuum:
x: 1000
y: 0
map:
x: 950
y: 1093
- vacuum:
x: 0
y: 1000
map:
x: 870
y: 1013
entity: vacuum.l10s_vacuum
vacuum_platform: Tasshack/dreame-vacuum
map_modes:

@ -57,6 +57,7 @@ exclude:
- number.spaceship_*
- select.spaceship_*
- sensor.spaceship_*
- sensor.odometer
- switch.spaceship_*
- update.spaceship_*
- input_text.l10s_vacuum_*
@ -109,7 +110,6 @@ exclude:
# BEGIN generated Portainer recorder/logbook noise exclusions
# Current retained Portainer telemetry is live-only; aggregate Docker history remains recorded.
- binary_sensor.nebula_sync_status_2
- binary_sensor.pihole_secondary_status_2
- binary_sensor.portainer_agent_status_2
- binary_sensor.portainer_status_2
- sensor.nebula_sync_state_2

@ -155,7 +155,6 @@ switch:
- switch.paiges_bookshelf_container
- switch.panel_notes_container_2
- switch.pihole_container_2
- switch.pihole_secondary_container_2
- switch.poker_tracker_container_2
- switch.portainer_agent_container_2
- switch.portainer_container_2

@ -23,7 +23,7 @@
# Notes: Docker host root disk usage uses Glances-backed normalized sensors; raw Glances sensors are recorder/logbook-filtered.
# Notes: Disk-pressure dispatch allows bounded safe cleanup of disposable caches and old generated backup artifacts, but not live data or restarts.
# Notes: Warning-level Docker host disk pressure is Joanna-only; Repairs are reserved for critical pressure.
# Notes: Nebula Sync DNS consistency compares primary/backup Pi-hole answers and dispatches Joanna on sustained drift or container loss.
# Notes: Nebula Sync compares the docker_10 primary with the physical office-pi DNS replica and dispatches Joanna on sustained drift or endpoint loss.
# 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.
@ -32,6 +32,7 @@
# Notes: Dashboard aggregate issue count includes compact BearClaw scheduled-job warning/error health.
# Notes: Docker host maintenance is counted separately from container runtime health so pending packages and stale host reports surface on Systems.
# Notes: Home Water rollup includes Rheem faults/telemetry loss plus active Phyn alerts and valve closure.
# Notes: UPS outage status aggregates the Garage and Office NUT servers from their raw status-data entities.
######################################################################
input_text:
@ -121,7 +122,7 @@ command_line:
name: Infra Nebula Sync DNS Consistency
unique_id: infra_nebula_sync_dns_consistency
command: >-
/bin/bash -c 'primary=192.168.10.10; secondary=192.168.10.14; host=GTG-PF45FK6F; fqdn=GTG-PF45FK6F.fordst.com; ip=192.168.10.117; q(){ dig +time=2 +tries=1 +short @"$1" "$2" A 2>/dev/null | tr -d "\r" | sort | tr "\n" "," | sed "s/,$//"; }; r(){ dig +time=2 +tries=1 +short @"$1" -x "$2" 2>/dev/null | tr -d "\r" | sed "s/\.$//" | sort | tr "\n" "," | sed "s/,$//"; }; p_short=$(q "$primary" "$host"); s_short=$(q "$secondary" "$host"); p_fqdn=$(q "$primary" "$fqdn"); s_fqdn=$(q "$secondary" "$fqdn"); p_rev=$(r "$primary" "$ip"); s_rev=$(r "$secondary" "$ip"); status=mismatch; if [ "$p_short" = "$ip" ] && [ "$s_short" = "$ip" ] && [ "$p_fqdn" = "$ip" ] && [ "$s_fqdn" = "$ip" ] && [ -n "$p_rev" ] && [ "$p_rev" = "$s_rev" ]; then status=ok; fi; printf "{\"status\":\"%s\",\"host\":\"%s\",\"expected_ip\":\"%s\",\"primary_short\":\"%s\",\"secondary_short\":\"%s\",\"primary_fqdn\":\"%s\",\"secondary_fqdn\":\"%s\",\"primary_reverse\":\"%s\",\"secondary_reverse\":\"%s\"}\n" "$status" "$host" "$ip" "$p_short" "$s_short" "$p_fqdn" "$s_fqdn" "$p_rev" "$s_rev"'
/bin/bash -c 'primary=192.168.10.10; secondary=192.168.10.100; host=GTG-PF45FK6F; fqdn=GTG-PF45FK6F.fordst.com; ip=192.168.10.117; q(){ dig +time=2 +tries=1 +short @"$1" "$2" A 2>/dev/null | tr -d "\r" | sort | tr "\n" "," | sed "s/,$//"; }; r(){ dig +time=2 +tries=1 +short @"$1" -x "$2" 2>/dev/null | tr -d "\r" | sed "s/\.$//" | sort | tr "\n" "," | sed "s/,$//"; }; p_short=$(q "$primary" "$host"); s_short=$(q "$secondary" "$host"); p_fqdn=$(q "$primary" "$fqdn"); s_fqdn=$(q "$secondary" "$fqdn"); p_rev=$(r "$primary" "$ip"); s_rev=$(r "$secondary" "$ip"); status=mismatch; if [ "$p_short" = "$ip" ] && [ "$s_short" = "$ip" ] && [ "$p_fqdn" = "$ip" ] && [ "$s_fqdn" = "$ip" ] && [ -n "$p_rev" ] && [ "$p_rev" = "$s_rev" ]; then status=ok; fi; printf "{\"status\":\"%s\",\"host\":\"%s\",\"expected_ip\":\"%s\",\"primary_short\":\"%s\",\"secondary_short\":\"%s\",\"primary_fqdn\":\"%s\",\"secondary_fqdn\":\"%s\",\"primary_reverse\":\"%s\",\"secondary_reverse\":\"%s\"}\n" "$status" "$host" "$ip" "$p_short" "$s_short" "$p_fqdn" "$s_fqdn" "$p_rev" "$s_rev"'
scan_interval: 300
value_template: "{{ value_json.status | default('unknown') }}"
json_attributes:
@ -138,7 +139,7 @@ command_line:
name: Infra Pihole IoT DNS Consistency
unique_id: infra_pihole_iot_dns_consistency
command: >-
/bin/bash -c 'primary=192.168.10.10; secondary=192.168.10.14; records="rachio.fordst.com=192.168.10.73 econet.fordst.com=192.168.10.92 dreame-vacuum.fordst.com=192.168.10.93 carlo-bed.fordst.com=192.168.10.95 lg-smart-fridge.fordst.com=192.168.10.96 tesla-blackbox-gw.fordst.com=192.168.10.97 bgw210.fordst.com=192.168.10.98"; q(){ dig +time=2 +tries=1 +short @"$1" "$2" A 2>/dev/null | tr -d "\r" | sort | tr "\n" "," | sed "s/,$//"; }; status=ok; checked=0; mismatch_count=0; mismatches=""; for record in $records; do host=${record%%=*}; ip=${record#*=}; p=$(q "$primary" "$host"); s=$(q "$secondary" "$host"); checked=$((checked+1)); if [ "$p" != "$ip" ] || [ "$s" != "$ip" ]; then status=mismatch; mismatch_count=$((mismatch_count+1)); mismatches="${mismatches}${host}:expected=${ip},primary=${p:-none},secondary=${s:-none};"; fi; done; if [ -z "$mismatches" ]; then mismatches=none; fi; printf "{\"status\":\"%s\",\"checked_records\":%s,\"mismatch_count\":%s,\"mismatches\":\"%s\",\"primary_dns\":\"%s\",\"backup_dns\":\"%s\"}\n" "$status" "$checked" "$mismatch_count" "$mismatches" "$primary" "$secondary"'
/bin/bash -c 'primary=192.168.10.10; secondary=192.168.10.100; records="rachio.fordst.com=192.168.10.73 econet.fordst.com=192.168.10.92 dreame-vacuum.fordst.com=192.168.10.93 carlo-bed.fordst.com=192.168.10.95 lg-smart-fridge.fordst.com=192.168.10.96 tesla-blackbox-gw.fordst.com=192.168.10.97 bgw210.fordst.com=192.168.10.98"; q(){ dig +time=2 +tries=1 +short @"$1" "$2" A 2>/dev/null | tr -d "\r" | sort | tr "\n" "," | sed "s/,$//"; }; status=ok; checked=0; mismatch_count=0; mismatches=""; for record in $records; do host=${record%%=*}; ip=${record#*=}; p=$(q "$primary" "$host"); s=$(q "$secondary" "$host"); checked=$((checked+1)); if [ "$p" != "$ip" ] || [ "$s" != "$ip" ]; then status=mismatch; mismatch_count=$((mismatch_count+1)); mismatches="${mismatches}${host}:expected=${ip},primary=${p:-none},secondary=${s:-none};"; fi; done; if [ -z "$mismatches" ]; then mismatches=none; fi; printf "{\"status\":\"%s\",\"checked_records\":%s,\"mismatch_count\":%s,\"mismatches\":\"%s\",\"primary_dns\":\"%s\",\"backup_dns\":\"%s\"}\n" "$status" "$checked" "$mismatch_count" "$mismatches" "$primary" "$secondary"'
scan_interval: 300
value_template: "{{ value_json.status | default('unknown') }}"
json_attributes:
@ -242,8 +243,10 @@ template:
'binary_sensor.infra_wan_quality_degraded',
'binary_sensor.infra_dns_pihole_degraded',
'binary_sensor.infra_compute_degraded',
'binary_sensor.infra_storage_degraded',
'binary_sensor.infra_external_monitoring_degraded',
'binary_sensor.infra_storage_degraded',
'binary_sensor.infra_external_monitoring_degraded',
'binary_sensor.juicepassproxy_monitoring_degraded',
'binary_sensor.infra_ups_on_battery',
'binary_sensor.docker_host_maintenance_attention',
'binary_sensor.hvac_maintenance_due',
'binary_sensor.home_water_problem',
@ -258,8 +261,10 @@ template:
'binary_sensor.infra_wan_quality_degraded',
'binary_sensor.infra_dns_pihole_degraded',
'binary_sensor.infra_compute_degraded',
'binary_sensor.infra_storage_degraded',
'binary_sensor.infra_external_monitoring_degraded',
'binary_sensor.infra_storage_degraded',
'binary_sensor.infra_external_monitoring_degraded',
'binary_sensor.juicepassproxy_monitoring_degraded',
'binary_sensor.infra_ups_on_battery',
'binary_sensor.docker_host_maintenance_attention',
'binary_sensor.hvac_maintenance_due',
'binary_sensor.home_water_problem',
@ -454,7 +459,7 @@ template:
secondary_reverse: "{{ state_attr('sensor.infra_nebula_sync_dns_consistency', 'secondary_reverse') }}"
nebula_status: "{{ states('binary_sensor.nebula_sync_status_2') }}"
nebula_state: "{{ states('sensor.nebula_sync_state_2') }}"
pihole_secondary_status: "{{ states('binary_sensor.pihole_secondary_status_2') }}"
pihole_secondary_status: "{{ states('binary_sensor.pi_hole_status_2') }}"
- name: "Infra Pihole IoT DNS Degraded"
unique_id: infra_pihole_iot_dns_degraded
@ -473,8 +478,20 @@ template:
unique_id: infra_ups_on_battery
device_class: problem
state: >-
{% set status = states('sensor.garage_ups_status') | upper %}
{{ 'OB' in status }}
{% set statuses = [
states('sensor.garage_ups_status_data') | upper,
states('sensor.office_ups_eaton_550_status_data') | upper
] %}
{% set ns = namespace(on_battery=false) %}
{% for status in statuses %}
{% if 'OB' in status.split() %}
{% set ns.on_battery = true %}
{% endif %}
{% endfor %}
{{ ns.on_battery }}
attributes:
garage_status: "{{ states('sensor.garage_ups_status') }}"
office_status: "{{ states('sensor.office_ups_eaton_550_status') }}"
- name: "Infra Website Degraded"
unique_id: infra_website_degraded
@ -734,7 +751,7 @@ automation:
degraded: "{{ is_state('binary_sensor.infra_nebula_sync_degraded', 'on') }}"
nebula_status: "{{ states('binary_sensor.nebula_sync_status_2') }}"
nebula_state: "{{ states('sensor.nebula_sync_state_2') }}"
pihole_secondary_status: "{{ states('binary_sensor.pihole_secondary_status_2') }}"
pihole_secondary_status: "{{ states('binary_sensor.pi_hole_status_2') }}"
action:
- choose:
- conditions: "{{ degraded and previous_band != 'warning' }}"
@ -753,7 +770,7 @@ automation:
- binary_sensor.infra_nebula_sync_degraded
- binary_sensor.nebula_sync_status_2
- sensor.nebula_sync_state_2
- binary_sensor.pihole_secondary_status_2
- binary_sensor.pi_hole_status_2
diagnostics: >-
issue_id={{ issue_id }},
dns_consistency={{ dns_state }},
@ -769,9 +786,9 @@ automation:
nebula_state={{ nebula_state }},
pihole_secondary_status={{ pihole_secondary_status }},
primary_dns=192.168.10.10,
backup_dns=192.168.10.14
backup_dns=192.168.10.100
request: >-
Investigate Nebula Sync on docker_14 and the backup Pi-hole sync path.
Investigate Nebula Sync on docker_14 and the physical backup Pi-hole on office-pi.
Verify both Pi-holes answer the GTG-PF45FK6F short name, FQDN, and reverse lookup consistently.
Check nebula_sync container status, Docker health, recent sync logs, and primary/replica Pi-hole API reachability.
If confidence is high, perform safe remediation such as a one-time Nebula Sync run or restarting only the nebula_sync container.

@ -4,7 +4,7 @@
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Pi-hole HA Sync - Mirror blocking state across DNS nodes
# Keep Pi-hole blocking on docker_10 and docker_14 in lockstep.
# Keep Pi-hole blocking on docker_10 and office-pi in lockstep.
# -------------------------------------------------------------------
# Notes: Uses switch.pi_hole + switch.pi_hole_2 from the Pi-hole integration.
# Notes: Auto re-enables Pi-hole after 60 minutes of being off.

@ -11,6 +11,8 @@
# Notes: Keeps 180 days (1/2 year); excludes vcloudinfo pings, noisy connectivity telemetry, countdown-style alarm helpers, low-value script/button/scene history, MariaDB snapshot helpers, raw Docker/Proxmox/Glances host telemetry including dynamic Docker veth sensors, PoE live power, and other high-churn entities; MariaDB via recorder_db_url.
# Notes: L10s status/room telemetry is live-only; keep curated VACUUM logbook entries plus error/run context instead.
# Notes: Tesla Fleet Spaceship telemetry is live-only in HA; TeslaMate is the historical car database.
# Notes: Persisted vehicle/JuiceBox measurements stay useful without synthetic
# last-report timestamps or transient max-current snapshot history.
# 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 except daily pedometer metrics for Carlo and Stacey, retained for fitness history; Life360 keeps location history and notify services remain available.
@ -89,6 +91,7 @@ exclude:
- number.spaceship_*
- select.spaceship_*
- sensor.spaceship_*
- sensor.odometer
- switch.spaceship_*
- update.spaceship_*
- select.sleepnumber_*
@ -216,7 +219,6 @@ exclude:
# BEGIN generated Portainer recorder/logbook noise exclusions
# Current retained Portainer telemetry is live-only; aggregate Docker history remains recorded.
- binary_sensor.nebula_sync_status_2
- binary_sensor.pihole_secondary_status_2
- binary_sensor.portainer_agent_status_2
- binary_sensor.portainer_status_2
- sensor.nebula_sync_state_2
@ -273,6 +275,10 @@ exclude:
- sensor.pi_hole_dns_queries_today
- sensor.rachio_watering_time
- sensor.time
- sensor.juicebox_max_current_offline_device
- sensor.juicebox_max_current_online_device
- sensor.juicepassproxy_health
- sensor.juicepassproxy_state
- sensor.vcloudinfo_com
- switch.bear_stone
- switch.alarm_panel_1_screensaver

Loading…
Cancel
Save

Powered by TurnKey Linux.