Skip to content

Commit 9498c49

Browse files
authored
Merge pull request #38 from nsleigh/feat/get-drive-data-pr
feat: add get_drive_data HA action for AI-powered drive health analysis
2 parents acd78a7 + 0cdbb58 commit 9498c49

5 files changed

Lines changed: 110 additions & 2 deletions

File tree

custom_components/smart_sniffer/__init__.py

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@
99
from __future__ import annotations
1010

1111
import logging
12+
from typing import Any
13+
14+
import voluptuous as vol
1215

1316
from homeassistant.config_entries import ConfigEntry
1417
from homeassistant.const import Platform
15-
from homeassistant.core import HomeAssistant
18+
from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse
19+
from homeassistant.exceptions import ServiceValidationError
1620

17-
from .const import DOMAIN
21+
from .attention import evaluate_attention
22+
from .const import DOMAIN, FILESYSTEMS_KEY, SERVICE_GET_DRIVE_DATA
1823
from .coordinator import AgentHealthCoordinator, SmartSnifferCoordinator
1924

2025
_LOGGER = logging.getLogger(__name__)
@@ -37,6 +42,67 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
3742

3843
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
3944

45+
# Register the get_drive_data service once per domain.
46+
if not hass.services.has_service(DOMAIN, SERVICE_GET_DRIVE_DATA):
47+
async def handle_get_drive_data(call: ServiceCall) -> dict[str, Any]:
48+
entry_id: str = call.data["config_entry_id"]
49+
domain_data = hass.data.get(DOMAIN, {})
50+
if entry_id not in domain_data:
51+
raise ServiceValidationError(
52+
f"No SMART Sniffer entry found with ID: {entry_id}"
53+
)
54+
coord = domain_data[entry_id]["coordinator"]
55+
health = domain_data[entry_id]["health_coordinator"]
56+
57+
drives: dict[str, Any] = {}
58+
for drive_id, drive_data in coord.data.items():
59+
if drive_id.startswith("_"):
60+
continue
61+
state, severity, reasons = evaluate_attention(drive_data)
62+
drives[drive_id] = {
63+
"model": drive_data.get("model"),
64+
"serial": drive_data.get("serial"),
65+
"protocol": drive_data.get("protocol"),
66+
"device_path": drive_data.get("device_path"),
67+
"attention": {
68+
"state": state,
69+
"severity": severity,
70+
"reasons": reasons,
71+
},
72+
"smart_data": drive_data.get("smart_data"),
73+
}
74+
75+
raw_filesystems: list[dict[str, Any]] = coord.data.get(FILESYSTEMS_KEY, [])
76+
filesystems = [
77+
{
78+
"mountpoint": fs.get("mountpoint"),
79+
"total_bytes": fs.get("total_bytes"),
80+
"used_bytes": fs.get("used_bytes"),
81+
"use_percent": fs.get("use_percent"),
82+
}
83+
for fs in raw_filesystems
84+
]
85+
86+
return {
87+
"agent": {
88+
"name": health.config_entry.title,
89+
"host": health.host,
90+
"os": health.data.get("os"),
91+
"uptime": health.data.get("uptime_seconds"),
92+
"version": health.data.get("version"),
93+
},
94+
"drives": drives,
95+
"filesystems": filesystems,
96+
}
97+
98+
hass.services.async_register(
99+
DOMAIN,
100+
SERVICE_GET_DRIVE_DATA,
101+
handle_get_drive_data,
102+
schema=vol.Schema({vol.Required("config_entry_id"): str}),
103+
supports_response=SupportsResponse.ONLY,
104+
)
105+
40106
# Reload the integration when options are changed via the UI.
41107
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
42108

@@ -48,6 +114,8 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
48114
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
49115
if unload_ok:
50116
hass.data[DOMAIN].pop(entry.entry_id)
117+
if not hass.data[DOMAIN]:
118+
hass.services.async_remove(DOMAIN, SERVICE_GET_DRIVE_DATA)
51119
return unload_ok
52120

53121

custom_components/smart_sniffer/const.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@
2121
# Key used in coordinator data dict to store filesystem info.
2222
# Underscore prefix avoids collision with drive ID keys.
2323
FILESYSTEMS_KEY = "_filesystems"
24+
25+
# Service name for the get_drive_data action.
26+
SERVICE_GET_DRIVE_DATA = "get_drive_data"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
get_drive_data:
2+
name: Get Drive Data
3+
description: >
4+
Returns the full cached SMART data for all drives monitored by a SMART Sniffer
5+
agent. Useful for passing raw drive health data to an AI for analysis.
6+
fields:
7+
config_entry_id:
8+
name: Config Entry
9+
description: The SMART Sniffer agent to query.
10+
required: true
11+
selector:
12+
config_entry:
13+
integration: smart_sniffer

custom_components/smart_sniffer/strings.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@
5959
"unknown": "An unexpected error occurred."
6060
}
6161
},
62+
"services": {
63+
"get_drive_data": {
64+
"name": "Get Drive Data",
65+
"description": "Returns the full cached SMART data for all drives monitored by a SMART Sniffer agent. Useful for passing raw drive health data to an AI for analysis.",
66+
"fields": {
67+
"config_entry_id": {
68+
"name": "Config Entry",
69+
"description": "The SMART Sniffer agent to query."
70+
}
71+
}
72+
}
73+
},
6274
"issues": {
6375
"agent_outdated": {
6476
"title": "SMART Sniffer: Update agent on {hostname} (v{current_version} → v{min_version})",

custom_components/smart_sniffer/translations/en.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@
5959
"unknown": "An unexpected error occurred."
6060
}
6161
},
62+
"services": {
63+
"get_drive_data": {
64+
"name": "Get Drive Data",
65+
"description": "Returns the full cached SMART data for all drives monitored by a SMART Sniffer agent. Useful for passing raw drive health data to an AI for analysis.",
66+
"fields": {
67+
"config_entry_id": {
68+
"name": "Config Entry",
69+
"description": "The SMART Sniffer agent to query."
70+
}
71+
}
72+
}
73+
},
6274
"issues": {
6375
"agent_outdated": {
6476
"title": "SMART Sniffer: Update agent on {hostname} (v{current_version} → v{min_version})",

0 commit comments

Comments
 (0)