一键导入
homeassistant-integration-patterns
Project-specific patterns for the Marstek integration (config flow, coordinator, scanner, entities, translations)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Project-specific patterns for the Marstek integration (config flow, coordinator, scanner, entities, translations)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
How to create, update, and manage Changesets for release preparation in this repository
Guidance for using correct energy and power metrics in Home Assistant energy features
High-level Home Assistant integration best practices, quality scale cues, and testing/CI expectations for custom components
Patterns for Home Assistant config flows, discovery handlers, options flows, and reauth for custom components
Practical test/CI playbook for Home Assistant custom components (config flow, coordinator, entities, diagnostics)
Repo-specific guidance for maintaining the Marstek integration (UDP Open API, polling, discovery/scanner) in a Home Assistant-friendly way
| name | homeassistant-integration-patterns |
| description | Project-specific patterns for the Marstek integration (config flow, coordinator, scanner, entities, translations) |
This skill helps you make correct, repo-consistent changes to this Home Assistant custom integration.
| Task | File(s) |
|---|---|
| Setup / teardown / coordinator wiring | __init__.py |
| Config flow (user, dhcp, integration discovery) | config_flow.py |
| Central polling (tiered intervals) | coordinator.py |
| IP-change scanner | scanner.py |
| Sensors | sensor.py (EntityDescription pattern) |
| Binary sensors | binary_sensor.py (EntityDescription pattern) |
| Select entities | select.py |
| Services | services.py (idempotent registration) |
| Device automation actions | device_action.py |
| Device info helper | device_info.py |
| Mode configuration | mode_config.py |
| Diagnostics | diagnostics.py |
| Text / translations | strings.json, translations/en.json |
| Icons | icons.json |
| Local API reference | docs/marstek_device_openapi.MD |
| UDP client library | pymarstek/ |
Coordinator-only I/O
MarstekDataUpdateCoordinator.data._async_setup() for one-time initialization during first refresh.always_update=False if data supports __eq__ comparison.Async-only
async def _async_update_data(self):
try:
return await self.api.fetch_data()
except AuthError as err:
# Triggers reauth flow automatically
raise ConfigEntryAuthFailed from err
except RateLimitError:
# Backoff with retry_after
raise UpdateFailed(retry_after=60)
except ConnectionError as err:
raise UpdateFailed(f"Connection failed: {err}")
Avoid unavailable clutter
Use translation-aware config-flow errors
custom_components/marstek/strings.json.Stable identifiers
_attr_has_entity_name = True and set device_info for grouping.Steps:
coordinator.data (a plain dict[str, Any] coming from pymarstek).MarstekSensorEntityDescription to the SENSORS tuple in sensor.py.exists_fn to conditionally create entities (avoids permanent unavailable state).unique_id stable (BLE-MAC + sensor key).translations/en.json (and keep strings.json in sync).suggested_display_precision for numeric sensors.unavailable noise.class MarstekSensor(CoordinatorEntity, SensorEntity):
_attr_has_entity_name = True # MANDATORY
def __init__(self, coordinator, description):
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = f"{coordinator.ble_mac}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, coordinator.ble_mac)},
name=coordinator.device_name,
manufacturer="Marstek",
)
@dataclass(kw_only=True)
class MarstekSensorEntityDescription(SensorEntityDescription):
value_fn: Callable[[dict], StateType]
exists_fn: Callable[[dict], bool] = lambda _: True
SENSORS: tuple[MarstekSensorEntityDescription, ...] = (
MarstekSensorEntityDescription(
key="battery_soc",
translation_key="battery_soc",
device_class=SensorDeviceClass.BATTERY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.get("soc"),
),
MarstekSensorEntityDescription(
key="power",
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.WATT,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.get("power"),
),
)
icon property)Create icons.json:
{
"entity": {
"sensor": {
"battery_soc": {
"default": "mdi:battery",
"state": {
"100": "mdi:battery",
"50": "mdi:battery-50"
}
}
}
}
}
EntityCategory.DIAGNOSTIC - RSSI, firmware version, temperatureEntityCategory.CONFIG - Settings the user can changeentity_registry_enabled_default = False for rarely-used sensorsSensorStateClass.MEASUREMENT - Instantaneous values (power, temperature)SensorStateClass.TOTAL - Values that can increase/decrease (net energy)SensorStateClass.TOTAL_INCREASING - Only increases, resets to 0 (lifetime energy)SensorDeviceClass.ENERGY_STORAGE for battery capacity (stored Wh)config_flow.py.When detecting connectivity issues or IP changes:
Example: The coordinator triggers MarstekScanner.async_request_scan() when it hits the failure threshold, enabling fast IP change detection without aggressive periodic scanning.