Home Assistant integration development
SkillDev toolsHome Assistant integration patterns — coordinator usage, entity unique IDs and naming, device registry, exception types, diagnostics redaction, and setup and unload. Use when working anywhere under custom_components/haeo/ outside the standalone core package.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Home Assistant integration development skill
What this skill tells your AI
The instructions your AI receives, as published by hass-energy/haeo in .agents/skills/integration/SKILL.md and read by ahel’s review.
Coordinator pattern
HAEO uses DataUpdateCoordinator for optimization scheduling. The coordinator loads data from sensors, runs optimization, and exposes results.
- Pass
config_entryto coordinator constructor - Use
UpdateFailedfor data loading or optimization errors - Integration determines update interval (not user-configurable)
Entity development
Unique IDs
Every entity must have a unique ID constructed from stable identifiers:
self._attr_unique_id = f"{entry.entry_id}-{element_id}-power"
Acceptable sources: config entry ID, subentry ID, device serial numbers. Never use: IP addresses, hostnames, user-provided names.
Entity naming
Use translation keys for all entity names:
class MySensor(SensorEntity):
_attr_has_entity_name = True
_attr_translation_key = "battery_power"
State handling
- Use
Nonefor unknown values (not "unknown" string) - Implement
availableproperty for availability
Event lifecycle
async def async_added_to_hass(self) -> None:
"""Subscribe to events."""
self.async_on_remove(self.coordinator.async_add_listener(self._handle_update))
Device registry
Group related entities under devices using translation keys:
_attr_device_info = DeviceInfo(
identifiers={(DOMAIN, device_id)},
translation_key="battery", # Use translation key for device name
)
Exception handling
All exceptions that may reach the user must use Home Assistant exception types with translations. Never raise generic exceptions that would show "unknown error" in the UI.
ConfigEntryNotReady: Device offline or temporary failureConfigEntryError: Unresolvable setup problemsUpdateFailed: Data loading or optimization errorsHomeAssistantError: User-facing errors with translation support
For service calls and user actions, use HomeAssistantError with a translation key:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="optimization_failed",
)
Diagnostics
Implement diagnostic data collection with redaction:
TO_REDACT = [CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE]
async def async_get_config_entry_diagnostics(hass: HomeAssistant, entry: ConfigEntry) -> dict[str, Any]:
return async_redact_data(entry.data, TO_REDACT)
Never expose passwords, tokens, or sensitive coordinates.
Setup and unload
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up from config entry."""
coordinator = MyCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
Signals
- GitHub stars
- 65
- Forks
- 21
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
integration-hass-energy- Source
- github.com/hass-energy/haeo