Files
ha-core-crash-fix/sensors.yaml
T

514 lines
19 KiB
YAML

# sensors.yaml - All sensors for monitoring, device management, and household automation
# Hardware monitoring sensors
- platform: openhardwaremonitor
host: 10.0.0.245
port: 8085
# SNMP sensors for NVX monitoring
- platform: snmp
host: 10.0.0.232
baseoid: 1.3.6.1.2.1.1.5.0
name: "NVX Name"
- platform: snmp
host: 10.0.0.232
baseoid: 1.3.6.1.4.1.4526.18.4.1.2.1
name: "NVX Fan RPM"
- platform: snmp
host: 10.0.0.232
baseoid: 1.3.6.1.4.1.4526.18.5.1.2.1
name: "NVX Temp Value"
# Command line sensors
- platform: command_line
name: "Chore Summary"
command: "cat /config/www/chore_summary.txt"
scan_interval: 60
- platform: command_line
name: "Chore Log Raw"
command: "cat /config/www/chore_log.txt"
scan_interval: 60
# Time and date sensors
- platform: time_date
display_options:
- "time"
- "date"
# All template sensors (using legacy format for compatibility)
- platform: template
sensors:
# Waste collection sensors
green_bin:
friendly_name: "Greens Bin"
value_template: >
{% set start_date = as_timestamp('2026-04-12 00:00:00') %}
{% set now_ts = now().timestamp() %}
{% set weeks_since_start = ((now_ts - start_date) / 604800) | round(0, 'floor') | int %}
{{ now().weekday() == 6 and weeks_since_start % 2 == 0 }}
recycling_bin:
friendly_name: "Recycling Bin"
value_template: >
{% set start_date = as_timestamp('2026-04-12 00:00:00') %}
{% set now_ts = now().timestamp() %}
{% set weeks_since_start = ((now_ts - start_date) / 604800) | round(0, 'floor') | int %}
{{ now().weekday() == 6 and weeks_since_start % 2 == 1 }}
# Time-based sensors
is_weekday:
friendly_name: "Is Weekday"
value_template: >
{% set now = now() %}
{{ now.weekday() >= 0 and now.weekday() <= 4 }}
current_day_name:
friendly_name: "Current Day Name"
value_template: >
{% set now = now() %}
{% set day_number = now.weekday() %}
{{ ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][day_number] }}
is_morning:
friendly_name: "Is Morning"
value_template: >
{% set now = now() %}
{{ now.hour >= 6 and now.hour < 12 }}
is_afternoon:
friendly_name: "Is Afternoon"
value_template: >
{% set now = now() %}
{{ now.hour >= 12 and now.hour < 18 }}
is_evening:
friendly_name: "Is Evening"
value_template: >
{% set now = now() %}
{{ now.hour >= 18 and now.hour < 21 }}
is_bedtime:
friendly_name: "Is Bedtime"
value_template: >
{% set now = now() %}
{{ now.hour >= 21 and now.hour <= 23 }}
is_weekend:
friendly_name: "Is Weekend"
value_template: >
{% set now = now() %}
{{ now.weekday() >= 5 }}
# School term sensors
school_term_1:
friendly_name: "School Term 1"
value_template: >
{% set now = as_timestamp(now()) %}
{% set start = as_timestamp(strptime('2026-01-27', '%Y-%m-%d')) %}
{% set end = as_timestamp(strptime('2026-04-02', '%Y-%m-%d')) %}
{{ now >= start and now <= end }}
school_term_2:
friendly_name: "School Term 2"
value_template: >
{% set now = as_timestamp(now()) %}
{% set start = as_timestamp(strptime('2026-04-20', '%Y-%m-%d')) %}
{% set end = as_timestamp(strptime('2026-06-26', '%Y-%m-%d')) %}
{{ now >= start and now <= end }}
school_term_3:
friendly_name: "School Term 3"
value_template: >
{% set now = as_timestamp(now()) %}
{% set start = as_timestamp(strptime('2026-07-13', '%Y-%m-%d')) %}
{% set end = as_timestamp(strptime('2026-09-18', '%Y-%m-%d')) %}
{{ now >= start and now <= end }}
school_term_4:
friendly_name: "School Term 4"
value_template: >
{% set now = as_timestamp(now()) %}
{% set start = as_timestamp(strptime('2026-10-05', '%Y-%m-%d')) %}
{% set end = as_timestamp(strptime('2026-12-18', '%Y-%m-%d')) %}
{{ now >= start and now <= end }}
is_school_term:
friendly_name: "Is School Term"
value_template: >
{{ states('sensor.school_term_1') == 'True' or
states('sensor.school_term_2') == 'True' or
states('sensor.school_term_3') == 'True' or
states('sensor.school_term_4') == 'True' }}
current_date_debug:
friendly_name: "Current Date Debug"
value_template: >
{{ now().date() }}
# Task management sensors
active_tasks_count:
friendly_name: "Active Tasks Count"
value_template: >
{% set tasks = [
'input_boolean.task_dishwasher_unload_pending',
'input_boolean.task_washing_machine_unload_pending',
'input_boolean.task_dryer_unload_pending',
'input_boolean.task_bins_out_pending',
'input_boolean.task_bins_in_pending',
'input_boolean.task_kitty_litter_clean_pending',
'input_boolean.task_kitty_litter_change_pending'
] %}
{{ tasks | select('is_state', 'on') | list | count }}
pending_tasks_list:
friendly_name: "Pending Tasks"
value_template: >
{% set task_names = {
'input_boolean.task_dishwasher_unload_pending': 'Unload Dishwasher',
'input_boolean.task_washing_machine_unload_pending': 'Unload Washing Machine',
'input_boolean.task_dryer_unload_pending': 'Unload Dryer',
'input_boolean.task_bins_out_pending': 'Put Bins Out',
'input_boolean.task_bins_in_pending': 'Bring Bins In',
'input_boolean.task_kitty_litter_clean_pending': 'Clean Kitty Litter',
'input_boolean.task_kitty_litter_change_pending': 'Change Kitty Litter'
} %}
{% set pending = [] %}
{% for entity, name in task_names.items() %}
{% if is_state(entity, 'on') %}
{% set pending = pending + [name] %}
{% endif %}
{% endfor %}
{{ pending | join(', ') }}
last_kitty_litter_change:
friendly_name: "Last Kitty Litter Change"
value_template: >
{{ states('input_datetime.last_kitty_litter_change') | as_timestamp | timestamp_custom('%Y-%m-%d')
if states('input_datetime.last_kitty_litter_change') != 'unknown' else 'Never' }}
# Weekly task totals for each person
lou_weekly_tasks:
friendly_name: "Lou's Weekly Tasks"
value_template: "{{ states('counter.chores_completed_lou') | int }}"
icon_template: mdi:account
jess_weekly_tasks:
friendly_name: "Jess's Weekly Tasks"
value_template: "{{ states('counter.chores_completed_jess') | int }}"
icon_template: mdi:account
william_weekly_tasks:
friendly_name: "William's Weekly Tasks"
value_template: "{{ states('counter.chores_completed_william') | int }}"
icon_template: mdi:account
xander_weekly_tasks:
friendly_name: "Xander's Weekly Tasks"
value_template: "{{ states('counter.chores_completed_xander') | int }}"
icon_template: mdi:account
bella_weekly_tasks:
friendly_name: "Bella's Weekly Tasks"
value_template: "{{ states('counter.chores_completed_bella') | int }}"
icon_template: mdi:account
# Total weekly tasks
total_weekly_tasks:
friendly_name: "Total Weekly Tasks"
value_template: >
{{ states('counter.chores_completed_lou') | int +
states('counter.chores_completed_jess') | int +
states('counter.chores_completed_william') | int +
states('counter.chores_completed_xander') | int +
states('counter.chores_completed_bella') | int }}
icon_template: mdi:clipboard-list
# Percentage calculations for pie chart
lou_percentage:
friendly_name: "Lou's Percentage"
value_template: >
{% set total = states('sensor.total_weekly_tasks') | int %}
{% set lou_tasks = states('counter.chores_completed_lou') | int %}
{% if total > 0 %}
{{ ((lou_tasks / total) * 100) | round(1) }}
{% else %}
0
{% endif %}
unit_of_measurement: "%"
jess_percentage:
friendly_name: "Jess's Percentage"
value_template: >
{% set total = states('sensor.total_weekly_tasks') | int %}
{% set jess_tasks = states('counter.chores_completed_jess') | int %}
{% if total > 0 %}
{{ ((jess_tasks / total) * 100) | round(1) }}
{% else %}
0
{% endif %}
unit_of_measurement: "%"
william_percentage:
friendly_name: "William's Percentage"
value_template: >
{% set total = states('sensor.total_weekly_tasks') | int %}
{% set william_tasks = states('counter.chores_completed_william') | int %}
{% if total > 0 %}
{{ ((william_tasks / total) * 100) | round(1) }}
{% else %}
0
{% endif %}
unit_of_measurement: "%"
xander_percentage:
friendly_name: "Xander's Percentage"
value_template: >
{% set total = states('sensor.total_weekly_tasks') | int %}
{% set xander_tasks = states('counter.chores_completed_xander') | int %}
{% if total > 0 %}
{{ ((xander_tasks / total) * 100) | round(1) }}
{% else %}
0
{% endif %}
unit_of_measurement: "%"
bella_percentage:
friendly_name: "Bella's Percentage"
value_template: >
{% set total = states('sensor.total_weekly_tasks') | int %}
{% set bella_tasks = states('counter.chores_completed_bella') | int %}
{% if total > 0 %}
{{ ((bella_tasks / total) * 100) | round(1) }}
{% else %}
0
{% endif %}
unit_of_measurement: "%"
# Network and device management sensors
total_devices_online:
friendly_name: "Total Devices Online"
icon_template: mdi:devices
unit_of_measurement: "devices"
value_template: >
{{ [
states('device_tracker.william_pc'),
states('device_tracker.william_laptop'),
states('device_tracker.william_phone'),
states('device_tracker.jess_laptop_1'),
states('device_tracker.jess_phone'),
states('device_tracker.bella_desktop'),
states('device_tracker.bella_phone'),
states('device_tracker.xander_gaming_pc'),
states('device_tracker.xander_console')
] | select('eq', 'home') | list | count }}
availability_template: >
{{ has_value('device_tracker.william_pc')
and has_value('device_tracker.jess_laptop_1')
and has_value('device_tracker.bella_phone') }}
# NOTE: This sensor MUST exclude its own entity_id, otherwise every
# recalculation changes its own state, which retriggers the template,
# causing a "Template loop detected" storm. The full entity list is
# intentionally NOT stored as an attribute (it exceeded the 16384-byte
# recorder limit and was rejected every cycle); only a capped preview
# is exposed for dashboards.
unavailable_entities:
friendly_name: "Unavailable Entities"
icon_template: >
{{ 'mdi:check-circle' if states('sensor.unavailable_entities')|int == 0 else 'mdi:alert-circle' }}
unit_of_measurement: "entities"
value_template: >
{{ states | selectattr('state', 'in', ['unavailable', 'unknown'])
| rejectattr('domain', 'eq', 'group')
| rejectattr('entity_id', 'eq', 'sensor.unavailable_entities')
| rejectattr('entity_id', 'search', 'sun\.')
| list | count }}
attribute_templates:
# Capped to first 50 entity_ids to stay well under the 16 KB
# recorder attribute limit. Drop this block entirely if you don't
# need the preview on a dashboard.
entities_preview: >
{{ (states | selectattr('state', 'in', ['unavailable', 'unknown'])
| rejectattr('domain', 'eq', 'group')
| rejectattr('entity_id', 'eq', 'sensor.unavailable_entities')
| rejectattr('entity_id', 'search', 'sun\.')
| map(attribute='entity_id') | list | sort)[:50] }}
family_devices_status:
friendly_name: "Family Devices Status"
icon_template: mdi:account-multiple
value_template: >
{% set devices = [
'device_tracker.william_pc',
'device_tracker.william_phone',
'device_tracker.jess_laptop_1',
'device_tracker.jess_phone',
'device_tracker.bella_desktop',
'device_tracker.bella_phone',
'device_tracker.xander_gaming_pc'
] %}
{% set online = devices | select('is_state', 'home') | list | count %}
{% set total = devices | count %}
{{ online }}/{{ total }}
network_performance_score:
friendly_name: "Network Performance Score"
unit_of_measurement: "%"
icon_template: >
{% set score = states('sensor.network_performance_score') | int(0) %}
{% if score >= 80 %}mdi:speedometer
{% elif score >= 60 %}mdi:speedometer-medium
{% else %}mdi:speedometer-slow
{% endif %}
value_template: >
{% if is_state('binary_sensor.ping_router', 'on') %}
{% set ping_time = state_attr('binary_sensor.ping_router', 'round_trip_time_avg') | float(0) %}
{% if ping_time < 10 %}100
{% elif ping_time < 50 %}80
{% elif ping_time < 100 %}60
{% elif ping_time < 200 %}40
{% else %}20
{% endif %}
{% else %}
0
{% endif %}
blocked_devices_count:
friendly_name: "Blocked Devices Count"
icon_template: mdi:block-helper
unit_of_measurement: "devices"
value_template: >
{{ states.input_boolean
| selectattr('entity_id', 'match', '.*_blocked$')
| selectattr('state', 'eq', 'on')
| list | count }}
attribute_templates:
blocked_devices: >
{{ states.input_boolean
| selectattr('entity_id', 'match', '.*_blocked$')
| selectattr('state', 'eq', 'on')
| map(attribute='name')
| list }}
bella_devices_status:
friendly_name: "Bella Devices Status"
icon_template: mdi:account-child
value_template: >
{% set blocked = states.input_boolean
| selectattr('entity_id', 'match', '^input_boolean\.bella_.*_blocked$')
| selectattr('state', 'eq', 'on')
| list | count %}
{% set total = 7 %}
{% if blocked == 0 %}All Access
{% elif blocked == total %}Fully Blocked
{% else %}{{ blocked }}/{{ total }} Blocked
{% endif %}
xander_devices_status:
friendly_name: "Xander Devices Status"
icon_template: mdi:account-child
value_template: >
{% set blocked = states.input_boolean
| selectattr('entity_id', 'match', '^input_boolean\.xander_.*_blocked$')
| selectattr('state', 'eq', 'on')
| list | count %}
{% set total = 7 %}
{% if blocked == 0 %}All Access
{% elif blocked == total %}Fully Blocked
{% else %}{{ blocked }}/{{ total }} Blocked
{% endif %}
william_devices_status:
friendly_name: "William Devices Status"
icon_template: mdi:account-child
value_template: >
{% set blocked = states.input_boolean
| selectattr('entity_id', 'match', '^input_boolean\.william_.*_blocked$')
| selectattr('state', 'eq', 'on')
| list | count %}
{% set total = 7 %}
{% if blocked == 0 %}All Access
{% elif blocked == total %}Fully Blocked
{% else %}{{ blocked }}/{{ total }} Blocked
{% endif %}
# Device blocking statistics
devices_currently_blocked:
friendly_name: "Devices Currently Blocked"
icon_template: mdi:shield-lock
unit_of_measurement: "devices"
value_template: >
{{ states.input_boolean
| selectattr('entity_id', 'match', '.*_blocked$')
| selectattr('state', 'eq', 'on')
| list | count }}
# System health monitoring
system_health_score:
friendly_name: "System Health Score"
unit_of_measurement: "%"
icon_template: >
{% set score = states('sensor.system_health_score') | int(0) %}
{% if score >= 90 %}mdi:heart-pulse
{% elif score >= 70 %}mdi:heart-half-full
{% else %}mdi:heart-broken
{% endif %}
value_template: >
{% set router_ok = 1 if is_state('binary_sensor.ping_router', 'on') else 0 %}
{% set auth_ok = 1 if states('input_text.router_token') not in ['unknown', '', 'unavailable'] else 0 %}
{% set internet_ok = 1 if is_state('binary_sensor.internet_connectivity', 'on') else 0 %}
{% set unavailable = states('sensor.unavailable_entities') | int(0) %}
{% set health_penalty = (unavailable * 2) | int %}
{% set base_score = ((router_ok + auth_ok + internet_ok) * 30) | int %}
{{ [base_score - health_penalty, 0] | max }}
# Network security level
network_security_level:
friendly_name: "Network Security Level"
icon_template: >
{% set level = states('sensor.network_security_level') %}
{% if level == 'High' %}mdi:shield-check
{% elif level == 'Medium' %}mdi:shield-half-full
{% else %}mdi:shield-alert
{% endif %}
value_template: >
{% set blocked = states('sensor.devices_currently_blocked') | int(0) %}
{% if blocked >= 10 %}High
{% elif blocked >= 5 %}Medium
{% elif blocked >= 1 %}Low
{% else %}Off
{% endif %}
# Router device count
router_device_count:
friendly_name: "Router Connected Devices"
icon_template: mdi:devices
unit_of_measurement: "devices"
value_template: >
{{ states.input_boolean
| selectattr('entity_id', 'match', '.*_online$')
| selectattr('state', 'eq', 'on')
| list | count }}
# Router access control rules count
router_access_control_rules:
friendly_name: "Active Access Control Rules"
icon_template: mdi:shield-check
unit_of_measurement: "rules"
value_template: >
{{ states('sensor.devices_currently_blocked') | int(0) }}
# MAC address change detection
devices_with_changed_macs:
friendly_name: "Devices with Changed MACs"
icon_template: mdi:alert-circle
unit_of_measurement: "devices"
value_template: >
{{ states.input_boolean
| selectattr('entity_id', 'match', '.*_mac_changed$')
| selectattr('state', 'eq', 'on')
| list | count }}