一键导入
python-homeassistant
Architecture, entity patterns, testing, and conventions for the hass-iopool Home Assistant custom integration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Architecture, entity patterns, testing, and conventions for the hass-iopool Home Assistant custom integration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Commit message format, PR conventions, branch rules, and pre-commit test gate for hass-iopool.
Writing, updating, and structuring documentation pages for hass-iopool. Covers MDX format, frontmatter, docs.page components, docs.json navigation registration, and when to update docs after code changes.
Project-specific test setup for hass-iopool — directory structure, test tiers, devcontainer/docker environment detection, running pytest, and shared fixtures.
基于 SOC 职业分类
| name | python-homeassistant |
| description | Architecture, entity patterns, testing, and conventions for the hass-iopool Home Assistant custom integration. |
| user-invocable | false |
Use this skill for any implementation, review, or debugging task in the custom_components/iopool/ codebase.
async/await everywhere for I/Oaiohttp to https://api.iopool.com/v1 — no external wrapper library (requirements: [] in manifest.json)
flake8 --max-line-length=150pytest with asyncio_mode = "auto" (see pyproject.toml)custom_components/iopool/
├── __init__.py # Entry setup/teardown, IopoolData wiring (filtration, coordinator)
├── api_models.py # IopoolAPIResponse, IopoolAPIResponsePool, IopoolLatestMeasure, IopoolAdvice
├── binary_sensor.py # BinarySensor platform
├── config_flow.py # UI config flow + options flow (CONFIG_VERSION=1)
├── const.py # All constants (DOMAIN, API endpoints, sensor types, config keys)
├── coordinator.py # IopoolDataUpdateCoordinator — polls every 300 s via aiohttp
├── diagnostics.py # HA diagnostics endpoint
├── entity.py # IopoolEntity base class (extends CoordinatorEntity + RestoreEntity)
├── filtration.py # Filtration logic and time-based scheduling
├── manifest.json # Integration metadata (no external requirements)
├── models.py # IopoolData, IopoolConfigData, IopoolConfigEntry alias
├── select.py # Select platform
├── sensor.py # Sensor platform
└── translations/ # en.json, fr.json — all entity human names
Always use IopoolConfigEntry (defined in models.py) instead of raw ConfigEntry:
from .models import IopoolConfigEntry
# NOT: from homeassistant.config_entries import ConfigEntry
IopoolConfigEntry = ConfigEntry[IopoolData]
coordinator: IopoolDataUpdateCoordinator = entry.runtime_data.coordinator
config: IopoolConfigData = entry.runtime_data.config
filtration: Filtration = entry.runtime_data.filtration
coordinator.data # IopoolAPIResponse object
coordinator.data.pools # list[IopoolAPIResponsePool]
coordinator.get_pool_data(pool_id) # IopoolAPIResponsePool | None
Always check for None before accessing pool data:
pool = coordinator.get_pool_data(pool_id)
if pool is None:
return
All entities extend IopoolEntity:
from .entity import IopoolEntity
class IopoolMySensor(IopoolEntity, SensorEntity):
pass
IopoolEntity already sets _attr_has_entity_name = True and provides device_info.
@dataclass(frozen=True)
class IopoolSensorEntityDescription(SensorEntityDescription):
exists_fn: Callable[..., bool] = lambda _: True
self._attr_unique_id = f"{config_entry_id}_{pool_id}_{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" }
}
}
from aiohttp.client_exceptions import ClientError, ServerTimeoutError
try:
async with self.session.get(url, headers=self.headers) as response:
response.raise_for_status()
data = await response.json()
except (ClientError, ServerTimeoutError) as err:
raise UpdateFailed(f"Error communicating with iopool API: {err}") from err
async/await@callback decorator on _handle_coordinator_updatetime.sleep, no synchronous HTTP) in async context_LOGGER = logging.getLogger(__name__) — never print()See ../testing-hass-iopool/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 selectpool_mode)mV, °C); omit for binary or selectexists_fn@dataclass(frozen=True) EntityDescription subclass with optional exists_fnunique_id following the {entry_id}_{pool_id}_{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 IopoolSensorEntityDescription(SensorEntityDescription):
"""Sensor entity description for iopool."""
exists_fn: Callable[..., bool] = lambda _: True
SENSORS: tuple[IopoolSensorEntityDescription, ...] = (
IopoolSensorEntityDescription(
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 pool: pool.latest_measure is not None,
),
)
async_setup_entryclass IopoolMySensor(IopoolEntity, SensorEntity):
def __init__(
self,
coordinator: IopoolDataUpdateCoordinator,
description: IopoolSensorEntityDescription,
config_entry_id: str,
pool_id: str,
pool_name: str,
) -> None:
super().__init__(coordinator, config_entry_id, pool_id, pool_name)
self.entity_description = description
self._attr_unique_id = f"{config_entry_id}_{pool_id}_{description.key}"
async def async_setup_entry(
hass: HomeAssistant,
entry: IopoolConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
coordinator = entry.runtime_data.coordinator
pool_id: str = entry.data[CONF_POOL_ID]
pool = coordinator.get_pool_data(pool_id)
if pool is None:
return
async_add_entities(
IopoolMySensor(coordinator, description, entry.entry_id, pool.id, pool.title)
for description in SENSORS
if description.exists_fn(pool)
)
| Attribute | Type | Description |
|---|---|---|
coordinator.data | IopoolAPIResponse | Full API response |
coordinator.data.pools | list[IopoolAPIResponsePool] | All pools for the API key |
coordinator.get_pool_data(pool_id) | IopoolAPIResponsePool | None | Single pool by ID |
pool.latest_measure | IopoolLatestMeasure | None | Latest sensor measurement |
pool.advice | IopoolAdvice | None | iopool filtration advice |
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/iopool/.
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 / IopoolEntity as base class for entitiesIopoolConfigEntry 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}_{pool_id}_{key} pattern_attr_has_entity_name = True is set (already in IopoolEntity)translation_key set on the EntityDescriptionexists_fn defined if the entity is conditionalconst.py_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-iopool/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/sensor/__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-iopool/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 |
mcp_github_search_issues | query=breaking change sensor coordinator 2024.4 |mcp_github_search_pull_requests | query=sensor coordinator 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/iopool/../testing-hass-iopool/SKILL.md §7../testing-hass-iopool/SKILL.md §3)Tests: line (see ../git-conventions/SKILL.md)