mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-14 12:56:30 +00:00
Re-organize quality scale
This commit is contained in:
parent
e49e2b7fbf
commit
b6a9f8b056
@ -155,6 +155,8 @@ async def async_step_unignore(self, user_input):
|
||||
|
||||
## Discovery steps
|
||||
|
||||
Integrations can define in their manifest that they support discovery via [Bluetooth](creating_integration_manifest.md#bluetooth), [DHCP](creating_integration_manifest.md#dhcp), [HomeKit](creating_integration_manifest.md#homekit), [Zeroconf/mDNS](creating_integration_manifest.md#zeroconf), [USB](creating_integration_manifest.md#usb), [MQTT](creating_integration_manifest.md#mqtt), or [SSDP/uPnP](creating_integration_manifest.md#ssdp).
|
||||
|
||||
When an integration is discovered, their respective discovery step is invoked (ie `async_step_dhcp` or `async_step_zeroconf`) with the discovery information. The step will have to check the following things:
|
||||
|
||||
- Make sure there are no other instances of this config flow in progress of setting up the discovered device. This can happen if there are multiple ways of discovering that a device is on the network.
|
||||
|
@ -17,51 +17,53 @@ This integration passes the bare minimum requirements to become part of the inde
|
||||
|
||||
## Silver 🥈
|
||||
|
||||
This integration is able to cope when things go wrong. It will not print any exceptions nor will it fill the log with retry attempts.
|
||||
This integration can be set up via the user interface and is able to cope when things go wrong. It will not print any exceptions nor will it fill the log with retry attempts.
|
||||
|
||||
- Satisfying all No score level requirements.
|
||||
- Connection/configuration is handled via a component.
|
||||
- Set an appropriate `SCAN_INTERVAL` (if a polling integration)
|
||||
- Raise [`PlatformNotReady`](integration_setup_failures.md#integrations-using-async_setup_platform) if unable to connect during platform setup (if appropriate)
|
||||
- Handles expiration of auth credentials. Refresh if possible or print correct error and fail setup. If based on a config entry, should trigger a new config entry flow to re-authorize. ([docs](config_entries_config_flow_handler.md#reauthentication))
|
||||
- Handles internet unavailable. Log a warning once when unavailable, log once when reconnected.
|
||||
- Handles device/service unavailable. Log a warning once when unavailable, log once when reconnected.
|
||||
- Operations like service calls and entity methods (e.g. *Set HVAC Mode*) have proper exception handling. Raise `ServiceValidationError` on invalid user input and raise `HomeAssistantError` for other failures such as a problem communicating with a device. [Read more](/docs/core/platform/raising_exceptions) about raising exceptions.
|
||||
- Set `available` property to `False` if appropriate ([docs](core/entity.md#generic-properties))
|
||||
- Entities have unique ID (if available) ([docs](entity_registry_index.md#unique-id-requirements))
|
||||
- Configuration:
|
||||
- Configuration is done using config entries and data is stored in `config_entry.runtime_data`.
|
||||
- Raise [`ConfigEntryNotReady`](integration_setup_failures.md) if unable to connect during platform setup (if appropriate)
|
||||
- Devices and entities:
|
||||
- Set an appropriate `SCAN_INTERVAL` (if a polling integration)
|
||||
- Handles internet unavailable. Log a warning once when unavailable, log once when reconnected.
|
||||
- Handles device/service unavailable. Log a warning once when unavailable, log once when reconnected.
|
||||
- Set `available` property to `False` if appropriate ([docs](core/entity.md#generic-properties))
|
||||
- Entities have unique ID (if available) ([docs](entity_registry_index.md#unique-id-requirements))
|
||||
- Services:
|
||||
- Operations like service calls and entity methods (e.g. *Set HVAC Mode*) have proper exception handling. Raise `ServiceValidationError` on invalid user input and raise `HomeAssistantError` for other failures such as a problem communicating with a device. [Read more](/docs/core/platform/raising_exceptions) about raising exceptions.
|
||||
- Tests:
|
||||
- Full test coverage for the config flow
|
||||
|
||||
## Gold 🥇
|
||||
|
||||
This is a solid integration that is able to survive poor conditions and can be configured via the user interface.
|
||||
This is a solid integration that offers the best possible user experience that Home Assistant has to offer.
|
||||
|
||||
- Satisfying all Silver level requirements.
|
||||
- Configurable via config entries.
|
||||
- Don't allow configuring already configured device/service (example: no 2 entries for same hub)
|
||||
- Discoverable (if available)
|
||||
- Set unique ID in config flow (if available)
|
||||
- Raise [`ConfigEntryNotReady`](integration_setup_failures.md#integrations-using-async_setup_entry) if unable to connect during entry setup (if appropriate)
|
||||
- Entities have device info (if available) ([docs](device_registry_index.md#defining-devices))
|
||||
- Configuration:
|
||||
- Don't allow configuring already configured device/service (example: no 2 entries for same hub). If possible, set a unique ID on the config flow.
|
||||
- [Discoverable](config_entries_config_flow_handler.md#discovery-steps) (if available)
|
||||
- Support config entry [unloading](config_entries_index.md#unloading-entries) and [removal](config_entries_index.md#removal-of-entries)
|
||||
- Handles expiration of auth credentials. Refresh if possible or print correct error and fail setup. If based on a config entry, should trigger a new config entry flow to re-authorize. ([docs](integration_setup_failures.md))
|
||||
- Devices and entities:
|
||||
- Entities have [device info](device_registry_index.md#defining-devices) and uses [`has_entity_name = True`](./core/entity.md#has_entity_name-true-mandatory-for-new-integrations)
|
||||
- Entities have correct device classes where appropriate ([docs](core/entity.md#generic-properties))
|
||||
- Supports entities being disabled and leverages `Entity.entity_registry_enabled_default` to disable less popular entities ([docs](core/entity.md#advanced-properties))
|
||||
- If the device/service API can remove entities, the integration should make sure to clean up the entity and device registry.
|
||||
- Entities only subscribe to updates inside `async_added_to_hass` and unsubscribe via `self.async_on_remove` or inside `async_will_remove_from_hass` ([docs](core/entity.md#lifecycle-hooks))
|
||||
- Set appropriate `PARALLEL_UPDATES` constant ([docs](integration_fetching_data.md#request-parallelism))
|
||||
- Tests
|
||||
- Full test coverage for the config flow
|
||||
- Above average test coverage for all integration modules
|
||||
- Tests for fetching data from the integration and controlling it ([docs](development_testing.md))
|
||||
- Has a code owner ([docs](creating_integration_manifest.md#code-owners))
|
||||
- Entities only subscribe to updates inside `async_added_to_hass` and unsubscribe inside `async_will_remove_from_hass` ([docs](core/entity.md#lifecycle-hooks))
|
||||
- Entities have correct device classes where appropriate ([docs](core/entity.md#generic-properties))
|
||||
- Supports entities being disabled and leverages `Entity.entity_registry_enabled_default` to disable less popular entities ([docs](core/entity.md#advanced-properties))
|
||||
- If the device/service API can remove entities, the integration should make sure to clean up the entity and device registry.
|
||||
- When communicating with a device or service, the integration implements the diagnostics platform which redacts sensitive information.
|
||||
- Implement the diagnostics platform with sensitive information redacted (if appropriate)
|
||||
|
||||
## Platinum 🏆
|
||||
|
||||
Best of the best. The integration is completely async, meaning it's super fast. Integrations that reach platinum level will require approval by the code owner for each PR.
|
||||
Best of the best. The integration implements all the best Home Assistant performance best practices. Integrations that reach platinum level will require approval by the code owner for each PR.
|
||||
|
||||
- Satisfying all Gold level requirements.
|
||||
- Set appropriate `PARALLEL_UPDATES` constant ([docs](integration_fetching_data.md#request-parallelism))
|
||||
- Support config entry unloading (called when config entry is removed)
|
||||
- Integration + dependency are async ([docs](asyncio_working_with_async.md))
|
||||
- Uses aiohttp or httpx and allows passing in websession (if making HTTP requests)
|
||||
- [Handles expired credentials](integration_setup_failures.md#handling-expired-credentials) (if appropriate)
|
||||
|
||||
## Internal 🏠
|
||||
|
||||
|
@ -4,13 +4,11 @@ title: "Handling setup failures"
|
||||
|
||||
Your integration may not be able to be set up for a variety of reasons. The most common cases are because the device or service is offline or the credentials are no longer valid. Your integration must retry setup so it can recover as soon as reasonably possible when the device or service is back online without the user having to restart Home Assistant.
|
||||
|
||||
## Handling offline or unavailable devices and services
|
||||
## Config entry not ready
|
||||
|
||||
### Integrations using `async_setup_entry`
|
||||
if the integration is unable to make a connection to the service, it is safe to assume that this is a temporary issue. In that case, a user can raise `ConfigEntryNotReady` exception from `async_setup_entry` in the integration's `__init__.py`, and Home Assistant will automatically take care of retrying set up later.
|
||||
|
||||
Raise the `ConfigEntryNotReady` exception from `async_setup_entry` in the integration's `__init__.py`, and Home Assistant will automatically take care of retrying set up later. To avoid doubt, raising `ConfigEntryNotReady` in a platform's `async_setup_entry` is ineffective because it is too late to be caught by the config entry setup.
|
||||
|
||||
#### Example
|
||||
You should not raise `ConfigEntryNotReady` in a platform's `async_setup_entry` is ineffective because it is too late to be caught by the config entry setup.
|
||||
|
||||
```python
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
@ -26,18 +24,36 @@ If you are using a [DataUpdateCoordinator](integration_fetching_data#coordinated
|
||||
|
||||
If your integration supports discovery, Home Assistant will automatically retry as soon as your device or service gets discovered.
|
||||
|
||||
#### Handling logging of a retry
|
||||
|
||||
Pass the error message to `ConfigEntryNotReady` as the first argument. Home Assistant will log the retry once with a log level of
|
||||
`warning`, and subsequent retries are logged at `debug` level. The error message will also be propagated to the UI and shown on the integrations page. Suppose you do not set a message when raising `ConfigEntryNotReady`; in that case, Home Assistant will try to extract the reason from the exception that is the cause of `ConfigEntryNotReady` if it was propagated from another exception.
|
||||
|
||||
The integration should not log any non-debug messages about the retry, and should instead rely on the logic built-in to `ConfigEntryNotReady` to avoid spamming the logs.
|
||||
|
||||
### Integrations using `async_setup_platform`
|
||||
## Handling expired credentials
|
||||
|
||||
Raise the `PlatformNotReady` exception from `async_setup_platform`, and Home Assistant will automatically take care of retrying set up later.
|
||||
Raise the `ConfigEntryAuthFailed` exception, and Home Assistant will automatically put the config entry in a failure state and [start a reauth flow](config_entries_config_flow_handler.md#reauthentication). The exception must be raised from `async_setup_entry` in `__init__.py` or from the `DataUpdateCoordinator` or the exception will not be effective at triggering the reauth flow. If your integration does not use a `DataUpdateCoordinator`, calling `entry.async_start_reauth()` can be used as an alternative to starting a reauth flow.
|
||||
|
||||
#### Example
|
||||
The `reauth` flow will be started with the following context variables, which are available in the `async_step_reauth` step:
|
||||
|
||||
- source: This will always be "SOURCE_REAUTH"
|
||||
- entry_id: The entry_id of the config entry that needs reauthentication
|
||||
- unique_id: The unique_id of the config entry that needs reauthentication
|
||||
|
||||
```python
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Setup the config entry for my device."""
|
||||
device = MyDevice(entry.data[CONF_HOST])
|
||||
try:
|
||||
await device.async_setup()
|
||||
except AuthFailed as ex:
|
||||
raise ConfigEntryAuthFailed(f"Credentials expired for {device.name}") from ex
|
||||
except (asyncio.TimeoutError, TimeoutException) as ex:
|
||||
raise ConfigEntryNotReady(f"Timed out while connecting to {device.ipaddr}") from ex
|
||||
```
|
||||
|
||||
## Platform not ready (legacy)
|
||||
|
||||
Old integrations were set up by calling the `async_setup_platform` method. These methods are able to raise the `PlatformNotReady` exception from `async_setup_platform`, and Home Assistant will automatically take care of retrying set up later.
|
||||
|
||||
```python
|
||||
async def async_setup_platform(
|
||||
@ -54,33 +70,7 @@ async def async_setup_platform(
|
||||
raise PlatformNotReady(f"Connection error while connecting to {device.ipaddr}: {ex}") from ex
|
||||
```
|
||||
|
||||
#### Handling logging of a retry
|
||||
|
||||
Pass the error message to `PlatformNotReady` as the first argument. Home Assistant will log the retry once with a log level of
|
||||
`warning`, and subsequent retries will be logged at `debug` level. Suppose you do not set a message when raising `ConfigEntryNotReady`; in that case, Home Assistant will try to extract the reason from the exception that is the cause of `ConfigEntryNotReady` if it was propagated from another exception.
|
||||
|
||||
The integration should not log any non-debug messages about the retry, and should instead rely on the logic built-in to `PlatformNotReady` to avoid spamming the logs.
|
||||
|
||||
## Handling expired credentials
|
||||
|
||||
Raise the `ConfigEntryAuthFailed` exception, and Home Assistant will automatically put the config entry in a failure state and start a reauth flow. The exception must be raised from `async_setup_entry` in `__init__.py` or from the `DataUpdateCoordinator` or the exception will not be effective at triggering the reauth flow. If your integration does not use a `DataUpdateCoordinator`, calling `entry.async_start_reauth()` can be used as an alternative to starting a reauth flow.
|
||||
|
||||
The `reauth` flow will be started with the following context variables, which are available in the `async_step_reauth` step:
|
||||
|
||||
- source: This will always be "SOURCE_REAUTH"
|
||||
- entry_id: The entry_id of the config entry that needs reauthentication
|
||||
- unique_id: The unique_id of the config entry that needs reauthentication
|
||||
|
||||
#### Example
|
||||
|
||||
```python
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Setup the config entry for my device."""
|
||||
device = MyDevice(entry.data[CONF_HOST])
|
||||
try:
|
||||
await device.async_setup()
|
||||
except AuthFailed as ex:
|
||||
raise ConfigEntryAuthFailed(f"Credentials expired for {device.name}") from ex
|
||||
except (asyncio.TimeoutError, TimeoutException) as ex:
|
||||
raise ConfigEntryNotReady(f"Timed out while connecting to {device.ipaddr}") from ex
|
||||
```
|
||||
|
Loading…
x
Reference in New Issue
Block a user