feat: surface BearClaw health and diagnostics

pull/1898/head
Carlo Costanzo 2 months ago
parent cabad62ca0
commit 89d12ee1e7

@ -0,0 +1,38 @@
######################################################################
# @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 - AI Diagnostics
# Shows the current instruction and response pair for request tracing.
# -------------------------------------------------------------------
# Notes: Included by config/dashboards/infrastructure/views/06b_ai_diagnostics.yaml.
######################################################################
- type: grid
column_span: 4
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: AI Diagnostics
- type: markdown
title: Response Received from OpenAI
content: >-
{{ state_attr('sensor.openai_response', 'response') or 'No response available.' }}
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml
# Core markdown is required because long templated diagnostic payloads cannot be rendered safely by the shared button-card templates.
- type: markdown
title: Instructions Sent to OpenAI
content: >-
{{ state_attr('sensor.openai_instructions', 'instructions') or 'No instructions available.' }}
card_mod:
style: !include /config/dashboards/infrastructure/card_mod/infra_card.yaml

@ -1,354 +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 - Joanna Activity
# Latest 12 dispatches from BearClaw's rolling 24-hour runtime history.
# -------------------------------------------------------------------
# Notes: Rows intentionally read the dispatchActivity status attribute so the count and detail share one source of truth.
######################################################################
# -------------------------------------------------------------------
# Dispatch summary
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(4, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(2, minmax(0, 1fr))
cards:
- type: custom:button-card
template: bearstone_infra_kpi
entity: sensor.joanna_all_dispatches_24h
name: All Jobs · 24H
icon: mdi:robot
- type: custom:button-card
template: bearstone_infra_kpi
entity: sensor.joanna_ha_dispatches_24h
name: HA Jobs · 24H
icon: mdi:home-automation
- type: custom:button-card
template: bearstone_infra_kpi
entity: sensor.joanna_queue_pending
name: Queue
icon: mdi:playlist-clock
- 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
# -------------------------------------------------------------------
# Recent dispatches
# -------------------------------------------------------------------
- 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: Most Recent Dispatches
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 0
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No dispatches in 24 hours';
return String(item.source || 'unknown')
.replace(/^home_assistant_automation\./, 'HA · ')
.replace(/^scheduler_/, 'Scheduled · ')
.replace(/^manual_/, 'Manual · ')
.replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 1
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 2
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 3
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 4
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 5
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- 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: Earlier Today
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 6
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 7
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 8
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 9
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 10
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]
- type: custom:button-card
template: bearstone_infra_list_row
entity: sensor.bearclaw_status_telemetry
icon: mdi:robot-outline
variables:
activity_index: 11
name: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'No additional dispatches';
return String(item.source || 'unknown').replace(/^home_assistant_automation\./, 'HA · ').replace(/^scheduler_/, 'Scheduled · ').replace(/^manual_/, 'Manual · ').replaceAll('_', ' ');
]]]
state_display: >
[[[
const item = entity?.attributes?.dispatchActivity?.items?.[variables?.activity_index];
if (!item) return 'NO ACTIVITY';
const state = String(item.state || 'queued').replaceAll('_', ' ').toUpperCase();
const when = item.dispatchedAt ? new Date(item.dispatchedAt).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : 'N/A';
return `${state} · ${when}`;
]]]

@ -6,7 +6,7 @@
# Infrastructure Partial - Joanna
# Focused dispatch health, latest activity, rolling volume, and diagnostics.
# -------------------------------------------------------------------
# Notes: The activity drill-down reads the same rolling 24-hour runtime job history as the dispatch counters.
# Notes: BearClaw Admin provides the detailed runtime drill-down while this page stays summary-focused.
# Notes: This view changes HA presentation only; BearClaw runtime behavior is untouched.
# Notes: Reset expiry is amber within 7 days and red within 3 days; the four reset slots remain visible.
######################################################################
@ -111,13 +111,13 @@
- 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`; ]]]'
entity: sensor.bearclaw_status_telemetry
name: BearClaw Admin
icon: mdi:shield-crown-outline
state_display: OPEN ADMIN
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/joanna-activity
action: url
url_path: http://192.168.10.13:8124/admin
- type: custom:vertical-stack-in-card
card_mod:
@ -166,14 +166,14 @@
icon: mdi:calendar-month
- type: custom:button-card
template: bearstone_infra_status_kpi
entity: binary_sensor.joanna_qmd_healthy
name: QMD Health
icon: mdi:heart-pulse
variables:
ok_state: 'on'
healthy_text: HEALTHY
alert_text: DEGRADED
template: bearstone_infra_list_row
entity: sensor.openai_response
name: AI Diagnostics
icon: mdi:message-text-outline
state_display: OPEN RESPONSE
tap_action:
action: navigate
navigation_path: /dashboard-infrastructure/ai-diagnostics
- type: custom:button-card
template: bearstone_infra_list_row
@ -245,7 +245,6 @@
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.codex_reset_credit_status
@ -287,13 +286,3 @@
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_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

@ -1222,15 +1222,57 @@ bearstone_overview_sleep_summary:
bearstone_health_kpi:
template: bearstone_infra_kpi
variables:
detail_layout: false
styles:
grid:
- grid-template-areas: >
[[[
return variables?.detail_layout
? '"i" "n" "s" "l"'
: '"i" "n" "s"';
]]]
- grid-template-columns: minmax(0, 1fr)
- grid-template-rows: >
[[[
return variables?.detail_layout
? '22px min-content min-content minmax(18px, auto)'
: '22px min-content min-content';
]]]
name:
- font-size: 12px
- font-weight: 900
- opacity: 0.8
- justify-self: stretch
- width: 100%
- min-width: 0
- white-space: normal
- overflow: visible
- text-overflow: clip
- line-height: 15px
state:
- font-size: 17px
- font-weight: 900
- opacity: 1
- justify-self: stretch
- width: 100%
- min-width: 0
- white-space: normal
- overflow: visible
- text-overflow: clip
- line-height: 22px
label:
- font-size: 12px
- font-weight: 600
- opacity: 0.78
- justify-self: stretch
- width: 100%
- min-width: 0
- white-space: normal
- overflow: visible
- text-overflow: clip
- text-align: center
- line-height: 16px
bearstone_infra_update_row:
template: bearstone_infra_list_row

@ -6,7 +6,7 @@
# Infrastructure View - Joanna
# Focused dispatch health, latest activity, diagnostics, and reset status.
# -------------------------------------------------------------------
# Notes: Replaces the unbounded embedded logbook with a direct Activity link.
# Notes: BearClaw Admin owns detailed runtime history; this view stays summary-focused.
######################################################################
title: Joanna

@ -3,20 +3,20 @@
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Infrastructure Subview - Joanna Activity
# Latest runtime dispatches from the same 24-hour source as the counters.
# Infrastructure View - AI Diagnostics
# Compact diagnostic surface for the most recent OpenAI response.
# -------------------------------------------------------------------
# Notes: Hidden drill-down reached from the Joanna Dispatch Trend card.
# Notes: The Joanna AI Diagnostics row is the canonical entry point.
######################################################################
title: Joanna Activity
path: joanna-activity
type: sections
title: AI Diagnostics
path: ai-diagnostics
subview: true
back_path: /dashboard-infrastructure/joanna
icon: mdi:message-text-outline
theme: default
type: sections
max_columns: 4
dense_section_placement: true
badges: []
sections: !include /config/dashboards/infrastructure/partials/joanna_activity_sections.yaml
sections: !include /config/dashboards/infrastructure/partials/ai_diagnostics_sections.yaml
cards: []

@ -1,71 +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
# -------------------------------------------------------------------
# Overview Partial - admin sections
# Reusable list extracted from a view for smaller diffs and safer edits.
# -------------------------------------------------------------------
# Notes: Extracted from config/dashboards/overview/views/08_admin.yaml key `sections`.
######################################################################
- type: grid
cards:
- type: tile
entity: automation.llm_vision_garage_cans_upper_right
- type: tile
entity: input_text.llmvision_garbage_last_keyframe
- type: tile
entity: input_datetime.llmvision_garbage_last_run
- type: tile
entity: input_text.llmvision_garbage_last_response
- type: tile
entity: calendar.llm_vision_timeline
- type: tile
entity: update.llm_vision_update
- type: tile
entity: input_button.llmvision_garbage_check
- type: tile
entity: binary_sensor.front_door_packages_present
- type: tile
entity: input_text.llmvision_front_door_last_response
- type: tile
entity: input_datetime.llmvision_front_door_last_run
- type: tile
entity: input_text.llmvision_front_door_last_keyframe
- type: tile
entity: input_button.llmvision_front_door_package_check
- type: grid
cards:
- type: markdown
title: AI Diagnostics
content: '**OpenAI Response:**
{{ state_attr(''sensor.openai_response'', ''response'') }}
'
- type: markdown
title: AI Diagnostics
content: '**OpenAI Instructions:**
{{ state_attr(''sensor.openai_instructions'', ''instructions'') }}
'
- type: grid
cards:
- camera_view: auto
type: picture-glance
title: Bedroom Tablet
image: https://demo.home-assistant.io/stub_config/kitchen.png
entities:
- entity: switch.alarm_panel_1_screensaver
image_entity: image.alarm_panel_1_screenshot
- camera_view: auto
type: picture-glance
title: Bedroom Tablet
image: https://demo.home-assistant.io/stub_config/kitchen.png
entities:
- entity: sensor.alarm_panel_1_battery
camera_image: camera.alarm_panel_1

@ -4,11 +4,12 @@
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Overview Partial - Health
# Current SleepIQ state, paired nightly trends, and native bed controls.
# Current SleepIQ state, Joanna achievements and steps, paired nightly trends, and native bed controls.
# -------------------------------------------------------------------
# Notes: Daily maximum statistics suppress SleepIQ's between-session zero states.
# Notes: Direct integration entities are reused; no dashboard helper state is added.
# Notes: The ribbon prioritizes occupancy, firmness, and current session duration.
# Notes: Step cards use each person's authoritative daily source with completed-day 7d averages and prior 28d/90d baselines.
######################################################################
# -------------------------------------------------------------------
@ -103,6 +104,120 @@
return `${Math.floor(value)}h ${Math.round((value % 1) * 60)}m`;
]]]
# -------------------------------------------------------------------
# HealthKit steps and personal records
# -------------------------------------------------------------------
- type: grid
column_span: 4
columns: 1
square: false
cards:
- type: custom:layout-card
grid_options:
columns: full
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(4, minmax(0, 1fr))
grid-auto-flow: row
grid-auto-rows: min-content
grid-gap: 12px
margin: 0
mediaquery:
"(max-width: 900px)":
grid-template-columns: repeat(2, minmax(0, 1fr))
cards:
- type: custom:button-card
template: bearstone_health_kpi
entity: sensor.joanna_carlo_steps_trend
name: Carlo Steps - 7d Avg
icon: mdi:walk
show_label: true
variables:
detail_layout: true
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${Math.round(value).toLocaleString()} / day` : 'NO DATA';
]]]
label: >
[[[
const attrs = entity?.attributes || {};
const value = (averageKey, samplesKey, windowDays) => {
const raw = attrs[averageKey];
const number = raw === null || raw === undefined || raw === '' ? NaN : Number(raw);
if (!Number.isFinite(number)) return '—';
const samples = Number(attrs[samplesKey] || 0);
const coverage = samples > 0 && samples < windowDays ? ` (${samples}d)` : '';
return `${Math.round(number).toLocaleString()}${coverage}`;
};
return `28d ${value('prior_28d_average', 'prior_28d_samples', 28)} · 90d ${value('prior_90d_average', 'prior_90d_samples', 90)}`;
]]]
- type: custom:button-card
template: bearstone_health_kpi
entity: sensor.joanna_stacey_steps_trend
name: Stacey Steps - 7d Avg
icon: mdi:walk
show_label: true
variables:
detail_layout: true
state_display: >
[[[
const value = Number(entity?.state);
return Number.isFinite(value) ? `${Math.round(value).toLocaleString()} / day` : 'NO DATA';
]]]
label: >
[[[
const attrs = entity?.attributes || {};
const value = (averageKey, samplesKey, windowDays) => {
const raw = attrs[averageKey];
const number = raw === null || raw === undefined || raw === '' ? NaN : Number(raw);
if (!Number.isFinite(number)) return '—';
const samples = Number(attrs[samplesKey] || 0);
const coverage = samples > 0 && samples < windowDays ? ` (${samples}d)` : '';
return `${Math.round(number).toLocaleString()}${coverage}`;
};
return `28d ${value('prior_28d_average', 'prior_28d_samples', 28)} · 90d ${value('prior_90d_average', 'prior_90d_samples', 90)}`;
]]]
- type: custom:button-card
template: bearstone_health_kpi
entity: sensor.joanna_carlo_latest_personal_record
name: Carlo Personal Record
icon: mdi:trophy-outline
show_label: true
variables:
detail_layout: true
state_display: >
[[[
return entity?.attributes?.display_value || 'NO RECORDS';
]]]
label: >
[[[
const attrs = entity?.attributes || {};
const pieces = [entity?.state, attrs.activity_type, attrs.achieved_on].filter((value) => value && value !== 'unknown');
return pieces.join(' · ') || 'Stored HealthKit history';
]]]
- type: custom:button-card
template: bearstone_health_kpi
entity: sensor.joanna_stacey_latest_personal_record
name: Stacey Personal Record
icon: mdi:trophy-outline
show_label: true
variables:
detail_layout: true
state_display: >
[[[
return entity?.attributes?.display_value || 'NO RECORDS';
]]]
label: >
[[[
const attrs = entity?.attributes || {};
const pieces = [entity?.state, attrs.activity_type, attrs.achieved_on].filter((value) => value && value !== 'unknown');
return pieces.join(' · ') || 'Stored HealthKit history';
]]]
# -------------------------------------------------------------------
# Fourteen-night paired trends
# -------------------------------------------------------------------

@ -4,10 +4,11 @@
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Overview View - health
# SleepIQ health metrics view for Carlo and Stacey.
# SleepIQ and Joanna health insights for Carlo and Stacey.
# -------------------------------------------------------------------
# Related Issue: 1584
# Notes: Promoted from the approved Health pilot; personal health remains with Overview.
# Notes: Joanna supplies shared personal records and completed-day 7d vs 28d vs 90d step trends.
######################################################################
title: Health

@ -1,18 +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
# -------------------------------------------------------------------
# Overview View - Admin
# YAML-exported Lovelace dashboard (split into view files).
# -------------------------------------------------------------------
# Notes: Exported from config/.storage/lovelace.lovelace view index 8.
######################################################################
title: Admin
icon: mdi:security
visible:
- user: be280a93c9d7416e98d25d0470f414be
cards: []
type: sections
sections: !include /config/dashboards/overview/partials/admin_sections.yaml

@ -16,6 +16,8 @@
# Notes: Hourly TeslaMate road-trip milestone/final callbacks become compact family mobile summaries; Joanna sends full reports to Carlo and Stacey.
# Notes: Status telemetry polling expects !secret bearclaw_status_url (token header stays !secret bearclaw_token).
# Notes: Status telemetry includes the latest 12 dispatches in the rolling 24-hour window for the Joanna Activity drill-down.
# Notes: Status telemetry also exposes compact, user-keyed step trends and personal records for the Health dashboard.
# Notes: Retired QMD health telemetry is no longer imported or materialized in Home Assistant.
# Notes: Codex reset-credit expiry telemetry is sourced from the appliance `codexUsage` status field.
# Notes: Reset-credit urgency is dashboard-only: warning within 7 days and critical within 3 days; no Repair is created.
# Notes: Codex reset walkthrough: https://youtu.be/7wKhtrvtyiI
@ -147,8 +149,8 @@ sensor:
- transports
- followups
- codexUsage
- qmdHealth
- memoryIndex
- healthInsights
template:
- sensor:
@ -332,15 +334,6 @@ template:
0
{% endif %}
- name: Joanna QMD Consecutive Failures
unique_id: joanna_qmd_consecutive_failures
icon: mdi:heart-pulse
unit_of_measurement: checks
state_class: measurement
state: >-
{% set qmd = state_attr('sensor.bearclaw_status_telemetry', 'qmdHealth') | default({}, true) %}
{{ qmd.get('consecutiveFailures', 0) | int(0) }}
- name: Joanna Memory Docs
unique_id: joanna_memory_docs
icon: mdi:file-document-multiple-outline
@ -374,14 +367,127 @@ template:
0
{% endif %}
- binary_sensor:
- name: Joanna QMD Healthy
unique_id: joanna_qmd_healthy
icon: mdi:heart-pulse
- name: Joanna Carlo Steps Trend
unique_id: joanna_carlo_steps_trend
icon: mdi:walk
unit_of_measurement: steps/day
state_class: measurement
availability: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('current7DayAverage') not in [none, 'unknown', 'unavailable', ''] }}
state: >-
{% set qmd = state_attr('sensor.bearclaw_status_telemetry', 'qmdHealth') | default({}, true) %}
{{ qmd.get('healthy', false) in [true, 'true', 'True', 'on', 'yes', 1, '1'] }}
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('current7DayAverage', 0) | int(0) }}
attributes:
prior_28d_average: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('prior28DayAverage') }}
prior_90d_average: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('prior90DayAverage') }}
change_vs_28_pct: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('changeVs28Percent') }}
change_vs_90_pct: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('changeVs90Percent') }}
current_7d_samples: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('current7DaySamples', 0) | int(0) }}
prior_28d_samples: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('prior28DaySamples', 0) | int(0) }}
prior_90d_samples: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('prior90DaySamples', 0) | int(0) }}
completed_through: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('steps', {}).get('completedThroughDayKey') }}
- name: Joanna Stacey Steps Trend
unique_id: joanna_stacey_steps_trend
icon: mdi:walk
unit_of_measurement: steps/day
state_class: measurement
availability: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('current7DayAverage') not in [none, 'unknown', 'unavailable', ''] }}
state: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('current7DayAverage', 0) | int(0) }}
attributes:
prior_28d_average: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('prior28DayAverage') }}
prior_90d_average: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('prior90DayAverage') }}
change_vs_28_pct: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('changeVs28Percent') }}
change_vs_90_pct: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('changeVs90Percent') }}
current_7d_samples: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('current7DaySamples', 0) | int(0) }}
prior_28d_samples: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('prior28DaySamples', 0) | int(0) }}
prior_90d_samples: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('prior90DaySamples', 0) | int(0) }}
completed_through: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('steps', {}).get('completedThroughDayKey') }}
- name: Joanna Carlo Latest Personal Record
unique_id: joanna_carlo_latest_personal_record
icon: mdi:trophy-outline
availability: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('personalRecords', {}).get('latest') is mapping }}
state: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('personalRecords', {}).get('latest', {}).get('label', 'No records') }}
attributes:
display_value: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('personalRecords', {}).get('latest', {}).get('displayValue') }}
activity_type: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('personalRecords', {}).get('latest', {}).get('activityType') }}
achieved_on: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('personalRecords', {}).get('latest', {}).get('dayKey') }}
record_count: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('carlo', {}).get('personalRecords', {}).get('count', 0) | int(0) }}
- name: Joanna Stacey Latest Personal Record
unique_id: joanna_stacey_latest_personal_record
icon: mdi:trophy-outline
availability: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('personalRecords', {}).get('latest') is mapping }}
state: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('personalRecords', {}).get('latest', {}).get('label', 'No records') }}
attributes:
display_value: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('personalRecords', {}).get('latest', {}).get('displayValue') }}
activity_type: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('personalRecords', {}).get('latest', {}).get('activityType') }}
achieved_on: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('personalRecords', {}).get('latest', {}).get('dayKey') }}
record_count: >-
{% set health = state_attr('sensor.bearclaw_status_telemetry', 'healthInsights') | default({}, true) %}
{{ health.get('users', {}).get('stacey', {}).get('personalRecords', {}).get('count', 0) | int(0) }}
- binary_sensor:
- name: Joanna Session Source Indexed
unique_id: joanna_session_source_indexed
icon: mdi:message-text-clock-outline

@ -1,10 +1,7 @@
# Static dashboard entities supplied by UI-managed helpers or integrations.
# Keep sorted. The validator proves these exist in live HA storage when available.
automation.llm_vision_garage_cans_upper_right
binary_sensor.codex_reset_credit_expiring_soon
binary_sensor.garage_phyn_leak_alert
binary_sensor.joanna_qmd_healthy
binary_sensor.joanna_session_source_indexed
binary_sensor.mcu1_gpio10
binary_sensor.mcu1_gpio13
binary_sensor.mcu1_gpio14
@ -28,8 +25,6 @@ button.l10s_vacuum_reset_filter
button.l10s_vacuum_reset_main_brush
button.l10s_vacuum_reset_mop_pad
button.l10s_vacuum_reset_side_brush
calendar.llm_vision_timeline
camera.alarm_panel_1
camera.bedroomgate
camera.filtergate
camera.frontlawn
@ -51,7 +46,6 @@ select.l10s_vacuum_auto_empty_frequency
select.l10s_vacuum_mop_pad_humidity
select.l10s_vacuum_suction_level
select.sleepnumber_carlo_foundation_preset_left
sensor.alarm_panel_1_battery
sensor.carlo_location_display
sensor.carlo_nas01_temperature
sensor.carlo_nas01_volume_1_used_space
@ -68,13 +62,16 @@ sensor.garage_ups_battery_runtime
sensor.joanna_all_dispatches_24h
sensor.joanna_all_dispatches_30d
sensor.joanna_all_dispatches_7d
sensor.joanna_carlo_latest_personal_record
sensor.joanna_carlo_steps_trend
sensor.joanna_ha_dispatches_24h
sensor.joanna_ha_dispatches_30d
sensor.joanna_ha_dispatches_7d
sensor.joanna_ha_errors_24h
sensor.joanna_ha_success_rate_24h
sensor.joanna_memory_docs
sensor.joanna_queue_pending
sensor.joanna_stacey_latest_personal_record
sensor.joanna_stacey_steps_trend
sensor.justin_location_display
sensor.l10s_vacuum_battery_level
sensor.l10s_vacuum_cleaning_count
@ -140,5 +137,4 @@ sensor.water_softener_salt_total_added
switch.l10s_vacuum_auto_dust_collecting
switch.phyn_autoshutoff_enabled
switch.phyn_scheduled_leak_test_enabled
update.llm_vision_update
weather.pirateweather

Loading…
Cancel
Save

Powered by TurnKey Linux.