diff --git a/config/dashboards/README.md b/config/dashboards/README.md index d411b192..57b5eeb1 100644 --- a/config/dashboards/README.md +++ b/config/dashboards/README.md @@ -78,6 +78,10 @@ Lovelace resources are loaded from: - Include paths in Lovelace YAML should use absolute container paths starting with `/config/`. - Example: `!include /config/dashboards/overview/partials/some_cards.yaml` - Views are loaded using `!include_dir_list` and ordered by filename (prefix with `01_`, `02_`, etc.). +- Infrastructure views are desktop-first and dense by default: use `type: sections`, `max_columns: 4`, and `dense_section_placement: true` on every standard view. + - Use responsive `layout-card` grids with `min-content` rows inside full-width section wrappers so panels pack tightly without fixed-height gaps. + - Keep related panels similar in height, avoid spacer cards, and verify both desktop and single-column mobile layouts. + - Keep WAN telemetry, compact dual Pi-hole controls, and current website health together on the Network view; reserve hidden subviews for detailed Pi-hole analytics and domain/monitor telemetry. - Prefer card-native styling; treat `card_mod` as a last resort. - Prefer CSS variables (`var(--*)`) over hardcoded hex colors. - When using the Stitch MCP for inspiration, generation may exceed the tool timeout; wait and then fetch results via `stitch/list_screens` and `stitch/get_screen`. diff --git a/config/dashboards/infrastructure/dashboard.yaml b/config/dashboards/infrastructure/dashboard.yaml index 1bf054d1..3f298b6f 100644 --- a/config/dashboards/infrastructure/dashboard.yaml +++ b/config/dashboards/infrastructure/dashboard.yaml @@ -8,6 +8,7 @@ # ------------------------------------------------------------------- # Notes: Entry point for dashboard key `dashboard-infrastructure`. Views are loaded from /config/dashboards/infrastructure/views. # Notes: Joanna dispatch telemetry view is available at `/dashboard-infrastructure/joanna`. +# Notes: Network combines WAN, dual Pi-hole, and website health; `/pihole` and `/website-health` are detail subviews. ###################################################################### button_card_templates: !include /config/dashboards/infrastructure/templates/button_card_templates.yaml diff --git a/config/dashboards/infrastructure/partials/docker_containers_sections.yaml b/config/dashboards/infrastructure/partials/docker_containers_sections.yaml index 0727221d..bcd4650c 100644 --- a/config/dashboards/infrastructure/partials/docker_containers_sections.yaml +++ b/config/dashboards/infrastructure/partials/docker_containers_sections.yaml @@ -3,167 +3,184 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure Partial - Docker containers sections -# Related Issue: 1560, 1584, 1725 -# Sections layout for the Docker containers view. +# Infrastructure Partial - Docker operations +# Host health, updates, volumes, active exceptions, and inventory drill-down. # ------------------------------------------------------------------- -# Notes: Auto-discovers Portainer container entities from `switch.*_container`. -# Notes: Keeps cards visible when Portainer telemetry is unavailable (degraded mode). -# Notes: Includes stack-level status tiles from Portainer `*_stack_status` entities. -# Notes: Portainer volume usage is visible; volume prune is confined to host maintenance popups with hold-confirm actions. -# Notes: Docker volume summary tiles are explicit per host because Portainer does not expose endpoint volume totals for every host. -# Notes: Excludes transient codex_appliance Portainer run containers from generic container lists. +# Notes: Healthy stacks and containers live in the hidden Docker Inventory subview. +# Notes: Host maintenance controls remain in the existing confirmed popups. ###################################################################### +# ------------------------------------------------------------------- +# Docker health strip (mandatory first full-width wrapper) +# ------------------------------------------------------------------- - type: grid column_span: 4 - columns: 3 + columns: 1 square: false cards: - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.garage_ups_load - name: UPS Load - icon: mdi:battery-charging-60 - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.carlo_nvr_volume_1_volume_used - name: NVR Used - icon: mdi:harddisk - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.carlo_nas01_volume_1_volume_used - name: NAS Used - icon: mdi:nas + - type: custom:layout-card + grid_options: + columns: full + layout_type: custom:grid-layout + layout: + grid-template-columns: repeat(5, 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_infra_kpi + entity: sensor.docker_monitored_container_count + name: Monitored + icon: mdi:docker + state_display: > + [[[ + const ids = states['sensor.docker_monitored_switch_inventory']?.attributes?.entity_id; + const unique = Array.isArray(ids) + ? ids.filter(id => !String(id).endsWith('_container_2')).length + : entity.state; + return `${unique} workloads`; + ]]] -- type: grid - column_span: 4 - columns: 4 - square: false - cards: - - type: custom:bubble-card - card_type: button - button_type: state - entity: sensor.docker_10_apt_status - name: docker_10 - icon: mdi:server - show_state: true - show_last_changed: true - card_layout: large - tap_action: - action: navigate - navigation_path: '#infra-docker-10' - button_action: - tap_action: - action: navigate - navigation_path: '#infra-docker-10' - - type: custom:bubble-card - card_type: button - button_type: state - entity: sensor.docker_17_apt_status - name: docker_17 - icon: mdi:server - show_state: true - show_last_changed: true - card_layout: large - tap_action: - action: navigate - navigation_path: '#infra-docker-17' - button_action: - tap_action: - action: navigate - navigation_path: '#infra-docker-17' - - type: custom:bubble-card - card_type: button - button_type: state - entity: sensor.docker_69_apt_status - name: docker_69 - icon: mdi:server - show_state: true - show_last_changed: true - card_layout: large - tap_action: - action: navigate - navigation_path: '#infra-docker-69' - button_action: - tap_action: - action: navigate - navigation_path: '#infra-docker-69' - - type: custom:bubble-card - card_type: button - button_type: state - entity: sensor.docker_14_apt_status - name: docker_14 - icon: mdi:server - show_state: true - show_last_changed: true - card_layout: large - tap_action: - action: navigate - navigation_path: '#infra-docker-14' - button_action: - tap_action: - action: navigate - navigation_path: '#infra-docker-14' + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: sensor.docker_monitored_unavailable_count + name: Unavailable + icon: mdi:alert-circle-outline + variables: + ok_state: '0' + healthy_text: NONE + raw_suffix: UNAVAILABLE + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.docker_container_telemetry_degraded + name: Telemetry + icon: mdi:lan-check + variables: + ok_state: 'off' + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.carlo_nvr_volume_1_volume_used + name: NVR Used + icon: mdi:harddisk + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.carlo_nas01_volume_1_volume_used + name: NAS Used + icon: mdi:nas +# ------------------------------------------------------------------- +# Host maintenance signals and volume telemetry +# ------------------------------------------------------------------- - type: grid column_span: 4 columns: 1 square: false cards: - - type: custom:vertical-stack-in-card + - type: custom:layout-card grid_options: columns: full - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml + 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:button-card - template: bearstone_infra_panel_header - name: Docker Volumes - - 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)) + - 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 + name: Host Updates + + - type: custom:button-card + template: bearstone_infra_update_row + entity: sensor.docker_10_apt_status + name: docker_10 + tap_action: + action: navigate + navigation_path: '#infra-docker-10' + + - type: custom:button-card + template: bearstone_infra_update_row + entity: sensor.docker_17_apt_status + name: docker_17 + tap_action: + action: navigate + navigation_path: '#infra-docker-17' + + - type: custom:button-card + template: bearstone_infra_update_row + entity: sensor.docker_69_apt_status + name: docker_69 + tap_action: + action: navigate + navigation_path: '#infra-docker-69' + + - type: custom:button-card + template: bearstone_infra_update_row + entity: sensor.docker_14_apt_status + name: docker_14 + tap_action: + action: navigate + navigation_path: '#infra-docker-14' + + - 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 + name: Docker Volumes + - type: custom:button-card template: bearstone_infra_docker_volume_row entity: sensor.carlo_hass_volume_disk_usage_total_size name: docker_10 variables: total_entity: sensor.carlo_hass_volume_disk_usage_total_size + - type: custom:button-card template: bearstone_infra_docker_volume_row entity: button.docker2_prune_unused_volumes name: docker_14 + variables: + not_instrumented: true + - type: custom:button-card template: bearstone_infra_docker_volume_row entity: button.docker17_prune_unused_volumes name: docker_17 variables: volume_entities: - - sensor.17214906eee4a16eed521e2904730a8272958bb32209c8b204fef3914a85006f_volume_size - - sensor.17e04b7a1a6902f3192bd825b497c5a7a920c64c88a216968cf1700da94d10f0_volume_size - - sensor.31a30aacc34d2988cbedbd8aa82d29066a7630ad8e51ce3d55ea0d785c5e8dbc_volume_size - - sensor.8c8b88aa16230a391d2e61e75fcc62a57ee569416d7c55ab4e8cd7487813b5dd_volume_size - - sensor.9bfb74e2a728618f9c3c1a363d2ccb3bba6e0580a14b3ca6f32afa4dea827b25_volume_size - - sensor.a5f10bca01c2cdda3915951e27eef9fcd39a7eae695e3e9b21850550d7d91e29_volume_size - - sensor.a5f10bca01c2cdda3915951e27eef9fcd39a7eae695e3e9b21850550d7d91e29c_volume_size - - sensor.a6fd445f48ed6892eb26e97814cb7720758588101a441e6b3ffe117cb55f612c_volume_size - - sensor.dc429dc8845534e799ea6170bb3a9fb79db3dbb08db6ed198a396f2aadaa1a85_volume_size - - sensor.de3d33e1a75cb2d24f5f7f27f4d9bb1f814d72ef9229000a2bf9372e421dfaaf_volume_size - - sensor.deaf7fea946c0cd1a40d161ab66367fddc1f99c2a5aae7bf4ad99b47fe25283c_volume_size - - sensor.openrecord_local_openrecord_next_cache_volume_size - - sensor.openrecord_local_openrecord_scrapers_node_modules_volume_size - - sensor.openrecord_local_openrecord_web_node_modules_volume_size + - sensor.17214906eee4a16eed521e2904730a8272958bb32209c8b204fef3914a85006f_volume_size + - sensor.17e04b7a1a6902f3192bd825b497c5a7a920c64c88a216968cf1700da94d10f0_volume_size + - sensor.31a30aacc34d2988cbedbd8aa82d29066a7630ad8e51ce3d55ea0d785c5e8dbc_volume_size + - sensor.8c8b88aa16230a391d2e61e75fcc62a57ee569416d7c55ab4e8cd7487813b5dd_volume_size + - sensor.9bfb74e2a728618f9c3c1a363d2ccb3bba6e0580a14b3ca6f32afa4dea827b25_volume_size + - sensor.a5f10bca01c2cdda3915951e27eef9fcd39a7eae695e3e9b21850550d7d91e29_volume_size + - sensor.a5f10bca01c2cdda3915951e27eef9fcd39a7eae695e3e9b21850550d7d91e29c_volume_size + - sensor.a6fd445f48ed6892eb26e97814cb7720758588101a441e6b3ffe117cb55f612c_volume_size + - sensor.dc429dc8845534e799ea6170bb3a9fb79db3dbb08db6ed198a396f2aadaa1a85_volume_size + - sensor.de3d33e1a75cb2d24f5f7f27f4d9bb1f814d72ef9229000a2bf9372e421dfaaf_volume_size + - sensor.deaf7fea946c0cd1a40d161ab66367fddc1f99c2a5aae7bf4ad99b47fe25283c_volume_size + - sensor.openrecord_local_openrecord_next_cache_volume_size + - sensor.openrecord_local_openrecord_scrapers_node_modules_volume_size + - sensor.openrecord_local_openrecord_web_node_modules_volume_size + - type: custom:button-card template: bearstone_infra_docker_volume_row entity: sensor.docker69_volume_disk_usage_total_size @@ -171,6 +188,9 @@ variables: total_entity: sensor.docker69_volume_disk_usage_total_size +# ------------------------------------------------------------------- +# Exceptions only; full inventory is a hidden subview +# ------------------------------------------------------------------- - type: grid column_span: 4 columns: 1 @@ -184,9 +204,27 @@ cards: - type: custom:button-card template: bearstone_infra_panel_header - name: Docker Stacks + name: Workload Exceptions + + - type: custom:button-card + template: bearstone_infra_alert_row + entity: binary_sensor.docker_container_telemetry_degraded + name: Docker telemetry degraded + icon: mdi:lan-disconnect + variables: + alert_kind: binary_on + state_display: > + [[[ + const unavailable = states['sensor.docker_monitored_unavailable_count']?.state ?? '0'; + const ids = states['sensor.docker_monitored_switch_inventory']?.attributes?.entity_id; + const total = Array.isArray(ids) + ? ids.filter(id => !String(id).endsWith('_container_2')).length + : (states['sensor.docker_monitored_container_count']?.state ?? '0'); + return `${unavailable}/${total} unavailable`; + ]]] + - type: custom:auto-entities - show_empty: true + show_empty: false card: type: custom:layout-card layout_type: custom:grid-layout @@ -203,84 +241,67 @@ filter: include: - entity_id: binary_sensor.*_stack_status + state: 'off' options: type: custom:button-card template: bearstone_infra_list_row_running - icon: mdi:package-variant - state_display: > - [[[ - const base = entity.entity_id.replace('binary_sensor.', '').replace('_stack_status', ''); - const count = states[`sensor.${base}_stack_containers_count`]?.state ?? 'n/a'; - const type = String(states[`sensor.${base}_stack_type`]?.state ?? 'n/a').toUpperCase(); - const status = entity.state === 'on' ? 'RUNNING' : 'DOWN'; - return `${status} | ${count} ctrs | ${type}`; - ]]] + icon: mdi:package-variant-closed-remove + state_display: '[[[ return "STACK DOWN"; ]]]' sort: method: name -- type: grid - column_span: 4 - columns: 1 - square: false - cards: - - !include /config/dashboards/infrastructure/popups/docker_10_maintenance.yaml - - !include /config/dashboards/infrastructure/popups/docker_17_maintenance.yaml - - !include /config/dashboards/infrastructure/popups/docker_69_maintenance.yaml - - !include /config/dashboards/infrastructure/popups/docker_14_maintenance.yaml - -- type: grid - column_span: 4 - columns: 1 - square: false - cards: - - type: custom:vertical-stack-in-card - grid_options: - columns: full - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - - type: custom:button-card - template: bearstone_infra_alert_row - entity: binary_sensor.docker_container_telemetry_degraded - name: Docker telemetry degraded - icon: mdi:lan-disconnect - variables: - alert_kind: binary_on - state_display: >- - [[[ - const unavailable = states['sensor.docker_monitored_unavailable_count']?.state ?? '0'; - const total = states['sensor.docker_monitored_container_count']?.state ?? '0'; - return `${unavailable}/${total} unavailable`; - ]]] - - type: custom:auto-entities - show_empty: true - grid_options: - columns: full + show_empty: false card: type: custom:layout-card layout_type: custom:grid-layout layout: - grid-template-columns: repeat(4, minmax(0, 1fr)) + 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(2, minmax(0, 1fr)) + grid-template-columns: repeat(1, minmax(0, 1fr)) card_param: cards filter: - include: - - entity_id: "/^switch\\..*_container(_2)?$/" - options: - type: custom:button-card - template: bearstone_infra_container_row - icon: mdi:docker - exclude: - - entity_id: "/^switch\\.[0-9a-f]{12}_codex_appliance_container$/" - - entity_id: "/^switch\\.docker_files_codex_appliance_run_[0-9a-f]+_container$/" - - state: unavailable - - state: unknown + template: | + [{% for entity_id in state_attr('sensor.docker_monitored_switch_inventory', 'entity_id') or [] %} + {% if not entity_id.endswith('_container_2') and states(entity_id) == 'off' %} + {'entity': '{{ entity_id }}', + 'type': 'custom:button-card', + 'template': 'bearstone_infra_container_row', + 'icon': 'mdi:docker'}, + {% endif %} + {% endfor %}] sort: method: name + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.docker_monitored_container_count + name: Open Full Docker Inventory + icon: mdi:format-list-bulleted-square + state_display: > + [[[ + const ids = states['sensor.docker_monitored_switch_inventory']?.attributes?.entity_id; + const unique = Array.isArray(ids) + ? ids.filter(id => !String(id).endsWith('_container_2')).length + : entity.state; + return `${unique} monitored workloads`; + ]]] + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/docker-inventory + +# Existing confirmed host maintenance popups are intentionally reused. +- type: grid + column_span: 4 + columns: 1 + square: false + cards: + - !include /config/dashboards/infrastructure/popups/docker_10_maintenance.yaml + - !include /config/dashboards/infrastructure/popups/docker_17_maintenance.yaml + - !include /config/dashboards/infrastructure/popups/docker_69_maintenance.yaml + - !include /config/dashboards/infrastructure/popups/docker_14_maintenance.yaml diff --git a/config/dashboards/infrastructure/partials/docker_inventory_sections.yaml b/config/dashboards/infrastructure/partials/docker_inventory_sections.yaml new file mode 100644 index 00000000..990210a8 --- /dev/null +++ b/config/dashboards/infrastructure/partials/docker_inventory_sections.yaml @@ -0,0 +1,175 @@ +###################################################################### +# @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 - Docker inventory +# Complete stack and monitored-container inventory for drill-down use. +# ------------------------------------------------------------------- +# Notes: This partial belongs to a hidden subview; the main Docker view stays exception-first. +###################################################################### + +# ------------------------------------------------------------------- +# Inventory navigation (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_infra_list_row + entity: sensor.docker_monitored_container_count + name: Back to Docker Operations + icon: mdi:arrow-left + state_display: > + [[[ + const ids = states['sensor.docker_monitored_switch_inventory']?.attributes?.entity_id; + const unique = Array.isArray(ids) + ? ids.filter(id => !String(id).endsWith('_container_2')).length + : entity.state; + return `${unique} monitored workloads`; + ]]] + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/docker + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: sensor.docker_monitored_unavailable_count + name: Unavailable + icon: mdi:alert-circle-outline + variables: + ok_state: '0' + healthy_text: NONE + raw_suffix: UNAVAILABLE + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.docker_container_telemetry_degraded + name: Telemetry + icon: mdi:lan-check + variables: + ok_state: 'off' + +# ------------------------------------------------------------------- +# All stacks +# ------------------------------------------------------------------- +- type: grid + column_span: 4 + columns: 1 + square: false + cards: + - type: custom:vertical-stack-in-card + grid_options: + columns: full + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml + cards: + - type: custom:button-card + template: bearstone_infra_panel_header + name: Docker Stacks + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.docker_monitored_container_count + name: Stack Telemetry + icon: mdi:package-variant + state_display: > + [[[ + const count = Object.keys(states) + .filter(id => /^binary_sensor\..*_stack_status$/.test(id)).length; + return count ? `${count} stacks reported` : 'Not exposed by Portainer'; + ]]] + + - type: custom:auto-entities + show_empty: false + card: + type: custom:layout-card + 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)) + card_param: cards + filter: + include: + - entity_id: binary_sensor.*_stack_status + options: + type: custom:button-card + template: bearstone_infra_list_row_running + icon: mdi:package-variant + state_display: > + [[[ + const base = entity.entity_id.replace('binary_sensor.', '').replace('_stack_status', ''); + const count = states[`sensor.${base}_stack_containers_count`]?.state ?? 'n/a'; + const status = entity.state === 'on' ? 'RUNNING' : 'DOWN'; + return `${status} | ${count} containers`; + ]]] + sort: + method: name + +# ------------------------------------------------------------------- +# All monitored containers +# ------------------------------------------------------------------- +- type: grid + column_span: 4 + columns: 1 + square: false + cards: + - type: custom:vertical-stack-in-card + grid_options: + columns: full + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml + cards: + - type: custom:button-card + template: bearstone_infra_panel_header + name: Monitored Containers + + - type: custom:auto-entities + show_empty: true + card: + type: custom:layout-card + 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)) + card_param: cards + filter: + template: | + [{% for entity_id in state_attr('sensor.docker_monitored_switch_inventory', 'entity_id') or [] %} + {% if not entity_id.endswith('_container_2') %} + {'entity': '{{ entity_id }}', + 'type': 'custom:button-card', + 'template': 'bearstone_infra_container_row', + 'icon': 'mdi:docker'}, + {% endif %} + {% endfor %}] + sort: + method: name diff --git a/config/dashboards/infrastructure/partials/home_sections.yaml b/config/dashboards/infrastructure/partials/home_sections.yaml index 81c3dd6e..83705436 100644 --- a/config/dashboards/infrastructure/partials/home_sections.yaml +++ b/config/dashboards/infrastructure/partials/home_sections.yaml @@ -3,16 +3,99 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure Partial - Home sections -# Desktop-first infra overview: full-width hero, exceptions-first alerts. +# Infrastructure Partial - operations summary +# Exception-first health strip, active issues, datacenter, and network trends. # ------------------------------------------------------------------- -# Notes: Default/light theme only; no dark-mode specific styling. -# Notes: Keep the first section full-width to avoid whitespace on desktop. -# Notes: Excludes transient codex_appliance Portainer run containers from generic exception lists. +# Notes: Six category tiles replace the mostly empty production status panel. +# Notes: All overview trends use a 24-hour window with visible series labels. ###################################################################### # ------------------------------------------------------------------- -# Home hero (mandatory first full-width container) +# Category 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_infra_status_kpi + entity: sensor.infra_dashboard_active_issue_count + name: Overall + icon: mdi:shield-check-outline + variables: + ok_state: '0' + healthy_text: ALL CLEAR + raw_suffix: ACTIVE + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.infra_wan_quality_degraded + name: Network + icon: mdi:wan + variables: + ok_state: 'off' + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/network + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.infra_dns_pihole_degraded + name: DNS + icon: mdi:dns-outline + variables: + ok_state: 'off' + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/network + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.infra_compute_degraded + name: Compute + icon: mdi:server-network + variables: + ok_state: 'off' + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/proxmox + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.infra_storage_degraded + name: Storage + icon: mdi:database-check-outline + variables: + ok_state: 'off' + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.infra_external_monitoring_degraded + name: External + icon: mdi:web-check + variables: + ok_state: 'off' + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/network + +# ------------------------------------------------------------------- +# Active exceptions and datacenter # ------------------------------------------------------------------- - type: grid column_span: 4 @@ -34,307 +117,68 @@ grid-template-columns: repeat(1, minmax(0, 1fr)) cards: - type: custom:vertical-stack-in-card - grid_options: - columns: full card_mod: style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml cards: - type: custom:button-card template: bearstone_infra_panel_header - name: Infrastructure Status - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.joanna_ha_dispatches_24h - name: Joanna Dispatch - icon: mdi:robot - tap_action: - action: navigate - navigation_path: /dashboard-infrastructure/joanna - state_display: > - [[[ - const ha24 = states['sensor.joanna_ha_dispatches_24h']?.state ?? '0'; - const all24 = states['sensor.joanna_all_dispatches_24h']?.state ?? '0'; - const queue = states['sensor.joanna_queue_pending']?.state ?? '0'; - return `HA ${ha24} | All ${all24} | Q ${queue}`; - ]]] + name: Active Exceptions - type: custom:button-card template: bearstone_infra_list_row - name: Network - icon: mdi:access-point-network - show_state: false - tap_action: - action: none - - - type: custom:button-card - template: bearstone_infra_alert_row - entity: sensor.unifi_ap_office_clients - name: Office AP has 0 clients - icon: mdi:wifi-alert - variables: - alert_kind: ap_zero - min_age_s: 300 - - - type: custom:button-card - template: bearstone_infra_alert_row - entity: sensor.unifi_ap_study_clients - name: Study AP has 0 clients - icon: mdi:wifi-alert - variables: - alert_kind: ap_zero - min_age_s: 300 - - - type: custom:button-card - template: bearstone_infra_alert_row - entity: sensor.unifi_ap_garage_clients - name: Garage AP has 0 clients - icon: mdi:wifi-alert - variables: - alert_kind: ap_zero - min_age_s: 300 - - - type: custom:button-card - template: bearstone_infra_alert_row - entity: sensor.speedtest_download - name: Internet speed is slow - icon: mdi:speedometer-slow - variables: - alert_kind: speedtest_slow - threshold: 300 + entity: sensor.infra_dashboard_active_issue_count + name: Operations Summary + icon: mdi:shield-search state_display: > - [[[ - const dl = parseFloat(states['sensor.speedtest_download']?.state); - const ul = parseFloat(states['sensor.speedtest_upload']?.state); - const dlText = Number.isFinite(dl) ? (dl.toFixed(0) + ' Mbps') : 'n/a'; - const ulText = Number.isFinite(ul) ? (ul.toFixed(0) + ' Mbps') : 'n/a'; - return `DL ${dlText} | UL ${ulText}`; + [[[ + const count = Number(entity?.state); + if (!Number.isFinite(count)) return 'NO DATA'; + return count === 0 ? 'NO ACTIVE EXCEPTIONS' : `${count} CATEGORIES NEED ATTENTION`; ]]] - type: custom:button-card template: bearstone_infra_alert_row - entity: sensor.speedtest_ping - name: WAN latency high + entity: binary_sensor.infra_wan_quality_degraded + name: WAN quality degraded icon: mdi:wan variables: - alert_kind: disk_high - threshold: 80 - state_display: > - [[[ return `${entity.state} ms`; ]]] - - - type: custom:button-card - template: bearstone_infra_alert_row - entity: switch.pi_hole - name: DNS Pi-hole disabled - icon: mdi:dns-outline - variables: - alert_kind: binary_off - tap_action: - action: navigate - navigation_path: /dashboard-infrastructure/pihole - state_display: > - [[[ return `Switch ${entity.state}`; ]]] - - - type: custom:button-card - template: bearstone_infra_alert_row - entity: binary_sensor.pihole_status - name: DNS Pi-hole service down - icon: mdi:dns - variables: - alert_kind: binary_off + alert_kind: binary_on tap_action: action: navigate - navigation_path: /dashboard-infrastructure/pihole + navigation_path: /dashboard-infrastructure/network - type: custom:button-card template: bearstone_infra_alert_row - entity: binary_sensor.vcloudinfo_com - name: vcloudinfo.com is down - icon: mdi:web-cancel + entity: binary_sensor.infra_dns_pihole_degraded + name: Pi-hole DNS degraded + icon: mdi:dns-outline variables: - alert_kind: binary_off + alert_kind: binary_on tap_action: action: navigate - navigation_path: /dashboard-infrastructure/website-health + navigation_path: /dashboard-infrastructure/network - type: custom:button-card template: bearstone_infra_alert_row - entity: binary_sensor.www_kingcrafthomes_com - name: kingcrafthomes.com is down - icon: mdi:web-cancel + entity: binary_sensor.proxmox1_runtime_healthy + name: Proxmox01 runtime unavailable + icon: mdi:server-off variables: alert_kind: binary_off tap_action: action: navigate - navigation_path: /dashboard-infrastructure/website-health + navigation_path: /dashboard-infrastructure/proxmox - type: custom:button-card template: bearstone_infra_alert_row - entity: binary_sensor.bear_stone - name: Bear Stone is down - icon: mdi:web-cancel + entity: binary_sensor.proxmox02_runtime_healthy + name: Proxmox02 runtime unavailable + icon: mdi:server-off variables: alert_kind: binary_off tap_action: action: navigate - navigation_path: /dashboard-infrastructure/website-health - - - type: custom:button-card - template: bearstone_infra_list_row - name: Domain expiration critical - icon: mdi:domain-off - tap_action: - action: navigate - navigation_path: /dashboard-infrastructure/website-health - state_display: > - [[[ - const ids = [ - 'sensor.vcloudinfo_com_days_until_expiration', - 'sensor.kingcrafthomes_com_days_until_expiration' - ]; - let min = null; - ids.forEach((id) => { - const raw = states[id]?.state; - const n = Number(raw); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min === null) ? 'No data' : `${Math.round(min)} days remaining`; - ]]] - styles: - card: - - display: > - [[[ - const ids = [ - 'sensor.vcloudinfo_com_days_until_expiration', - 'sensor.kingcrafthomes_com_days_until_expiration' - ]; - let min = null; - ids.forEach((id) => { - const n = Number(states[id]?.state); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min !== null && min < 14) ? 'block' : 'none'; - ]]] - - - type: custom:button-card - template: bearstone_infra_list_row - name: Domain expiration warning - icon: mdi:domain - tap_action: - action: navigate - navigation_path: /dashboard-infrastructure/website-health - state_display: > - [[[ - const ids = [ - 'sensor.vcloudinfo_com_days_until_expiration', - 'sensor.kingcrafthomes_com_days_until_expiration' - ]; - let min = null; - ids.forEach((id) => { - const raw = states[id]?.state; - const n = Number(raw); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min === null) ? 'No data' : `${Math.round(min)} days remaining`; - ]]] - styles: - card: - - display: > - [[[ - const ids = [ - 'sensor.vcloudinfo_com_days_until_expiration', - 'sensor.kingcrafthomes_com_days_until_expiration' - ]; - let min = null; - ids.forEach((id) => { - const n = Number(states[id]?.state); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min !== null && min >= 14 && min < 30) ? 'block' : 'none'; - ]]] - - - type: custom:button-card - template: bearstone_infra_list_row - name: Certificate expiration critical - icon: mdi:certificate-outline - tap_action: - action: navigate - navigation_path: /dashboard-infrastructure/website-health - state_display: > - [[[ - const keys = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - /(vcloudinfo|kingcrafthomes)/.test(k) && - /(cert|ssl|tls)/.test(k) - ); - let min = null; - keys.forEach((k) => { - const n = Number(states[k]?.state); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min === null) ? 'Not available' : `${Math.round(min)} days remaining`; - ]]] - styles: - card: - - display: > - [[[ - const keys = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - /(vcloudinfo|kingcrafthomes)/.test(k) && - /(cert|ssl|tls)/.test(k) - ); - let min = null; - keys.forEach((k) => { - const n = Number(states[k]?.state); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min !== null && min < 14) ? 'block' : 'none'; - ]]] - - - type: custom:button-card - template: bearstone_infra_list_row - name: Certificate expiration warning - icon: mdi:certificate - tap_action: - action: navigate - navigation_path: /dashboard-infrastructure/website-health - state_display: > - [[[ - const keys = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - /(vcloudinfo|kingcrafthomes)/.test(k) && - /(cert|ssl|tls)/.test(k) - ); - let min = null; - keys.forEach((k) => { - const n = Number(states[k]?.state); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min === null) ? 'Not available' : `${Math.round(min)} days remaining`; - ]]] - styles: - card: - - display: > - [[[ - const keys = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - /(vcloudinfo|kingcrafthomes)/.test(k) && - /(cert|ssl|tls)/.test(k) - ); - let min = null; - keys.forEach((k) => { - const n = Number(states[k]?.state); - if (Number.isFinite(n)) min = (min === null) ? n : Math.min(min, n); - }); - return (min !== null && min >= 14 && min < 30) ? 'block' : 'none'; - ]]] - - - type: custom:button-card - template: bearstone_infra_list_row - name: System - icon: mdi:alert-circle-outline - show_state: false - tap_action: - action: none + navigation_path: /dashboard-infrastructure/proxmox - type: custom:button-card template: bearstone_infra_alert_row @@ -346,8 +190,6 @@ tap_action: action: navigate navigation_path: /dashboard-infrastructure/proxmox - state_display: > - [[[ return 'UPDATES'; ]]] - type: custom:button-card template: bearstone_infra_alert_row @@ -359,224 +201,110 @@ tap_action: action: navigate navigation_path: /dashboard-infrastructure/proxmox - state_display: > - [[[ return 'UPDATES'; ]]] - type: custom:button-card template: bearstone_infra_alert_row - entity: sensor.disk_use_percent - name: Home Assistant disk usage high - icon: mdi:harddisk + entity: binary_sensor.docker_container_telemetry_degraded + name: Docker telemetry degraded + icon: mdi:docker variables: - alert_kind: disk_high - threshold: 80 + alert_kind: binary_on state_display: > - [[[ return `${entity.state}% used`; ]]] + [[[ + const unavailable = states['sensor.docker_monitored_unavailable_count']?.state ?? '0'; + const total = states['sensor.docker_monitored_container_count']?.state ?? '0'; + return `${unavailable}/${total} unavailable`; + ]]] + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/docker - type: custom:button-card - template: bearstone_infra_list_row - name: Services - icon: mdi:docker - show_state: false - tap_action: - action: none + template: bearstone_infra_alert_row + entity: binary_sensor.infra_storage_degraded + name: Storage threshold or telemetry problem + icon: mdi:database-alert-outline + variables: + alert_kind: binary_on - type: custom:button-card template: bearstone_infra_alert_row - entity: binary_sensor.docker_container_telemetry_degraded - name: Docker telemetry degraded - icon: mdi:lan-disconnect + entity: binary_sensor.infra_website_degraded + name: Website availability degraded + icon: mdi:web-off variables: alert_kind: binary_on tap_action: action: navigate - navigation_path: /dashboard-infrastructure/docker - state_display: >- - [[[ - const unavailable = states['sensor.docker_monitored_unavailable_count']?.state ?? '0'; - const total = states['sensor.docker_monitored_container_count']?.state ?? '0'; - return `${unavailable}/${total} unavailable`; - ]]] + navigation_path: /dashboard-infrastructure/network - - type: custom:auto-entities - show_empty: false - card: - type: custom:layout-card - 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)) - card_param: cards - filter: - include: - - entity_id: "/^switch\\..*_container(_2)?$/" - options: - type: custom:button-card - template: bearstone_infra_container_row - icon: mdi:docker - exclude: - - entity_id: "/^switch\\.[0-9a-f]{12}_codex_appliance_container$/" - - entity_id: "/^switch\\.docker_files_codex_appliance_run_[0-9a-f]+_container$/" - - state: 'on' - - state: unavailable - - state: unknown + - type: custom:button-card + template: bearstone_infra_alert_row + entity: sensor.proxmox_garage_average_temperature + name: Garage compute temperature high + icon: mdi:thermometer-alert + variables: + alert_kind: numeric_high + threshold: 145 + state_display: > + [[[ return `${entity.state} °F`; ]]] + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/proxmox - - type: custom:vertical-stack-in-card - grid_options: - columns: full - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - type: custom:button-card template: bearstone_infra_panel_header - name: Datacenter + name: Network Trends + - type: custom:mini-graph-card - name: Garage Temp - icon: mdi:thermometer - hours_to_show: 96 + name: Wi-Fi Clients + icon: mdi:wifi + hours_to_show: 24 points_per_hour: 1 line_width: 2 smoothing: true show: - legend: false + legend: true labels: false name: true icon: true state: true - color_thresholds: - - value: 50 - color: '#f39c12' - - value: 120 - color: '#d35400' - - value: 145 - color: '#c0392b' entities: - - entity: sensor.proxmox_garage_average_temperature + - entity: sensor.total_wifi_clients + name: Total + show_graph: false + - entity: sensor.unifi_ap_office_clients + name: Office + - entity: sensor.unifi_ap_study_clients + name: Study + - entity: sensor.unifi_ap_garage_clients name: Garage card_mod: style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml - - type: custom:layout-card - 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:button-card - template: bearstone_infra_list_row - entity: sensor.garage_ups_status - name: UPS Status - 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 v = Number(entity?.state); - return Number.isFinite(v) ? `${v.toFixed(0)}%` : (entity?.state ?? 'unknown'); - ]]] - - - 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 secs = parseInt(entity?.state, 10); - if (!Number.isFinite(secs)) return entity?.state ?? 'unknown'; - const hours = Math.floor(secs / 3600); - const mins = Math.floor((secs % 3600) / 60); - return hours > 0 ? `${hours}h ${mins}m` : `${mins}m`; - ]]] - - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.garage_ups_status - name: On Battery - icon: mdi:battery-alert-variant-outline - state_display: > - [[[ - const s = String(entity?.state || '').toUpperCase(); - return s.includes('OB') ? 'Yes' : 'No'; - ]]] - -# ------------------------------------------------------------------- -# Overviews (desktop: 2 columns, mobile: stack) -# ------------------------------------------------------------------- -- 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 - name: Wi-Fi Overview - type: custom:mini-graph-card - name: Clients - icon: mdi:wifi + name: Internet Throughput + icon: mdi:speedometer hours_to_show: 24 - line_width: 2 points_per_hour: 1 + line_width: 2 smoothing: true show: - graph: line - legend: false + fill: false + legend: true labels: false name: true icon: true - state: true + state: false entities: - - entity: sensor.total_wifi_clients - name: Total - show_state: true - show_graph: false - show_line: false - show_points: false - show_fill: false - show_legend: false - - entity: sensor.unifi_ap_office_clients - name: Office AP - show_state: true - - entity: sensor.unifi_ap_study_clients - name: Study AP - show_state: true - - entity: sensor.unifi_ap_garage_clients - name: Garage AP - show_state: true + - entity: sensor.speedtest_download + name: Download + show_legend_state: true + - entity: sensor.speedtest_upload + name: Upload + show_legend_state: true + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml - type: custom:vertical-stack-in-card card_mod: @@ -584,23 +312,72 @@ cards: - type: custom:button-card template: bearstone_infra_panel_header - name: Internet Trend + name: Datacenter + - type: custom:mini-graph-card - name: Speedtest - icon: mdi:speedometer + name: Garage Compute Temperature + icon: mdi:thermometer hours_to_show: 24 - points_per_hour: 1 + points_per_hour: 2 line_width: 2 smoothing: true show: - fill: false legend: false labels: false name: true icon: true state: true + color_thresholds: + - value: 80 + color: '#43a047' + - value: 135 + color: '#f39c12' + - value: 145 + color: '#c0392b' entities: - - entity: sensor.speedtest_download - name: Download - - entity: sensor.speedtest_upload - name: Upload + - entity: sensor.proxmox_garage_average_temperature + name: Garage + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: sensor.garage_ups_status + name: UPS Status + 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`; + ]]] + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.garage_ups_status + name: On Battery + icon: mdi:battery-alert-variant-outline + state_display: > + [[[ + const status = String(entity?.state ?? '').toUpperCase(); + return status ? (status.includes('OB') ? 'YES' : 'NO') : 'NO DATA'; + ]]] diff --git a/config/dashboards/infrastructure/partials/joanna_sections.yaml b/config/dashboards/infrastructure/partials/joanna_sections.yaml index 99773301..ea34c5d6 100644 --- a/config/dashboards/infrastructure/partials/joanna_sections.yaml +++ b/config/dashboards/infrastructure/partials/joanna_sections.yaml @@ -3,58 +3,67 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure Partial - Joanna sections -# Joanna/BearClaw dispatch KPI, trend, latest-state, and filtered activity panels. +# Infrastructure Partial - Joanna +# Focused dispatch health, latest activity, rolling volume, and diagnostics. # ------------------------------------------------------------------- -# Notes: Reuses shared bearstone_infra_* templates and standard infra card_mod snippets. +# Notes: The large embedded logbook is replaced by a direct Activity navigation card. +# Notes: This view changes HA presentation only; BearClaw runtime behavior is untouched. ###################################################################### +# ------------------------------------------------------------------- +# Dispatch health strip (mandatory first full-width wrapper) +# ------------------------------------------------------------------- - type: grid column_span: 4 - columns: 6 + columns: 1 square: false cards: - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_ha_dispatches_24h - name: HA 24H - icon: mdi:calendar-clock - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_ha_dispatches_7d - name: HA 7D - icon: mdi:calendar-range - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_ha_dispatches_30d - name: HA 30D - icon: mdi:calendar-month - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_ha_errors_24h - name: HA Errors 24H - icon: mdi:alert-circle-outline - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.codex_reset_credits_available - name: Resets - icon: mdi:backup-restore - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_all_dispatches_24h - name: All 24H - icon: mdi:calendar-clock - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_all_dispatches_7d - name: All 7D - icon: mdi:calendar-range - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.joanna_all_dispatches_30d - name: All 30D - icon: mdi:calendar-month + - 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:button-card + template: bearstone_infra_kpi + entity: sensor.joanna_ha_dispatches_24h + name: HA 24H + icon: mdi:home-automation + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.joanna_all_dispatches_24h + name: All 24H + icon: mdi:robot + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.joanna_ha_success_rate_24h + name: HA Success + icon: mdi:percent-circle + state_display: '[[[ return `${entity.state}%`; ]]]' + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: sensor.joanna_ha_errors_24h + name: HA Errors 24H + icon: mdi:alert-circle-outline + variables: + ok_state: '0' + healthy_text: NONE + raw_suffix: ERRORS + +# ------------------------------------------------------------------- +# Trend, latest state, and reset summary +# ------------------------------------------------------------------- - type: grid column_span: 4 columns: 3 @@ -66,9 +75,10 @@ cards: - type: custom:button-card template: bearstone_infra_panel_header - name: HA Dispatch Trend + name: Dispatch Trend + - type: custom:mini-graph-card - name: HA Dispatches (24h Window) + name: HA Dispatches (24h Rolling) icon: mdi:chart-timeline-variant hours_to_show: 168 points_per_hour: 1 @@ -82,17 +92,40 @@ state: true entities: - entity: sensor.joanna_ha_dispatches_24h - name: HA 24h + name: HA Dispatches card_mod: style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.joanna_ha_dispatches_7d + name: HA Dispatches 7D + icon: mdi:calendar-range + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.joanna_ha_dispatches_30d + name: HA Dispatches 30D + icon: mdi:calendar-month + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.joanna_all_dispatches_24h + name: Open Joanna Activity + icon: mdi:timeline-text-outline + state_display: '[[[ return `${entity.state} dispatches in 24h`; ]]]' + tap_action: + action: navigate + navigation_path: /logbook?entity_id=script.joanna_dispatch + - 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 - name: Latest Snapshot + name: Latest Activity + - type: custom:button-card template: bearstone_infra_list_row entity: sensor.bearclaw_status_telemetry @@ -100,12 +133,12 @@ icon: mdi:robot state_display: > [[[ - const stats = states['sensor.bearclaw_status_telemetry']?.attributes?.dispatchStats || {}; - const latest = stats?.latest?.haAutomation || {}; - const source = latest?.source || 'none'; - const when = latest?.dispatchedAt || 'n/a'; + const latest = states['sensor.bearclaw_status_telemetry']?.attributes?.dispatchStats?.latest?.haAutomation || {}; + const source = latest.source || 'none'; + const when = latest.dispatchedAt ? String(latest.dispatchedAt).replace('T', ' ').slice(0, 16) : 'n/a'; return `${source} | ${when}`; ]]] + - type: custom:button-card template: bearstone_infra_list_row entity: sensor.bearclaw_status_telemetry @@ -113,48 +146,34 @@ icon: mdi:check-circle-outline state_display: > [[[ - const stats = states['sensor.bearclaw_status_telemetry']?.attributes?.dispatchStats || {}; - const latest = stats?.latest?.haAutomation || {}; - const state = latest?.state || 'none'; - const when = latest?.completedAt || 'n/a'; + const latest = states['sensor.bearclaw_status_telemetry']?.attributes?.dispatchStats?.latest?.haAutomation || {}; + const state = latest.state || 'none'; + const when = latest.completedAt ? String(latest.completedAt).replace('T', ' ').slice(0, 16) : 'n/a'; return `${state} | ${when}`; ]]] + - type: custom:button-card template: bearstone_infra_list_row - entity: sensor.bearclaw_status_telemetry - name: Latest Any Dispatch - icon: mdi:robot-excited - state_display: > - [[[ - const stats = states['sensor.bearclaw_status_telemetry']?.attributes?.dispatchStats || {}; - const latest = stats?.latest?.all || {}; - const source = latest?.source || 'none'; - const when = latest?.dispatchedAt || 'n/a'; - return `${source} | ${when}`; - ]]] + entity: sensor.joanna_all_dispatches_7d + name: All Dispatches 7D + icon: mdi:calendar-range + - type: custom:button-card template: bearstone_infra_list_row - entity: sensor.bearclaw_status_telemetry - name: HA Success (24h) - icon: mdi:percent-circle - state_display: > - [[[ - const v = states['sensor.joanna_ha_success_rate_24h']?.state ?? '0'; - return `${v}%`; - ]]] + entity: sensor.joanna_all_dispatches_30d + name: All Dispatches 30D + icon: mdi:calendar-month + - type: custom:button-card - template: bearstone_infra_list_row + template: bearstone_infra_status_kpi entity: binary_sensor.joanna_qmd_healthy name: QMD Health icon: mdi:heart-pulse - state_display: > - [[[ - const qmd = states['sensor.bearclaw_status_telemetry']?.attributes?.qmdHealth || {}; - const healthy = states['binary_sensor.joanna_qmd_healthy']?.state === 'on'; - const status = qmd?.status || (healthy ? 'healthy' : 'unknown'); - const failures = states['sensor.joanna_qmd_consecutive_failures']?.state ?? '0'; - return `${status} | fail ${failures}`; - ]]] + variables: + ok_state: 'on' + healthy_text: HEALTHY + alert_text: DEGRADED + - type: custom:button-card template: bearstone_infra_list_row entity: sensor.joanna_memory_docs @@ -162,21 +181,10 @@ icon: mdi:database-search state_display: > [[[ - const docs = states['sensor.joanna_memory_docs']?.state ?? '0'; + const docs = entity?.state ?? '0'; const chunks = states['sensor.joanna_memory_chunks']?.state ?? '0'; const stale = states['binary_sensor.joanna_memory_index_stale']?.state === 'on'; - return `${docs} docs | ${chunks} chunks${stale ? ' | stale' : ''}`; - ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: binary_sensor.joanna_session_source_indexed - name: Session Transcript Indexing - icon: mdi:message-text-clock-outline - state_display: > - [[[ - const enabled = states['binary_sensor.joanna_session_source_indexed']?.state === 'on'; - const age = states['sensor.joanna_minutes_since_memory_index']?.state ?? '0'; - return `${enabled ? 'enabled' : 'disabled'} | ${age} min ago`; + return `${docs} docs | ${chunks} chunks${stale ? ' | STALE' : ''}`; ]]] - type: custom:vertical-stack-in-card @@ -186,6 +194,7 @@ - type: custom:button-card template: bearstone_infra_panel_header name: Codex Reset Credits + - type: custom:button-card template: bearstone_infra_list_row entity: sensor.codex_reset_credit_status @@ -194,125 +203,90 @@ state_display: > [[[ const usage = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage || {}; - const status = usage.status || 'unknown'; - const ok = usage.ok === true; const last = usage.lastCheckAt ? String(usage.lastCheckAt).replace('T', ' ').slice(0, 16) : 'not checked'; - return `${ok ? 'ok' : status} | ${last}`; - ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.codex_reset_credit_next_expiration - name: Next Expiration - icon: mdi:calendar-clock - state_display: > - [[[ - const usage = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage || {}; - const days = usage.minDaysRemaining; - const expRaw = usage.soonestExpiresAt || ''; - const exp = expRaw ? String(expRaw).replace('T', ' ').slice(0, 16) : 'n/a'; - const dayText = Number.isFinite(Number(days)) ? `${Number(days).toFixed(1)}d` : 'n/a'; - return `${dayText} | ${exp}`; + return `${usage.ok === true ? 'ok' : (usage.status || 'unknown')} | ${last}`; ]]] + - type: custom:button-card - template: bearstone_infra_list_row + template: bearstone_infra_status_kpi entity: binary_sensor.codex_reset_credit_expiring_soon - name: Repair Window - icon: mdi:alert-clock + name: Next Expiration + icon: mdi:calendar-alert + variables: + ok_state: 'off' state_display: > [[[ - const usage = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage || {}; - const warn = usage.warnDays ?? 7; - const count = usage.warningCount ?? 0; - return `${count} within ${warn}d`; + const raw = states['sensor.codex_reset_credit_next_expiration']?.state; + const days = Number(states['sensor.codex_reset_credit_min_days_remaining']?.state); + if (!raw || raw === 'unknown' || raw === 'unavailable') return 'NO DATA'; + const when = new Date(raw).toLocaleString('en-US', { + month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit' + }); + return `${when} | ${Number.isFinite(days) ? days.toFixed(1) + ' DAYS' : ''}`; ]]] + - type: custom:button-card template: bearstone_infra_list_row - entity: sensor.bearclaw_status_telemetry - name: Reset #1 - icon: mdi:backup-restore + entity: sensor.codex_reset_credit_status + name: Reset Slot 1 + icon: mdi:numeric-1-box-outline state_display: > [[[ - const credits = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage?.credits || []; - const credit = credits[0]; - if (!credit) return 'No reset'; - const days = Number.isFinite(Number(credit.days_remaining)) ? `${Number(credit.days_remaining).toFixed(1)}d` : 'n/a'; - const exp = credit.expires_at ? String(credit.expires_at).replace('T', ' ').slice(0, 16) : 'n/a'; - return `${credit.status || 'unknown'} | ${days} | ${exp}`; + const credit = (entity?.attributes?.credits || []).find(item => Number(item.index) === 1); + if (!credit?.expires_at) return 'NO DATA'; + const when = new Date(credit.expires_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); + const days = Number(credit.days_remaining); + return `${when} | ${Number.isFinite(days) ? days.toFixed(1) + ' DAYS' : String(credit.status || '').toUpperCase()}`; ]]] + - type: custom:button-card template: bearstone_infra_list_row - entity: sensor.bearclaw_status_telemetry - name: Reset #2 - icon: mdi:backup-restore + entity: sensor.codex_reset_credit_status + name: Reset Slot 2 + icon: mdi:numeric-2-box-outline state_display: > [[[ - const credits = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage?.credits || []; - const credit = credits[1]; - if (!credit) return 'No reset'; - const days = Number.isFinite(Number(credit.days_remaining)) ? `${Number(credit.days_remaining).toFixed(1)}d` : 'n/a'; - const exp = credit.expires_at ? String(credit.expires_at).replace('T', ' ').slice(0, 16) : 'n/a'; - return `${credit.status || 'unknown'} | ${days} | ${exp}`; + const credit = (entity?.attributes?.credits || []).find(item => Number(item.index) === 2); + if (!credit?.expires_at) return 'NO DATA'; + const when = new Date(credit.expires_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); + const days = Number(credit.days_remaining); + return `${when} | ${Number.isFinite(days) ? days.toFixed(1) + ' DAYS' : String(credit.status || '').toUpperCase()}`; ]]] + - type: custom:button-card template: bearstone_infra_list_row - entity: sensor.bearclaw_status_telemetry - name: Reset #3 - icon: mdi:backup-restore + entity: sensor.codex_reset_credit_status + name: Reset Slot 3 + icon: mdi:numeric-3-box-outline state_display: > [[[ - const credits = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage?.credits || []; - const credit = credits[2]; - if (!credit) return 'No reset'; - const days = Number.isFinite(Number(credit.days_remaining)) ? `${Number(credit.days_remaining).toFixed(1)}d` : 'n/a'; - const exp = credit.expires_at ? String(credit.expires_at).replace('T', ' ').slice(0, 16) : 'n/a'; - return `${credit.status || 'unknown'} | ${days} | ${exp}`; + const credit = (entity?.attributes?.credits || []).find(item => Number(item.index) === 3); + if (!credit?.expires_at) return 'NO DATA'; + const when = new Date(credit.expires_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); + const days = Number(credit.days_remaining); + return `${when} | ${Number.isFinite(days) ? days.toFixed(1) + ' DAYS' : String(credit.status || '').toUpperCase()}`; ]]] + - type: custom:button-card template: bearstone_infra_list_row - entity: sensor.bearclaw_status_telemetry - name: Reset #4 - icon: mdi:backup-restore + entity: sensor.codex_reset_credit_status + name: Reset Slot 4 + icon: mdi:numeric-4-box-outline state_display: > [[[ - const credits = states['sensor.bearclaw_status_telemetry']?.attributes?.codexUsage?.credits || []; - const credit = credits[3]; - if (!credit) return 'No reset'; - const days = Number.isFinite(Number(credit.days_remaining)) ? `${Number(credit.days_remaining).toFixed(1)}d` : 'n/a'; - const exp = credit.expires_at ? String(credit.expires_at).replace('T', ' ').slice(0, 16) : 'n/a'; - return `${credit.status || 'unknown'} | ${days} | ${exp}`; + const credit = (entity?.attributes?.credits || []).find(item => Number(item.index) === 4); + if (!credit?.expires_at) return 'NO DATA'; + const when = new Date(credit.expires_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); + const days = Number(credit.days_remaining); + return `${when} | ${Number.isFinite(days) ? days.toFixed(1) + ' DAYS' : String(credit.status || '').toUpperCase()}`; ]]] -- 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 - grid_options: - columns: full - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - - type: custom:button-card - template: bearstone_infra_panel_header - name: Joanna Activity - # Fallback card: Lovelace logbook card is required to show filtered activity history. - - type: logbook - hours_to_show: 72 - entities: - - automation.bearclaw_reply_webhook - - automation.codex_reset_credit_expiry_repair - - automation.tugtainer_dispatch_joanna_for_available_updates - - binary_sensor.codex_reset_credit_expiring_soon - - script.joanna_dispatch + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.joanna_session_source_indexed + name: Transcript Indexing + icon: mdi:message-text-clock-outline + variables: + ok_state: 'on' + healthy_text: ENABLED + alert_text: DISABLED diff --git a/config/dashboards/infrastructure/partials/mariadb_sections.yaml b/config/dashboards/infrastructure/partials/mariadb_sections.yaml index 0bbfa549..4dc2012c 100644 --- a/config/dashboards/infrastructure/partials/mariadb_sections.yaml +++ b/config/dashboards/infrastructure/partials/mariadb_sections.yaml @@ -3,149 +3,289 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure Partial - mariadb sections -# Reusable list extracted from a view for smaller diffs and safer edits. +# Infrastructure Partial - MariaDB +# Humanized KPIs, seven-day capacity trends, recorder health, and tuning. # ------------------------------------------------------------------- -# Notes: Stitch-inspired MariaDB layout (KPI strip + 3 panel columns). +# Notes: Database growth, ingest rate, and connections use consistent 168-hour graphs. ###################################################################### +# ------------------------------------------------------------------- +# Humanized KPI strip (mandatory first full-width wrapper) +# ------------------------------------------------------------------- - type: grid column_span: 4 - columns: 4 - square: false - cards: - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.database_size - name: DB Size - icon: mdi:database - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.database_tables_count - name: Tables - icon: mdi:table - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_connections - name: Conn. - icon: mdi:lan-connect - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_uptime - name: Uptime - icon: mdi:timer-outline - -- type: grid - column_span: 4 - columns: 3 + columns: 1 square: false 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 - name: Database Statistics - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.database_total_records - name: Total Records - icon: mdi:counter - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.database_records_per_day - name: Records per Day - icon: mdi:chart-line - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.database_oldest_record - name: Oldest Record - icon: mdi:clock-start - - - type: custom:vertical-stack-in-card - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml + - 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:button-card - template: bearstone_infra_panel_header - name: MariaDB Status - - type: custom:button-card - template: bearstone_infra_list_row_running - entity: sensor.mariadb_status - name: Server Status + template: bearstone_infra_kpi + entity: sensor.database_size + name: Database Size icon: mdi:database state_display: > [[[ - if (entity.state === 'unknown') return 'Unknown'; - return String(entity.state).toUpperCase(); + const mib = Number(entity?.state); + return Number.isFinite(mib) ? `${(mib / 1024).toFixed(1)} GiB` : 'NO DATA'; ]]] + - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.mariadb_version - name: Version - icon: mdi:information-outline + template: bearstone_infra_kpi + entity: sensor.database_tables_count + name: Tables + icon: mdi:table + - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.mariadb_performance - name: Performance - icon: mdi:chart-line + template: bearstone_infra_kpi + entity: sensor.mariadb_connections + name: Connections + icon: mdi:lan-connect + - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.mariadb_questions - name: Total Queries - icon: mdi:database-search + template: bearstone_infra_kpi + entity: sensor.mariadb_uptime + name: Uptime + icon: mdi:timer-outline + state_display: > + [[[ + const seconds = Number(entity?.state); + if (!Number.isFinite(seconds)) return 'NO DATA'; + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + return `${days}d ${hours}h`; + ]]] - - type: custom:vertical-stack-in-card +# ------------------------------------------------------------------- +# Capacity and workload trends +# ------------------------------------------------------------------- +- type: grid + column_span: 4 + columns: 3 + square: false + cards: + - type: custom:mini-graph-card + name: Database Growth + icon: mdi:database-arrow-up + hours_to_show: 168 + points_per_hour: 0.25 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + entities: + - entity: sensor.database_size + name: Database Size + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:mini-graph-card + name: Recorder Ingest Rate + icon: mdi:chart-line + hours_to_show: 168 + points_per_hour: 0.25 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + entities: + - entity: sensor.database_records_per_day + name: Records per Day + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:mini-graph-card + name: Active Connections + icon: mdi:lan-connect + hours_to_show: 168 + points_per_hour: 0.25 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + entities: + - entity: sensor.mariadb_connections + name: Connections card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + +# ------------------------------------------------------------------- +# Recorder and server health +# ------------------------------------------------------------------- +- 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: dense + 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_infra_panel_header - name: MariaDB Tuning - - type: grid - columns: 2 - square: false + - 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_kpi - entity: sensor.mariadb_buffer_pool_size - name: InnoDB Buffer - icon: mdi:memory + template: bearstone_infra_panel_header + name: Recorder Health + - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_max_connections - name: Max Conn. - icon: mdi:account-multiple + template: bearstone_infra_list_row + entity: sensor.database_total_records + name: Total Records + icon: mdi:counter + - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_log_file_size - name: Log File - icon: mdi:file + template: bearstone_infra_list_row + entity: sensor.database_records_per_day + name: Records per Day + icon: mdi:chart-line + - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_tmp_table_size - name: Temp Size - icon: mdi:table + template: bearstone_infra_list_row + entity: sensor.database_oldest_record + name: Oldest Retained Record + icon: mdi:clock-start + + - 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_kpi - entity: sensor.mariadb_io_capacity - name: IO Capacity - icon: mdi:speedometer + template: bearstone_infra_panel_header + name: MariaDB Status + - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_io_threads - name: IO Threads - icon: mdi:developer-board + template: bearstone_infra_list_row_running + entity: sensor.mariadb_status + name: Server Status + icon: mdi:database-check + state_display: '[[[ return String(entity.state ?? "NO DATA").toUpperCase(); ]]]' + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.mariadb_version + name: Version + icon: mdi:information-outline + - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_table_cache - name: Table Cache - icon: mdi:cached + template: bearstone_infra_list_row + entity: sensor.mariadb_performance + name: Query Rate + icon: mdi:speedometer + - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.mariadb_buffer_sizes - name: Sort/Join - icon: mdi:code-brackets + template: bearstone_infra_list_row + entity: sensor.mariadb_questions + name: Total Queries + icon: mdi:database-search + +# ------------------------------------------------------------------- +# Static tuning reference +# ------------------------------------------------------------------- +- 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: dense + 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_infra_panel_header + name: MariaDB Tuning Reference + view_layout: + grid-column: 1 / -1 + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_buffer_pool_size + name: InnoDB Buffer + icon: mdi:memory + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_max_connections + name: Max Connections + icon: mdi:account-multiple + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_log_file_size + name: Log File + icon: mdi:file + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_tmp_table_size + name: Temp Table Size + icon: mdi:table + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_io_capacity + name: IO Capacity + icon: mdi:speedometer + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_io_threads + name: IO Threads + icon: mdi:developer-board + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_table_cache + name: Table Cache + icon: mdi:cached + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.mariadb_buffer_sizes + name: Sort / Join + icon: mdi:code-brackets diff --git a/config/dashboards/infrastructure/partials/network_sections.yaml b/config/dashboards/infrastructure/partials/network_sections.yaml new file mode 100644 index 00000000..18edde56 --- /dev/null +++ b/config/dashboards/infrastructure/partials/network_sections.yaml @@ -0,0 +1,315 @@ +###################################################################### +# @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 - Network, DNS, and external services +# Current WAN telemetry, dual Pi-hole operations, and website health. +# ------------------------------------------------------------------- +# Notes: Pi-hole blocking controls are mirrored by pihole_ha.yaml. +# Notes: Detailed Pi-hole and website telemetry live in hidden drill-down views. +###################################################################### + +# ------------------------------------------------------------------- +# Current network health +# ------------------------------------------------------------------- +- 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_infra_status_kpi + entity: binary_sensor.infra_wan_quality_degraded + name: WAN + icon: mdi:wan + variables: + ok_state: 'off' + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.speedtest_download + name: Download + icon: mdi:download-network-outline + state_display: > + [[[ + const value = Number(entity?.state); + const unit = entity?.attributes?.unit_of_measurement ?? 'Mbit/s'; + return Number.isFinite(value) ? `${value.toFixed(0)} ${unit}` : 'NO DATA'; + ]]] + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.speedtest_upload + name: Upload + icon: mdi:upload-network-outline + state_display: > + [[[ + const value = Number(entity?.state); + const unit = entity?.attributes?.unit_of_measurement ?? 'Mbit/s'; + return Number.isFinite(value) ? `${value.toFixed(0)} ${unit}` : 'NO DATA'; + ]]] + + - type: custom:button-card + template: bearstone_infra_kpi + entity: sensor.speedtest_ping + name: Latency + icon: mdi:timer-outline + state_display: > + [[[ + const value = Number(entity?.state); + const unit = entity?.attributes?.unit_of_measurement ?? 'ms'; + return Number.isFinite(value) ? `${value.toFixed(1)} ${unit}` : 'NO DATA'; + ]]] + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.pi_hole_status + name: Primary DNS + icon: mdi:pi-hole + variables: + ok_state: 'on' + healthy_text: RUNNING + alert_text: DOWN + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.pi_hole_status_2 + name: Secondary DNS + icon: mdi:pi-hole + variables: + ok_state: 'on' + healthy_text: RUNNING + alert_text: DOWN + +# ------------------------------------------------------------------- +# Trends, Pi-hole controls, and website health +# ------------------------------------------------------------------- +- 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: 1200px)": + grid-template-columns: repeat(2, minmax(0, 1fr)) + "(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 + name: Internet + + - type: custom:mini-graph-card + name: Internet Throughput + icon: mdi:speedometer + hours_to_show: 24 + points_per_hour: 1 + line_width: 2 + smoothing: true + show: + fill: false + legend: true + labels: false + name: true + icon: true + state: false + entities: + - entity: sensor.speedtest_download + name: Download + show_legend_state: true + - entity: sensor.speedtest_upload + name: Upload + show_legend_state: true + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.speedtest_ping + name: Current Latency + icon: mdi:wan + state_display: > + [[[ + const value = Number(entity?.state); + const unit = entity?.attributes?.unit_of_measurement ?? 'ms'; + return Number.isFinite(value) ? `${value.toFixed(1)} ${unit}` : '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 + name: Pi-hole DNS + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.pi_hole_status + name: Primary Service + icon: mdi:dns + state_display: > + [[[ return entity?.state === 'on' ? 'RUNNING' : 'DOWN'; ]]] + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: switch.pi_hole + name: Primary Blocking + icon: mdi:shield-check-outline + state_display: > + [[[ return entity?.state === 'on' ? 'ENABLED' : 'DISABLED'; ]]] + tap_action: + action: toggle + confirmation: + text: Toggle Pi-hole blocking? Home Assistant mirrors this setting to both DNS nodes. + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.pi_hole_status_2 + name: Secondary Service + icon: mdi:dns + state_display: > + [[[ return entity?.state === 'on' ? 'RUNNING' : 'DOWN'; ]]] + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: switch.pi_hole_2 + name: Secondary Blocking + icon: mdi:shield-check-outline + state_display: > + [[[ return entity?.state === 'on' ? 'ENABLED' : 'DISABLED'; ]]] + tap_action: + action: toggle + confirmation: + text: Toggle Pi-hole blocking? Home Assistant mirrors this setting to both DNS nodes. + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.infra_nebula_sync_dns_consistency + name: Primary / Secondary Sync + icon: mdi:database-sync-outline + state_display: > + [[[ return String(entity?.state ?? 'NO DATA').toUpperCase(); ]]] + + - type: custom:button-card + template: bearstone_infra_list_row + entity: binary_sensor.infra_dns_pihole_degraded + name: Open Detailed Pi-hole Analytics + icon: mdi:chart-box-outline + state_display: > + [[[ return 'OPEN'; ]]] + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/pihole + + - 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 + name: Website Health + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.vcloudinfo_com + name: vcloudinfo.com + icon: mdi:web + state_display: > + [[[ return entity?.state === 'on' ? 'UP' : String(entity?.state ?? 'NO DATA').toUpperCase(); ]]] + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.www_kingcrafthomes_com + name: kingcrafthomes.com + icon: mdi:web + state_display: > + [[[ return entity?.state === 'on' ? 'UP' : String(entity?.state ?? 'NO DATA').toUpperCase(); ]]] + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.bear_stone + name: Bear Stone + icon: mdi:web-check + state_display: > + [[[ return entity?.state === 'on' ? 'UP' : String(entity?.state ?? 'NO DATA').toUpperCase(); ]]] + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.infra_website_down_count + name: Monitoring Coverage + icon: mdi:cloud-check-outline + state_display: > + [[[ + const down = Number(entity?.state); + if (!Number.isFinite(down)) return 'NO DATA'; + return `${3 - down}/3 MONITORS UP`; + ]]] + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.ipmer_com_days_until_expiration + name: Next Domain Expiry + icon: mdi:calendar-clock + state_display: > + [[[ + const domains = [ + ['vcloudinfo.com', 'sensor.vcloudinfo_com_days_until_expiration', 'sensor.vcloudinfo_com_expires'], + ['ipmer.com', 'sensor.ipmer_com_days_until_expiration', 'sensor.ipmer_com_expires'], + ['kingcraftshomes.com', 'sensor.kingcrafthomes_com_days_until_expiration', 'sensor.kingcrafthomes_com_expires'], + ]; + const candidates = domains + .map(([name, daysId, expiresId]) => ({ + name, + days: Number(states[daysId]?.state), + expires: String(states[expiresId]?.state ?? ''), + })) + .filter((item) => Number.isFinite(item.days)) + .sort((a, b) => a.days - b.days); + if (!candidates.length) return 'NO DATA'; + const next = candidates[0]; + const date = /^\d{4}-\d{2}-\d{2}/.test(next.expires) + ? next.expires.slice(0, 10) + : 'DATE UNKNOWN'; + return `${next.name.toUpperCase()} | ${Math.round(next.days)} DAYS | ${date}`; + ]]] + + - type: custom:button-card + template: bearstone_infra_list_row + entity: binary_sensor.infra_website_degraded + name: Open Website Details + icon: mdi:chart-box-outline + state_display: > + [[[ return 'OPEN'; ]]] + tap_action: + action: navigate + navigation_path: /dashboard-infrastructure/website-health diff --git a/config/dashboards/infrastructure/partials/pihole_detail_sections.yaml b/config/dashboards/infrastructure/partials/pihole_detail_sections.yaml new file mode 100644 index 00000000..dfc57235 --- /dev/null +++ b/config/dashboards/infrastructure/partials/pihole_detail_sections.yaml @@ -0,0 +1,50 @@ +###################################################################### +# @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 - Pi-hole detail drill-down +# Large analytics cards for both primary and secondary DNS nodes. +# ------------------------------------------------------------------- +# Notes: Kept out of the primary Network view to preserve dense operations layout. +###################################################################### + +- 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: 1200px)": + 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 + name: Primary DNS + - type: custom:pi-hole + device_id: d69637da16f7d7f3626070582be59808 + + - 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 + name: Secondary DNS + - type: custom:pi-hole + device_id: e6ca0f9504eaa7908cc84b5d77571d61 + diff --git a/config/dashboards/infrastructure/partials/pihole_sections.yaml b/config/dashboards/infrastructure/partials/pihole_sections.yaml deleted file mode 100644 index 318b1e92..00000000 --- a/config/dashboards/infrastructure/partials/pihole_sections.yaml +++ /dev/null @@ -1,26 +0,0 @@ -###################################################################### -# @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 - Pi-hole sections -# Dedicated full-width Pi-hole panel. -# ------------------------------------------------------------------- -# Notes: Uses `custom:pi-hole` with existing device_id. -###################################################################### - -- type: grid - column_span: 4 - columns: 1 - square: false - cards: - - type: custom:vertical-stack-in-card - grid_options: - columns: full - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - - type: custom:pi-hole - device_id: d69637da16f7d7f3626070582be59808 - grid_options: - columns: full diff --git a/config/dashboards/infrastructure/partials/proxmox_sections.yaml b/config/dashboards/infrastructure/partials/proxmox_sections.yaml index 4219aa79..789441df 100644 --- a/config/dashboards/infrastructure/partials/proxmox_sections.yaml +++ b/config/dashboards/infrastructure/partials/proxmox_sections.yaml @@ -3,191 +3,347 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure Partial - proxmox sections -# Reusable list extracted from a view for smaller diffs and safer edits. +# Infrastructure Partial - Proxmox +# Runtime/update status with one-metric host, VM, and temperature trends. # ------------------------------------------------------------------- -# Related Issue: 1584 -# Notes: Standardized on `custom:button-card` + `custom:mini-graph-card` with `card_mod` polish. +# Notes: All graphs use 24-hour windows and explicit threshold colors. +# Notes: Pending updates remain windowed maintenance signals, not runtime failures. ###################################################################### +# ------------------------------------------------------------------- +# Host status strip (mandatory first full-width wrapper) +# ------------------------------------------------------------------- - type: grid column_span: 4 - columns: 6 + columns: 1 square: false cards: - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.node_proxmox1_cpu_used - name: P1 CPU - icon: mdi:cpu-64-bit - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.node_proxmox1_memory_used_percentage - name: P1 MEM - icon: mdi:memory - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.proxmox1_disk_used_percentage - name: P1 DISK - icon: mdi:harddisk - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.node_proxmox02_cpu_used - name: P2 CPU - icon: mdi:cpu-64-bit - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.node_proxmox02_memory_used_percentage - name: P2 MEM - icon: mdi:memory - - type: custom:button-card - template: bearstone_infra_kpi - entity: sensor.proxmox02_disk_used_percentage - name: P2 DISK - icon: mdi:harddisk + - 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:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.proxmox1_runtime_healthy + name: Proxmox01 Runtime + icon: mdi:server + variables: + ok_state: 'on' + healthy_text: ONLINE + alert_text: OFFLINE + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.proxmox02_runtime_healthy + name: Proxmox02 Runtime + icon: mdi:server + variables: + ok_state: 'on' + healthy_text: ONLINE + alert_text: OFFLINE + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.node_proxmox1_updates_packages + name: Proxmox01 Updates + icon: mdi:package-up + variables: + ok_state: 'off' + healthy_text: CURRENT + alert_text: PENDING + + - type: custom:button-card + template: bearstone_infra_status_kpi + entity: binary_sensor.node_proxmox02_updates_packages + name: Proxmox02 Updates + icon: mdi:package-up + variables: + ok_state: 'off' + healthy_text: CURRENT + alert_text: PENDING + +# ------------------------------------------------------------------- +# Host resource trends +# ------------------------------------------------------------------- - type: grid column_span: 4 - columns: 2 + columns: 1 square: false cards: - - type: custom:button-card - template: bearstone_infra_list_row_running - entity: binary_sensor.proxmox1_runtime_healthy - name: Proxmox01 Runtime - icon: mdi:server - state_display: > - [[[ return entity.state === 'on' ? 'ONLINE' : 'OFFLINE'; ]]] - - type: custom:button-card - template: bearstone_infra_list_row_running - entity: binary_sensor.proxmox02_runtime_healthy - name: Proxmox02 Runtime - icon: mdi:server - state_display: > - [[[ return entity.state === 'on' ? 'ONLINE' : 'OFFLINE'; ]]] + - 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: dense + 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 + name: Proxmox01 + + - type: custom:mini-graph-card + name: CPU Utilization + icon: mdi:cpu-64-bit + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + 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.node_proxmox1_cpu_used + name: CPU + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + - type: custom:mini-graph-card + name: Memory Utilization + icon: mdi:memory + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + color_thresholds: + - value: 0 + color: '#43a047' + - value: 70 + color: '#f39c12' + - value: 90 + color: '#c0392b' + entities: + - entity: sensor.node_proxmox1_memory_used_percentage + name: Memory + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:mini-graph-card + name: Disk Utilization + icon: mdi:harddisk + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + color_thresholds: + - value: 0 + color: '#43a047' + - value: 70 + color: '#f39c12' + - value: 85 + color: '#c0392b' + entities: + - entity: sensor.proxmox1_disk_used_percentage + name: Disk + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - 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 + name: Proxmox02 + + - type: custom:mini-graph-card + name: CPU Utilization + icon: mdi:cpu-64-bit + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + 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.node_proxmox02_cpu_used + name: CPU + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:mini-graph-card + name: Memory Utilization + icon: mdi:memory + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + color_thresholds: + - value: 0 + color: '#43a047' + - value: 70 + color: '#f39c12' + - value: 90 + color: '#c0392b' + entities: + - entity: sensor.node_proxmox02_memory_used_percentage + name: Memory + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + + - type: custom:mini-graph-card + name: Disk Utilization + icon: mdi:harddisk + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: false + labels: false + name: true + icon: true + state: true + color_thresholds: + - value: 0 + color: '#43a047' + - value: 70 + color: '#f39c12' + - value: 85 + color: '#c0392b' + entities: + - entity: sensor.proxmox02_disk_used_percentage + name: Disk + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + +# ------------------------------------------------------------------- +# VM and thermal trends (same-unit series only) +# ------------------------------------------------------------------- - type: grid column_span: 4 columns: 3 square: false cards: - - type: custom:vertical-stack-in-card + - type: custom:mini-graph-card + name: VM CPU Utilization + icon: mdi:chart-line + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: true + labels: false + name: true + icon: true + state: false + entities: + - entity: sensor.qemu_docker69_169_cpu_used + name: Docker69 + - entity: sensor.qemu_carlo_hass_105_cpu_used + name: Home Assistant + - entity: sensor.qemu_docker2_101_cpu_used + name: Frigate card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - - type: custom:button-card - template: bearstone_infra_panel_header - name: Proxmox01 - - type: custom:mini-graph-card - name: Host CPU / Memory / Disk - icon: mdi:server - hours_to_show: 24 - points_per_hour: 2 - line_width: 2 - animate: true - show: - fill: true - legend: false - icon: true - name: true - state: true - entities: - - entity: sensor.node_proxmox1_cpu_used - name: CPU - - entity: sensor.node_proxmox1_memory_used_percentage - name: Memory - - entity: sensor.proxmox1_disk_used_percentage - name: Disk - - type: custom:mini-graph-card - name: VMs CPU / Memory - icon: mdi:chart-line - hours_to_show: 24 - points_per_hour: 2 - line_width: 2 - animate: true - show: - fill: false - legend: false - icon: true - name: true - state: false - entities: - - entity: sensor.qemu_docker69_169_cpu_used - name: Docker69 CPU - - entity: sensor.qemu_docker69_169_memory_used_percentage - name: Docker69 MEM - - entity: sensor.qemu_carlo_hass_105_cpu_used - name: HASS CPU - - entity: sensor.qemu_carlo_hass_105_memory_used_percentage - name: HASS MEM + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml - - type: custom:vertical-stack-in-card + - type: custom:mini-graph-card + name: VM Memory Utilization + icon: mdi:memory + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: true + labels: false + name: true + icon: true + state: false + entities: + - entity: sensor.qemu_docker69_169_memory_used_percentage + name: Docker69 + - entity: sensor.qemu_carlo_hass_105_memory_used_percentage + name: Home Assistant + - entity: sensor.qemu_docker2_101_memory_used_percentage + name: Frigate card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - - type: custom:button-card - template: bearstone_infra_panel_header - name: Proxmox02 - - type: custom:mini-graph-card - name: Host CPU / Memory / Disk - icon: mdi:server - hours_to_show: 24 - points_per_hour: 2 - line_width: 2 - animate: true - show: - fill: true - legend: false - icon: true - name: true - state: true - entities: - - entity: sensor.node_proxmox02_cpu_used - name: CPU - - entity: sensor.node_proxmox02_memory_used_percentage - name: Memory - - entity: sensor.proxmox02_disk_used_percentage - name: Disk - - type: custom:mini-graph-card - name: Frigate VM CPU / Memory - icon: mdi:video - hours_to_show: 24 - points_per_hour: 2 - line_width: 2 - animate: true - show: - fill: false - legend: false - icon: true - name: true - state: false - entities: - - entity: sensor.qemu_docker2_101_cpu_used - name: CPU - - entity: sensor.qemu_docker2_101_memory_used_percentage - name: MEM + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml - - type: custom:vertical-stack-in-card + - type: custom:mini-graph-card + name: Garage Temperature + icon: mdi:thermometer + hours_to_show: 24 + points_per_hour: 2 + line_width: 2 + smoothing: true + show: + legend: true + labels: false + name: true + icon: true + state: true + color_thresholds: + - value: 80 + color: '#43a047' + - value: 135 + color: '#f39c12' + - value: 145 + color: '#c0392b' + entities: + - entity: sensor.proxmox_garage_average_temperature + name: Garage + - entity: sensor.pirateweather_temperature + name: Outside card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml - cards: - - type: custom:button-card - template: bearstone_infra_panel_header - name: Garage Temp - - type: custom:mini-graph-card - entities: - - entity: sensor.proxmox_garage_average_temperature - name: Garage - - entity: sensor.pirateweather_temperature - name: Outside - name: Garage Temp - hours_to_show: 96 - color_thresholds: - - value: 50 - color: '#f39c12' - - value: 120 - color: '#d35400' - - value: 145 - color: '#c0392b' - card_mod: - style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml + style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml diff --git a/config/dashboards/infrastructure/partials/website_health_sections.yaml b/config/dashboards/infrastructure/partials/website_health_sections.yaml index 4841a26e..8bb584c0 100644 --- a/config/dashboards/infrastructure/partials/website_health_sections.yaml +++ b/config/dashboards/infrastructure/partials/website_health_sections.yaml @@ -3,15 +3,14 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure Partial - Website health sections -# Website uptime + response windows + domain expiry telemetry view. +# Infrastructure Partial - Website health +# Current UptimeRobot availability, domain registration, and actionable exceptions. # ------------------------------------------------------------------- -# Related Issue: 1584 -# Notes: Uses direct Uptime Kuma entities (no aggregate uptime min sensors). +# Notes: The installed UptimeRobot integration exposes current monitor state, not Kuma-style rollups. ###################################################################### # ------------------------------------------------------------------- -# Website hero (mandatory first full-width container) +# Current health and domain registration (mandatory first full-width wrapper) # ------------------------------------------------------------------- - type: grid column_span: 4 @@ -33,233 +32,116 @@ grid-template-columns: repeat(1, minmax(0, 1fr)) cards: - type: custom:vertical-stack-in-card - grid_options: - columns: full card_mod: style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml cards: - type: custom:button-card template: bearstone_infra_panel_header - name: Website Uptime - - type: custom:layout-card - 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:button-card - template: bearstone_infra_list_row_running - entity: binary_sensor.vcloudinfo_com - name: vcloudinfo.com - icon: mdi:web - state_display: > - [[[ return entity.state === 'on' ? 'UP' : (entity.state || 'unknown').toUpperCase(); ]]] - - type: custom:button-card - template: bearstone_infra_list_row_running - entity: binary_sensor.www_kingcrafthomes_com - name: kingcrafthomes.com - icon: mdi:web - state_display: > - [[[ return entity.state === 'on' ? 'UP' : (entity.state || 'unknown').toUpperCase(); ]]] - - type: custom:button-card - template: bearstone_infra_list_row_running - entity: binary_sensor.bear_stone - name: Bear Stone - icon: mdi:web-check - state_display: > - [[[ return entity.state === 'on' ? 'UP' : (entity.state || 'unknown').toUpperCase(); ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: binary_sensor.vcloudinfo_com - name: vcloudinfo.com uptime - icon: mdi:chart-line - state_display: > - [[[ - const pick = (metric, window) => { - const suffix = `${metric}_${window}`; - const candidates = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - k.includes('vcloudinfo_com') && - k.endsWith(suffix) - ); - const eid = candidates[0]; - return eid ? (states[eid]?.state ?? 'n/a') : 'n/a'; - }; - const uptime1d = pick('uptime', '1d'); - const uptime30d = pick('uptime', '30d'); - const uptime365d = pick('uptime', '365d'); - return `1d ${uptime1d}% | 30d ${uptime30d}% | 365d ${uptime365d}%`; - ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: binary_sensor.vcloudinfo_com - name: vcloudinfo.com response - icon: mdi:timer-outline - state_display: > - [[[ - const pick = (metric, window) => { - const suffix = `${metric}_${window}`; - const candidates = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - k.includes('vcloudinfo_com') && - k.endsWith(suffix) - ); - const eid = candidates[0]; - return eid ? (states[eid]?.state ?? 'n/a') : 'n/a'; - }; - const r1d = pick('avg_response_time', '1d'); - const r30d = pick('avg_response_time', '30d'); - const r365d = pick('avg_response_time', '365d'); - return `1d ${r1d}s | 30d ${r30d}s | 365d ${r365d}s`; - ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: binary_sensor.www_kingcrafthomes_com - name: kingcrafthomes.com uptime - icon: mdi:chart-line - state_display: > - [[[ - const pick = (metric, window) => { - const suffix = `${metric}_${window}`; - const candidates = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - (k.includes('kingcrafthomes_com') || k.includes('www_kingcrafthomes_com')) && - k.endsWith(suffix) - ); - const eid = candidates[0]; - return eid ? (states[eid]?.state ?? 'n/a') : 'n/a'; - }; - const uptime1d = pick('uptime', '1d'); - const uptime30d = pick('uptime', '30d'); - const uptime365d = pick('uptime', '365d'); - return `1d ${uptime1d}% | 30d ${uptime30d}% | 365d ${uptime365d}%`; - ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: binary_sensor.www_kingcrafthomes_com - name: kingcrafthomes.com response - icon: mdi:timer-outline - state_display: > - [[[ - const pick = (metric, window) => { - const suffix = `${metric}_${window}`; - const candidates = Object.keys(states).filter((k) => - k.startsWith('sensor.') && - (k.includes('kingcrafthomes_com') || k.includes('www_kingcrafthomes_com')) && - k.endsWith(suffix) - ); - const eid = candidates[0]; - return eid ? (states[eid]?.state ?? 'n/a') : 'n/a'; - }; - const r1d = pick('avg_response_time', '1d'); - const r30d = pick('avg_response_time', '30d'); - const r365d = pick('avg_response_time', '365d'); - return `1d ${r1d}s | 30d ${r30d}s | 365d ${r365d}s`; - ]]] + name: Current Website Health + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.vcloudinfo_com + name: vcloudinfo.com + icon: mdi:web + state_display: '[[[ return entity.state === "on" ? "UP" : String(entity.state || "unknown").toUpperCase(); ]]]' + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.www_kingcrafthomes_com + name: kingcrafthomes.com + icon: mdi:web + state_display: '[[[ return entity.state === "on" ? "UP" : String(entity.state || "unknown").toUpperCase(); ]]]' + + - type: custom:button-card + template: bearstone_infra_list_row_running + entity: binary_sensor.bear_stone + name: Bear Stone + icon: mdi:web-check + state_display: '[[[ return entity.state === "on" ? "UP" : String(entity.state || "unknown").toUpperCase(); ]]]' + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.infra_website_down_count + name: Monitoring Coverage + icon: mdi:cloud-check-outline + state_display: > + [[[ + const down = Number(entity?.state); + if (!Number.isFinite(down)) return 'NO DATA'; + return `${3 - down}/3 CURRENT MONITORS UP`; + ]]] - type: custom:vertical-stack-in-card - grid_options: - columns: full card_mod: style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml cards: - type: custom:button-card template: bearstone_infra_panel_header - name: Domain Expiry - - type: custom:layout-card - 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:button-card - template: bearstone_infra_list_row - entity: sensor.vcloudinfo_com_days_until_expiration - name: vcloudinfo.com - icon: mdi:calendar-clock - state_display: > - [[[ - const days = states['sensor.vcloudinfo_com_days_until_expiration']?.state ?? 'n/a'; - const expRaw = states['sensor.vcloudinfo_com_expires']?.state; - let exp = 'n/a'; - const s = String(expRaw ?? ''); - if (s && !['unknown','unavailable','none',''].includes(s.toLowerCase())) { - if (/^\d{4}-\d{2}-\d{2}/.test(s)) { - exp = s.slice(0, 10); - } else { - const dt = new Date(s); - if (!Number.isNaN(dt.getTime())) { - const y = dt.getFullYear(); - const m = String(dt.getMonth() + 1).padStart(2, '0'); - const d = String(dt.getDate()).padStart(2, '0'); - exp = `${y}-${m}-${d}`; - } - } - } - return `${days}d | ${exp}`; - ]]] - - type: custom:button-card - template: bearstone_infra_list_row - entity: sensor.kingcrafthomes_com_days_until_expiration - name: kingcrafthomes.com - icon: mdi:calendar-clock - state_display: > - [[[ - const days = states['sensor.kingcrafthomes_com_days_until_expiration']?.state ?? 'n/a'; - const expRaw = states['sensor.kingcrafthomes_com_expires']?.state; - let exp = 'n/a'; - const s = String(expRaw ?? ''); - if (s && !['unknown','unavailable','none',''].includes(s.toLowerCase())) { - if (/^\d{4}-\d{2}-\d{2}/.test(s)) { - exp = s.slice(0, 10); - } else { - const dt = new Date(s); - if (!Number.isNaN(dt.getTime())) { - const y = dt.getFullYear(); - const m = String(dt.getMonth() + 1).padStart(2, '0'); - const d = String(dt.getDate()).padStart(2, '0'); - exp = `${y}-${m}-${d}`; - } - } - } - return `${days}d | ${exp}`; - ]]] + name: Domain Registration Expiration + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.vcloudinfo_com_days_until_expiration + name: vcloudinfo.com + icon: mdi:calendar-clock + state_display: '[[[ return `${entity.state} days`; ]]]' + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.ipmer_com_days_until_expiration + name: ipmer.com + icon: mdi:calendar-clock + state_display: '[[[ return `${entity.state} days`; ]]]' + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.kingcrafthomes_com_days_until_expiration + name: kingcrafthomes.com + icon: mdi:calendar-clock + state_display: '[[[ return `${entity.state} days`; ]]]' + +# ------------------------------------------------------------------- +# Actionable exceptions +# ------------------------------------------------------------------- - type: grid column_span: 4 - columns: 3 + columns: 1 square: false cards: - - type: custom:button-card - template: bearstone_infra_alert_row - entity: binary_sensor.infra_website_degraded - name: Website status degraded - icon: mdi:web-off - variables: - alert_kind: binary_on - - type: custom:button-card - template: bearstone_infra_alert_row - entity: binary_sensor.infra_website_uptime_slo_breach - name: Uptime SLO breach - icon: mdi:alert-decagram - variables: - alert_kind: binary_on - - type: custom:button-card - template: bearstone_infra_alert_row - entity: binary_sensor.infra_website_latency_degraded - name: Website latency degraded - icon: mdi:timer-alert - variables: - alert_kind: binary_on + - type: custom:vertical-stack-in-card + grid_options: + columns: full + card_mod: + style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml + cards: + - type: custom:button-card + template: bearstone_infra_panel_header + name: Website Exceptions + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.infra_website_down_count + name: Current Availability Summary + icon: mdi:web-check + state_display: > + [[[ + const count = Number(entity?.state); + if (!Number.isFinite(count)) return 'NO DATA'; + return count === 0 ? 'ALL MONITORS UP' : `${count} MONITORS DOWN`; + ]]] + + - type: custom:button-card + template: bearstone_infra_alert_row + entity: binary_sensor.infra_website_degraded + name: Website availability degraded + icon: mdi:web-off + variables: + alert_kind: binary_on + + - type: custom:button-card + template: bearstone_infra_list_row + entity: sensor.infra_website_down_count + name: Telemetry Scope + icon: mdi:information-outline + state_display: '[[[ return "CURRENT UP/DOWN | UPTIMEROBOT"; ]]]' diff --git a/config/dashboards/infrastructure/templates/button_card_templates.yaml b/config/dashboards/infrastructure/templates/button_card_templates.yaml index 704f6de8..b1766b61 100644 --- a/config/dashboards/infrastructure/templates/button_card_templates.yaml +++ b/config/dashboards/infrastructure/templates/button_card_templates.yaml @@ -731,6 +731,8 @@ bearstone_infra_docker_volume_row: return `${value.toFixed(precision)} MiB`; }; + if (variables?.not_instrumented === true) return 'Not instrumented'; + const totalEntity = variables && variables.total_entity ? states[variables.total_entity] : entity; @@ -784,7 +786,7 @@ bearstone_infra_alert_row: if (kind === 'binary_on') show = (stateStr === 'on'); else if (kind === 'binary_off') show = (stateStr === 'off'); else if (kind === 'ap_zero') show = (stateStr === '0' && ageS >= minAge); - else if (kind === 'disk_high') { + else if (kind === 'disk_high' || kind === 'numeric_high') { const v = parseFloat(stateStr); show = Number.isFinite(v) && (thr !== null ? (v > thr) : (v > 80)); } else if (kind === 'speedtest_slow') { @@ -889,3 +891,152 @@ bearstone_infra_kpi: - font-size: 16px - font-weight: 800 - opacity: 0.9 + +bearstone_infra_status_kpi: + template: bearstone_infra_kpi + state_display: > + [[[ + const raw = String(entity?.state ?? '').toLowerCase(); + const unavailable = ['unknown', 'unavailable', 'none', ''].includes(raw); + const okState = String(variables?.ok_state ?? 'off').toLowerCase(); + if (unavailable) return 'NO DATA'; + if (raw === okState) return variables?.healthy_text ?? 'HEALTHY'; + if (variables?.alert_text) return variables.alert_text; + if (variables?.raw_suffix) return `${entity.state} ${variables.raw_suffix}`; + return 'ATTENTION'; + ]]] + styles: + card: + - border-color: > + [[[ + const raw = String(entity?.state ?? '').toLowerCase(); + const okState = String(variables?.ok_state ?? 'off').toLowerCase(); + if (['unknown', 'unavailable', 'none', ''].includes(raw)) return 'rgba(245,124,0,0.45)'; + return raw === okState ? 'rgba(67,160,71,0.45)' : 'rgba(229,57,53,0.40)'; + ]]] + - background: > + [[[ + const raw = String(entity?.state ?? '').toLowerCase(); + const okState = String(variables?.ok_state ?? 'off').toLowerCase(); + if (['unknown', 'unavailable', 'none', ''].includes(raw)) return 'rgba(255,243,224,0.85)'; + return raw === okState ? 'rgba(232,245,233,0.85)' : 'rgba(255,235,238,0.85)'; + ]]] + icon: + - color: > + [[[ + const raw = String(entity?.state ?? '').toLowerCase(); + const okState = String(variables?.ok_state ?? 'off').toLowerCase(); + if (['unknown', 'unavailable', 'none', ''].includes(raw)) return 'rgba(245,124,0,1)'; + return raw === okState ? 'rgba(46,125,50,1)' : 'rgba(198,40,40,1)'; + ]]] + state: + - color: > + [[[ + const raw = String(entity?.state ?? '').toLowerCase(); + const okState = String(variables?.ok_state ?? 'off').toLowerCase(); + if (['unknown', 'unavailable', 'none', ''].includes(raw)) return 'rgba(230,81,0,1)'; + return raw === okState ? 'rgba(46,125,50,1)' : 'rgba(198,40,40,1)'; + ]]] + - opacity: 1 + +bearstone_infra_update_row: + template: bearstone_infra_list_row + icon: mdi:package-up + show_label: true + variables: + apt_severity: > + [[[ + const state = String(entity?.state ?? '').toUpperCase(); + if (!state || state.includes('UNKNOWN') || state.includes('UNAVAILABLE') || state.includes('ERROR')) return 'error'; + const host = entity?.entity_id?.match(/^sensor\.(docker_\d+)_apt_status$/)?.[1]; + const dueRaw = host ? states[`input_datetime.apt_${host}_action_due`]?.state : null; + const due = dueRaw && !['unknown', 'unavailable', 'none'].includes(String(dueRaw).toLowerCase()) + ? new Date(String(dueRaw).replace(' ', 'T')) + : null; + const actionable = state.includes('PENDING') || state.includes('REBOOT REQ'); + if (actionable && due instanceof Date && !Number.isNaN(due.getTime()) && Date.now() > due.getTime()) return 'overdue'; + if (actionable) return 'scheduled'; + if (state.includes('NO UPDATES') || state.includes('UPDATED')) return 'healthy'; + return 'neutral'; + ]]] + state_display: > + [[[ return String(entity?.state ?? 'NO DATA').toUpperCase(); ]]] + label: > + [[[ + const state = String(entity?.state ?? '').toUpperCase(); + const host = entity?.entity_id?.match(/^sensor\.(docker_\d+)_apt_status$/)?.[1]; + const dueRaw = host ? states[`input_datetime.apt_${host}_action_due`]?.state : null; + const parseDate = (raw) => { + if (!raw || ['unknown', 'unavailable', 'none', ''].includes(String(raw).toLowerCase())) return null; + const value = new Date(String(raw).replace(' ', 'T')); + return Number.isNaN(value.getTime()) ? null : value; + }; + const formatTime = (value) => value.toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit' + }).toUpperCase(); + const formatDue = (value) => { + const weekday = value.toLocaleDateString('en-US', { weekday: 'short' }).toUpperCase(); + return `${weekday} ${formatTime(value)}`; + }; + const actionable = state.includes('PENDING') || state.includes('REBOOT REQ'); + const due = parseDate(dueRaw); + if (actionable) { + const action = state.includes('REBOOT REQ') ? 'REBOOT' : 'UPDATE'; + return due ? `${action} ${formatDue(due)}` : `${action} SCHEDULED`; + } + return 'NO ACTION SCHEDULED'; + ]]] + styles: + grid: + - grid-template-areas: '"i n s" "i l l"' + - grid-template-columns: 24px 1fr auto + - grid-template-rows: min-content min-content + card: + - border-color: > + [[[ + if (variables.apt_severity === 'overdue') return 'rgba(229,57,53,0.40)'; + if (variables.apt_severity === 'error' || variables.apt_severity === 'scheduled') return 'rgba(245,124,0,0.45)'; + if (variables.apt_severity === 'healthy') return 'rgba(67,160,71,0.45)'; + return 'var(--divider-color)'; + ]]] + - background: > + [[[ + if (variables.apt_severity === 'overdue') return 'rgba(255,235,238,0.85)'; + if (variables.apt_severity === 'error' || variables.apt_severity === 'scheduled') return 'rgba(255,243,224,0.85)'; + if (variables.apt_severity === 'healthy') return 'rgba(232,245,233,0.85)'; + return 'rgba(0,0,0,0.02)'; + ]]] + icon: + - color: > + [[[ + if (variables.apt_severity === 'overdue') return 'rgba(198,40,40,1)'; + if (variables.apt_severity === 'error' || variables.apt_severity === 'scheduled') return 'rgba(230,81,0,1)'; + if (variables.apt_severity === 'healthy') return 'rgba(46,125,50,1)'; + return 'var(--primary-color)'; + ]]] + state: + - color: > + [[[ + if (variables.apt_severity === 'overdue') return 'rgba(198,40,40,1)'; + if (variables.apt_severity === 'error' || variables.apt_severity === 'scheduled') return 'rgba(230,81,0,1)'; + if (variables.apt_severity === 'healthy') return 'rgba(46,125,50,1)'; + return 'var(--secondary-text-color)'; + ]]] + label: + - grid-area: l + - justify-self: start + - padding-top: 3px + - font-size: 11px + - font-weight: 700 + - letter-spacing: 0.02em + - opacity: 0.72 + - white-space: normal + - text-align: left + - color: > + [[[ + if (variables.apt_severity === 'overdue') return 'rgba(198,40,40,1)'; + if (variables.apt_severity === 'error' || variables.apt_severity === 'scheduled') return 'rgba(230,81,0,1)'; + if (variables.apt_severity === 'healthy') return 'rgba(46,125,50,1)'; + return 'var(--secondary-text-color)'; + ]]] diff --git a/config/dashboards/infrastructure/views/01_home.yaml b/config/dashboards/infrastructure/views/01_home.yaml index 7c22b5a0..b0868577 100644 --- a/config/dashboards/infrastructure/views/01_home.yaml +++ b/config/dashboards/infrastructure/views/01_home.yaml @@ -3,10 +3,10 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure View - Home -# Clean layout inspired by Stitch wireframe (hosts, right-rail trends, storage, wifi, apt). +# Infrastructure View - operations summary +# Compact category health, active exceptions, datacenter, and network trends. # ------------------------------------------------------------------- -# Notes: Uses existing Infrastructure entities from Proxmox/UniFi/UPS/Docker hosts. +# Notes: Production exception-first Infrastructure home view. ###################################################################### title: Infrastructure @@ -15,6 +15,7 @@ type: sections icon: mdi:view-dashboard-variant theme: default max_columns: 4 +dense_section_placement: true badges: [] sections: !include /config/dashboards/infrastructure/partials/home_sections.yaml cards: [] diff --git a/config/dashboards/infrastructure/views/02_proxmox.yaml b/config/dashboards/infrastructure/views/02_proxmox.yaml index e8fd3fe5..5f05e70a 100644 --- a/config/dashboards/infrastructure/views/02_proxmox.yaml +++ b/config/dashboards/infrastructure/views/02_proxmox.yaml @@ -3,18 +3,19 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure View - ProxMox -# YAML-exported Lovelace dashboard (split into view files). +# Infrastructure View - Proxmox +# Host health and one-metric trends without duplicate KPI reporting. # ------------------------------------------------------------------- -# Notes: Exported from config/.storage/lovelace.dashboard_infrastructure view index 1. +# Notes: All graphs use a consistent 24-hour window. ###################################################################### title: ProxMox path: proxmox -cards: [] type: sections icon: mdi:server theme: default +max_columns: 4 +dense_section_placement: true badges: [] sections: !include /config/dashboards/infrastructure/partials/proxmox_sections.yaml -max_columns: 4 +cards: [] diff --git a/config/dashboards/infrastructure/views/03_docker_containers.yaml b/config/dashboards/infrastructure/views/03_docker_containers.yaml index 4184f20f..6e3b3696 100644 --- a/config/dashboards/infrastructure/views/03_docker_containers.yaml +++ b/config/dashboards/infrastructure/views/03_docker_containers.yaml @@ -3,12 +3,10 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure View - Docker containers -# Related Issue: 1560, 1725 -# Container status + restart controls (Portainer integration). +# Infrastructure View - Docker +# Exception-first host, update, volume, and workload health. # ------------------------------------------------------------------- -# Notes: Uses `binary_sensor.*_status` and `button.*_restart_container` entities (Portainer integration). -# Notes: 2026.5 Portainer volume prune controls are exposed through confirmed host maintenance popups; kill/recreate buttons are intentionally not exposed broadly. +# Notes: Complete healthy inventory is available from the hidden Docker Inventory subview. ###################################################################### title: Docker @@ -16,6 +14,8 @@ path: docker type: sections icon: mdi:docker theme: default +max_columns: 4 +dense_section_placement: true badges: [] sections: !include /config/dashboards/infrastructure/partials/docker_containers_sections.yaml -max_columns: 4 +cards: [] diff --git a/config/dashboards/infrastructure/views/04_network.yaml b/config/dashboards/infrastructure/views/04_network.yaml new file mode 100644 index 00000000..9414e97e --- /dev/null +++ b/config/dashboards/infrastructure/views/04_network.yaml @@ -0,0 +1,21 @@ +###################################################################### +# @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 - Network and External Services +# Combined WAN telemetry, dual Pi-hole operations, and website health. +# ------------------------------------------------------------------- +# Notes: Detailed Pi-hole and website telemetry use hidden drill-down subviews. +###################################################################### + +title: Network +path: network +type: sections +icon: mdi:wan +theme: default +max_columns: 4 +dense_section_placement: true +badges: [] +sections: !include /config/dashboards/infrastructure/partials/network_sections.yaml +cards: [] diff --git a/config/dashboards/infrastructure/views/04_pihole.yaml b/config/dashboards/infrastructure/views/04_pihole.yaml index dfd4d917..24fbc57f 100644 --- a/config/dashboards/infrastructure/views/04_pihole.yaml +++ b/config/dashboards/infrastructure/views/04_pihole.yaml @@ -3,17 +3,20 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure View - Pi-hole -# Dedicated Pi-hole view after Docker. +# Infrastructure Subview - Pi-hole Detail +# Large analytics and controls for both DNS nodes. # ------------------------------------------------------------------- -# Notes: Full-width sections layout for Pi-hole telemetry/control card. +# Notes: Hidden drill-down reached from the combined Network view. ###################################################################### -title: Pi-hole +title: Pi-hole Details path: pihole type: sections -icon: mdi:pi-hole +subview: true +back_path: /dashboard-infrastructure/network theme: default -badges: [] -sections: !include /config/dashboards/infrastructure/partials/pihole_sections.yaml max_columns: 4 +dense_section_placement: true +badges: [] +sections: !include /config/dashboards/infrastructure/partials/pihole_detail_sections.yaml +cards: [] diff --git a/config/dashboards/infrastructure/views/05_mariadb.yaml b/config/dashboards/infrastructure/views/05_mariadb.yaml index f53bbe6c..cab4e931 100644 --- a/config/dashboards/infrastructure/views/05_mariadb.yaml +++ b/config/dashboards/infrastructure/views/05_mariadb.yaml @@ -4,17 +4,18 @@ # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- # Infrastructure View - MariaDB -# YAML-exported Lovelace dashboard (split into view files). +# Humanized KPIs, recorder health, capacity trends, and tuning details. # ------------------------------------------------------------------- -# Notes: Exported from config/.storage/lovelace.dashboard_infrastructure view index 5. +# Notes: Trend cards use a consistent seven-day window. ###################################################################### -type: sections title: MariaDB path: mariadb -max_columns: 4 +type: sections icon: mdi:database theme: default +max_columns: 4 +dense_section_placement: true badges: [] sections: !include /config/dashboards/infrastructure/partials/mariadb_sections.yaml cards: [] diff --git a/config/dashboards/infrastructure/views/06_joanna.yaml b/config/dashboards/infrastructure/views/06_joanna.yaml index 27f0af79..87732c54 100644 --- a/config/dashboards/infrastructure/views/06_joanna.yaml +++ b/config/dashboards/infrastructure/views/06_joanna.yaml @@ -4,20 +4,18 @@ # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- # Infrastructure View - Joanna -# Dispatch and activity telemetry for BearClaw/Joanna. +# Focused dispatch health, latest activity, diagnostics, and reset status. # ------------------------------------------------------------------- -# Notes: Uses telemetry from /api/bearclaw/status ingested by bearclaw.yaml. -# Notes: Shows Codex reset-credit expiry data from the codexUsage status field. -# Notes: Codex reset walkthrough: https://youtu.be/7wKhtrvtyiI -# Notes: Codex reset companion post: https://www.vcloudinfo.com/2026/06/track-codex-resets-home-assistant.html +# Notes: Replaces the unbounded embedded logbook with a direct Activity link. ###################################################################### -type: sections title: Joanna path: joanna -max_columns: 4 +type: sections icon: mdi:robot theme: default +max_columns: 4 +dense_section_placement: true badges: [] sections: !include /config/dashboards/infrastructure/partials/joanna_sections.yaml cards: [] diff --git a/config/dashboards/infrastructure/views/07_website_health.yaml b/config/dashboards/infrastructure/views/07_website_health.yaml index 1f4a3739..d27fc70f 100644 --- a/config/dashboards/infrastructure/views/07_website_health.yaml +++ b/config/dashboards/infrastructure/views/07_website_health.yaml @@ -3,18 +3,20 @@ # For more info visit https://www.vcloudinfo.com/click-here # Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig # ------------------------------------------------------------------- -# Infrastructure View - Website Health -# Website uptime + domain expiry + certificate telemetry details. +# Infrastructure Subview - Website Details +# Current uptime, registration expiry, and actionable exceptions. # ------------------------------------------------------------------- -# Notes: Home view surfaces only exceptions; this view carries detail. +# Notes: Hidden drill-down reached from the combined Network view. ###################################################################### -title: Website Health +title: Website Details path: website-health type: sections -icon: mdi:web-check +subview: true +back_path: /dashboard-infrastructure/network theme: default +max_columns: 4 +dense_section_placement: true badges: [] sections: !include /config/dashboards/infrastructure/partials/website_health_sections.yaml -max_columns: 4 cards: [] diff --git a/config/dashboards/infrastructure/views/08_docker_inventory.yaml b/config/dashboards/infrastructure/views/08_docker_inventory.yaml new file mode 100644 index 00000000..2ec9292b --- /dev/null +++ b/config/dashboards/infrastructure/views/08_docker_inventory.yaml @@ -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 Subview - Docker Inventory +# Full stack and container inventory separated from the operational view. +# ------------------------------------------------------------------- +# Notes: Hidden subview reached from the Docker exceptions panel. +###################################################################### + +title: Docker Inventory +path: docker-inventory +type: sections +subview: true +icon: mdi:format-list-bulleted-square +theme: default +max_columns: 4 +dense_section_placement: true +badges: [] +sections: !include /config/dashboards/infrastructure/partials/docker_inventory_sections.yaml +cards: [] diff --git a/config/dashboards/overview/partials/home_sections.yaml b/config/dashboards/overview/partials/home_sections.yaml index c88a0fd7..10fd34d6 100644 --- a/config/dashboards/overview/partials/home_sections.yaml +++ b/config/dashboards/overview/partials/home_sections.yaml @@ -24,6 +24,7 @@ not_home: grayscale(100%) opacity(50%) Justin Dorm: grayscale(10%) opacity(50%) Paige Home: grayscale(10%) opacity(50%) + Joyce Home: grayscale(100%) opacity(50%) driving: grayscale(100%) opacity(50%) - type: picture-entity entity: person.stacey @@ -35,6 +36,7 @@ not_home: grayscale(100%) opacity(50%) Justin Dorm: grayscale(10%) opacity(50%) Paige Home: grayscale(10%) opacity(50%) + Joyce Home: grayscale(100%) opacity(50%) gym: grayscale(100%) opacity(50%) driving: grayscale(100%) opacity(50%) - type: picture-entity @@ -47,6 +49,7 @@ not_home: grayscale(100%) opacity(50%) Justin Dorm: grayscale(10%) opacity(50%) Paige Home: grayscale(10%) opacity(50%) + Joyce Home: grayscale(100%) opacity(50%) gym: grayscale(100%) opacity(50%) driving: grayscale(100%) opacity(50%) - type: picture-entity @@ -60,6 +63,7 @@ paige_work: grayscale(100%) opacity(50%) Justin Dorm: grayscale(10%) opacity(50%) Paige Home: grayscale(10%) opacity(50%) + Joyce Home: grayscale(100%) opacity(50%) gym: grayscale(100%) opacity(50%) driving: grayscale(100%) opacity(50%) columns: 4