원클릭으로
python-homeassistant
Architecture, entity patterns, testing, and conventions for the hass-diagral Home Assistant custom integration.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Architecture, entity patterns, testing, and conventions for the hass-diagral Home Assistant custom integration.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Writing, updating, and structuring documentation pages for hass-diagral. Covers MDX format, frontmatter, docs.page components, docs.json navigation registration, and when to update docs after code changes.
Commit message format, PR conventions, branch rules, and pre-commit test gate for hass-diagral.
Planning-track selection, epic/feature decomposition, readiness gates, and plan-delta rules.
Project-specific test setup for hass-diagral — directory structure, test tiers, devcontainer/docker environment detection, running pytest, and shared fixtures.
| name | python-homeassistant |
| description | Architecture, entity patterns, testing, and conventions for the hass-diagral Home Assistant custom integration. |
| user-invocable | false |
Use this skill for any implementation, review, or debugging task in the custom_components/diagral/ codebase.
async/await everywhere for I/Opydiagral (pinned in manifest.json) — all Diagral API calls go through this library exclusively
flake8 --max-line-length=150pytest with asyncio_mode = "auto" (see pyproject.toml)custom_components/diagral/
├── __init__.py # Entry setup/teardown, webhook registration, DiagralConfigEntry alias
├── coordinator.py # DiagralDataUpdateCoordinator — polls every 300 s
├── models.py # DiagralData, DiagralConfigData, DiagralOptionsData
├── const.py # All constants (DOMAIN, service names, config keys)
├── config_flow.py # UI config flow + options flow
├── entity.py # DiagralEntity base class (extends CoordinatorEntity)
├── alarm_control_panel.py # AlarmControlPanel platform
├── sensor.py # Sensor platform
├── webhook.py # Webhook handler (push updates from Diagral cloud)
├── diagnostics.py # HA diagnostics endpoint
├── services.yaml # Custom service definitions
├── manifest.json # Integration metadata (pydiagral version pinned)
└── translations/ # en.json, fr.json — all entity human names
Always use DiagralConfigEntry (defined in __init__.py) instead of raw ConfigEntry:
from . import DiagralConfigEntry
# NOT: from homeassistant.config_entries import ConfigEntry
DiagralConfigEntry = ConfigEntry[DiagralData]
coordinator: DiagralDataUpdateCoordinator = entry.runtime_data.coordinator
api: DiagralAPI = entry.runtime_data.api
config: DiagralConfigData = entry.runtime_data.config
webhook_id: str = entry.runtime_data.webhook_id
coordinator.data["alarm_config"] # AlarmConfiguration
coordinator.data["devices_infos"] # DeviceInfos
coordinator.data["groups"] # list[Group]
coordinator.data["system_status"] # SystemStatus
coordinator.data["anomalies"] # Anomalies
Access with .get() and safe fallbacks when the key may be absent:
status: SystemStatus = coordinator.data.get("system_status")
All entities extend DiagralEntity:
from .entity import DiagralEntity
class DiagralMySensor(DiagralEntity, SensorEntity):
pass
DiagralEntity already sets _attr_has_entity_name = True and provides device_info.
@dataclass(frozen=True)
class DiagralSensorEntityDescription(SensorEntityDescription):
exists_fn: Callable[..., bool] = lambda _: True
self._attr_unique_id = (
f"{config_entry.entry_id}_{DOMAIN}"
f"_{coordinator.data['alarm_config'].alarm.central.serial}"
f"_{description.key}"
)
Every entity needs translation_key on the description. Add the key to both translations/en.json and translations/fr.json:
"entity": {
"sensor": {
"my_key": { "name": "Human Readable Name" }
}
}
.nabu.casa domain) and direct HA webhookHA_CLOUD_DOMAIN = ".nabu.casa" constant used for detectionpydiagral.models.WebHookNotification.from_dict()coordinator.async_request_refresh()from pydiagral.exceptions import DiagralAPIError
try:
await api.some_call()
except DiagralAPIError as err:
raise UpdateFailed(f"Error communicating with API: {err}") from err
Never call the Diagral API directly — always go through pydiagral.
async/await@callback decorator on _handle_coordinator_updatetime.sleep, no synchronous HTTP) in async context_LOGGER = logging.getLogger(__name__) — never print()See ../testing-hass-diagral/SKILL.md for the full project-specific test setup:
pytest run commands (devcontainer / docker exec)conftest.pyFor generic testing principles, see ../testing-qa/SKILL.md.
If any of the following is unclear, gather the information via vscode_askQuestions before starting implementation.
sensor, binary_sensor, or alarm_control_panelbattery_level)%, °C); omit for binary or alarmexists_fn@dataclass(frozen=True) EntityDescription subclass with exists_fnunique_id following the {entry_id}_{DOMAIN}_{serial}_{key} patterntranslation_key added to both en.json and fr.jsondocs/integration/entities.mdxtests/test_<platform>.py — at minimum: unique_id format, entity state, exists_fn if definedfeat(<platform>): ✨ Add <entity_name> entity@dataclass(frozen=True)
class DiagralSensorEntityDescription(SensorEntityDescription):
"""Sensor entity description for Diagral."""
exists_fn: Callable[..., bool] = lambda _: True
SENSORS: tuple[DiagralSensorEntityDescription, ...] = (
DiagralSensorEntityDescription(
key="my_sensor", # snake_case, unique within the platform
translation_key="my_sensor", # must match the key in en.json / fr.json
icon="mdi:...",
native_unit_of_measurement="unit",
# exists_fn=lambda coordinator: coordinator.some_condition,
),
)
async_setup_entryclass DiagralMySensor(DiagralEntity, SensorEntity):
def __init__(
self,
coordinator: DiagralDataUpdateCoordinator,
description: DiagralSensorEntityDescription,
config_entry: DiagralConfigEntry,
) -> None:
super().__init__(coordinator)
self.entity_description = description
self._entry_id = config_entry.entry_id
self._alarm_config = coordinator.data.get("alarm_config", {})
self._attr_unique_id = (
f"{self._entry_id}_{DOMAIN}"
f"_{self._alarm_config.alarm.central.serial}"
f"_{description.key}"
)
async def async_setup_entry(
hass: HomeAssistant,
entry: DiagralConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
coordinator = entry.runtime_data.coordinator
async_add_entities(
DiagralMySensor(coordinator, description, entry)
for description in SENSORS
if description.exists_fn(coordinator)
)
| Key | Type | Description |
|---|---|---|
alarm_config | AlarmConfiguration | Full alarm configuration |
system_status | SystemStatus | Current system status |
anomalies | Anomalies | Current anomalies list |
groups | list[Group] | Active arming groups |
devices_infos | DeviceInfos | All registered devices |
Add under entity.<platform>.<translation_key> in both translations/en.json and translations/fr.json:
"entity": {
"sensor": {
"my_sensor": {
"name": "Human Readable Name"
}
}
}
Whenever a feature, service, entity, or behavior is added or modified, apply this process before considering the task complete:
Read the relevant docs/ pages — scan docs/integration/ to identify pages that cover the area being changed (entities, actions, events, webhook, setup, etc.).
Identify what needs documenting — new behavior, changed defaults, added options, new entities, removed capabilities, updated configuration steps, etc.
Preserve the existing style — match the tone, structure, table format, and MDX components already used on the target page. Do not introduce new formatting patterns.
When in doubt, ask the developer — if it is unclear whether a change warrants a documentation update, ask via vscode_askQuestions (mandatory — see global rule in copilot-instructions.md) before writing or skipping it:
"Should I update the documentation for this change? If yes, which page(s)?"
| Check | Tool | What it validates |
|---|---|---|
hassfest | GitHub Actions | manifest.json, translations, quality_scale.yaml |
hacs/action | GitHub Actions | HACS compatibility |
CodeQL | GitHub Actions | Python security analysis |
See ../git-conventions/SKILL.md for the full rules:
Tests: line)Use this checklist when reviewing any file in custom_components/diagral/.
except: clausesflake8 --max-line-length=150 <file>async/await for all I/O-bound operations (no blocking calls in async context)_LOGGER = logging.getLogger(__name__) — no print() statementsCoordinatorEntity / DiagralEntity as base class for entitiesDiagralConfigEntry used instead of raw ConfigEntryentry.runtime_data.coordinator to access the coordinator@callback decorator on _handle_coordinator_updateconst.py — no magic strings or numbers inline_attr_unique_id follows {entry_id}_{DOMAIN}_{serial}_{key} pattern_attr_has_entity_name = True is set (already in DiagralEntity)translation_key set on the EntityDescriptionexists_fn defined if the entity is conditionalpydiagral)_LOGGER.error or _LOGGER.warning.get() with safe fallbacks when a key may be absentexcept: pass blocksReport what is not yet tested in tests/test_<module>.py:
### Issues (must fix)
- `<file>:<line>` — description
### Suggestions (nice to have)
- description
### Test gaps
- description
Trigger: When the user mentions that a behavior changed since a specific HA version (e.g., "this worked in HA 2024.3 but broke in 2024.4"). Always perform this investigation before modifying integration code, to understand the root cause rather than patching symptoms.
Based on the integration code that changed behavior, identify the HA modules likely involved. Common locations:
homeassistant/components/<platform>/ — platform base classes and contractshomeassistant/helpers/entity.py, entity_registry.py — entity lifecyclehomeassistant/components/alarm_control_panel/__init__.py — alarm panel contractThe devcontainer contains a git clone of HA. Use it to inspect history directly.
Step 2a — Detect environment and locate the HA repo:
# Detect environment (see ../testing-hass-diagral/SKILL.md §3)
test -d /workspaces && echo "inside devcontainer" || echo "outside devcontainer"
# Find the HA git repository
find /workspaces -name ".git" -maxdepth 3 2>/dev/null
Step 2b — Browse commit history on a suspected file:
# List commits on a file (all history)
git -C <ha_repo_path> log --oneline --follow -- homeassistant/components/alarm_control_panel/__init__.py
# Restrict to a version range
git -C <ha_repo_path> log --oneline v2024.3.0..v2024.4.0 -- <file>
# See the full diff of a commit
git -C <ha_repo_path> show <commit_sha>
Outside devcontainer: retrieve the container ID first, then prefix with docker exec <CONTAINER_ID> (see ../testing-hass-diagral/SKILL.md §3).
Use MCP GitHub tools to search history and context in home-assistant/core or home-assistant/frontend:
| Goal | Tool | Key parameters |
|---|---|---|
| Browse commits on a file | mcp_github_list_commits | owner=home-assistant, repo=core, path=homeassistant/components/... |
| Read a specific commit | mcp_github_get_commit | sha from the list above |
| Search code in HA | mcp_github_search_code | query=MyClass repo:home-assistant/core |
| Find related issues | mcp_github_search_issues | query=breaking change alarm_control_panel 2024.4 |
| Find related PRs | mcp_github_search_pull_requests | query=alarm_control_panel in home-assistant/core |
Primary repos to check (not exclusively):
home-assistant/core — Python backend, entities, platforms, helpershome-assistant/frontend — UI components (if the change is visual/frontend)After finding relevant commits, confirm using HA release blog posts:
https://www.home-assistant.io/blog/ — release notes per versionOnce the HA change is fully understood:
custom_components/diagral/../testing-hass-diagral/SKILL.md §7../testing-hass-diagral/SKILL.md §3)Tests: line (see ../git-conventions/SKILL.md)