mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-19 07:16:29 +00:00
Release 0.91
This commit is contained in:
parent
40fc0f5a3d
commit
cf2fe9a108
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,108 @@
|
|||||||
|
---
|
||||||
|
title: Working with Async
|
||||||
|
id: version-0.91.0-asyncio_working_with_async
|
||||||
|
original_id: asyncio_working_with_async
|
||||||
|
---
|
||||||
|
|
||||||
|
Although we have a backwards compatible API, using the async core directly will be a lot faster. Most core components have already been rewritten to leverage the async core. This includes the EntityComponent helper (foundation of light, switch, etc), scripts, groups and automation.
|
||||||
|
|
||||||
|
## Interacting with the core
|
||||||
|
|
||||||
|
[All methods in the Home Assistant core][dev-docs] are implemented in two flavors: an async version and a version to be called from other threads. The versions for other are merely wrappers that call the async version in a threadsafe manner.
|
||||||
|
|
||||||
|
So if you are making calls to the core (the hass object) from within a callback or coroutine, use the methods that start with async_. If you need to call an async_ function that is a coroutine, your task must also be a coroutine.
|
||||||
|
|
||||||
|
## Implementing an async component
|
||||||
|
|
||||||
|
To make a component async, implement an async_setup.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def setup(hass, config):
|
||||||
|
# Setup your component outside of the event loop.
|
||||||
|
```
|
||||||
|
|
||||||
|
Will turn into:
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def async_setup(hass, config):
|
||||||
|
# Setup your component inside of the event loop.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementing an async platform
|
||||||
|
|
||||||
|
For platforms we support async setup. Instead of setup_platform you need to have a coroutine async_setup_platform.
|
||||||
|
|
||||||
|
```python
|
||||||
|
setup_platform(hass, config, add_entities, discovery_info=None):
|
||||||
|
# Setup your platform outside of the event loop.
|
||||||
|
```
|
||||||
|
|
||||||
|
Will turn into:
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities,
|
||||||
|
discovery_info=None):
|
||||||
|
# Setup your platform inside of the event loop
|
||||||
|
```
|
||||||
|
|
||||||
|
The only difference with the original parameters is that the `add_entities` function has been replaced by the async friendly callback `async_add_entities`.
|
||||||
|
|
||||||
|
## Implementing an async entity
|
||||||
|
|
||||||
|
You can make your entity async friendly by converting your update method to be async. This requires the dependency of your entities to also be async friendly!
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MyEntity(Entity):
|
||||||
|
def update(self):
|
||||||
|
"""Retrieve latest state."""
|
||||||
|
self._state = fetch_state()
|
||||||
|
```
|
||||||
|
|
||||||
|
Will turn into:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MyEntity(Entity):
|
||||||
|
async def async_update(self):
|
||||||
|
"""Retrieve latest state."""
|
||||||
|
self._state = await async_fetch_state()
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure that all properties defined on your entity do not result in I/O being done. All data has to be fetched inside the update method and cached on the entity. This is because these properties are read from within the event loop and thus doing I/O will result in the core of Home Assistant waiting until your I/O is done.
|
||||||
|
|
||||||
|
## Calling async functions from threads
|
||||||
|
|
||||||
|
Sometimes it will happen that you’re in a thread and you want to call a function that is only available as async. Home Assistant includes a few async helper utilities to help with this.
|
||||||
|
|
||||||
|
In the following example, `say_hello` will schedule `async_say_hello` and block till the function has run and get the result back.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
def say_hello(hass, target):
|
||||||
|
return asyncio.run_coroutine_threadsafe(
|
||||||
|
async_say_hello(hass, target), hass.loop).result()
|
||||||
|
|
||||||
|
async def async_say_hello(hass, target):
|
||||||
|
return "Hello {}!".format(target)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Calling sync functions from async
|
||||||
|
|
||||||
|
If you are running inside an async context, it might sometimes be necessary to call a sync function. Do this like this:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# hub.update() is a sync function.
|
||||||
|
result = await hass.async_add_executor_job(hub.update)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Starting independent task from async
|
||||||
|
|
||||||
|
If you want to spawn a task that will not block the current async context, you can choose to create it as a task on the event loop. It will then be executed in parallel.
|
||||||
|
|
||||||
|
```python
|
||||||
|
hass.async_create_task(async_say_hello(hass, target))
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[dev-docs]: https://dev-docs.home-assistant.io/en/master/api/core.html
|
||||||
|
[dev-docs-async]: https://dev-docs.home-assistant.io/en/dev/api/util.html#module-homeassistant.util.async
|
@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
title: Checklist for creating a component
|
||||||
|
id: version-0.91.0-creating_component_code_review
|
||||||
|
original_id: creating_component_code_review
|
||||||
|
---
|
||||||
|
|
||||||
|
A checklist of things to do when you're adding a new component.
|
||||||
|
|
||||||
|
> Not all existing platforms follow the requirements in this checklist. This cannot be used as a reason to not follow them!
|
||||||
|
|
||||||
|
### 0. Common
|
||||||
|
|
||||||
|
1. Follow our [Style guidelines](development_guidelines.md)
|
||||||
|
2. Use existing constants from [`const.py`](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/const.py)
|
||||||
|
* Only add new constants to `const.py` if they are widely used. Otherwise keep them on components level
|
||||||
|
|
||||||
|
### 1. Requirements
|
||||||
|
|
||||||
|
1. Requirement version pinned: `REQUIREMENTS = ['phue==0.8.1']`
|
||||||
|
2. We no longer want requirements hosted on GitHub. Please upload to PyPi.
|
||||||
|
3. Requirements should [only be imported inside functions](creating_component_deps_and_reqs.md). This is necessary because requirements are installed on the fly.
|
||||||
|
|
||||||
|
### 2. Configuration
|
||||||
|
|
||||||
|
1. Voluptuous schema present for [configuration validation](development_validation.md)
|
||||||
|
2. Default parameters specified in voluptuous schema, not in `setup(…)`
|
||||||
|
3. Schema using as many generic config keys as possible from `homeassistant.const`
|
||||||
|
4. If your component has platforms, define a `PLATFORM_SCHEMA` instead of a `CONFIG_SCHEMA`.
|
||||||
|
5. If using a `PLATFORM_SCHEMA` to be used with `EntityComponent`, import base from `homeassistant.helpers.config_validation`
|
||||||
|
6. Never depend on users adding things to `customize` to configure behavior inside your component.
|
||||||
|
|
||||||
|
### 3. Component/platform communication
|
||||||
|
|
||||||
|
1. If you need to share global data with platforms, use the dictionary `hass.data`. `hass.data[DATA_XY]` while `XY` is the component is preferred over `hass.data[DOMAIN]`.
|
||||||
|
2. If the component fetches data that causes its related platform entities to update, you can notify them using the dispatcher code in `homeassistant.helpers.dispatcher`.
|
||||||
|
|
||||||
|
|
||||||
|
### 4. Communication with devices/services
|
||||||
|
|
||||||
|
1. All API specific code has to be part of a third party library hosted on PyPi. Home Assistant should only interact with objects and not make direct calls to the API.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# bad
|
||||||
|
status = requests.get(url('/status'))
|
||||||
|
|
||||||
|
# good
|
||||||
|
from phue import Bridge
|
||||||
|
bridge = Bridge(...)
|
||||||
|
status = bridge.status()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Make your pull request as small as possible
|
||||||
|
Keep a new integration to the minimum functionality needed for someone to get value out of the integration. This allows reviewers to sign off on smaller chunks of code one at a time, and lets us get your new integration/features in sooner. **Pull requests containing large code dumps will not be a priority for review and may be closed.**
|
||||||
|
- Limit to a single platform
|
||||||
|
- Do not add features not needed to directly support the single platform (such as custom services)
|
||||||
|
- Do not mix clean-ups and new features in a single pull request.
|
||||||
|
- Do not solve several issues in a single pull request.
|
||||||
|
- Do not submit pull requests that depend on other work which is still unmerged.
|
||||||
|
|
||||||
|
### 6. Event names
|
||||||
|
Prefix component event names with the component name itself. For example, use `netatmo_person` instead of `person` for the `netatmo` component.
|
||||||
|
|
||||||
|
### 7. Tests
|
||||||
|
Strongly consider adding tests for your component to minimize future regressions.
|
@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
title: Example light platform
|
||||||
|
id: version-0.91.0-creating_platform_example_light
|
||||||
|
original_id: creating_platform_example_light
|
||||||
|
---
|
||||||
|
|
||||||
|
This example is for adding support for the imaginary Awesome Lights. It shows the different best practices for developing a platform.
|
||||||
|
|
||||||
|
Similar to Example Sensor Platform, copy the code below, and create it as a file in `<config_dir>/custom_components/awesomelights/light.py`.
|
||||||
|
|
||||||
|
Add the following to your configuration.yaml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
light:
|
||||||
|
- platform: awesomelights
|
||||||
|
host: HOST_HERE
|
||||||
|
username: USERNAME_HERE
|
||||||
|
password: PASSWORD_HERE_OR_secrets.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the `platform` name matches the directory name that contains the source code.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
# Import the device class from the component that you want to support
|
||||||
|
from homeassistant.components.light import ATTR_BRIGHTNESS, Light, PLATFORM_SCHEMA
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
|
# Home Assistant depends on 3rd party packages for API specific code.
|
||||||
|
REQUIREMENTS = ['awesome_lights==1.2.3']
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Validation of the user's configuration
|
||||||
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
|
vol.Required(CONF_HOST): cv.string,
|
||||||
|
vol.Optional(CONF_USERNAME, default='admin'): cv.string,
|
||||||
|
vol.Optional(CONF_PASSWORD): cv.string,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
"""Setup the Awesome Light platform."""
|
||||||
|
import awesomelights
|
||||||
|
|
||||||
|
# Assign configuration variables. The configuration check takes care they are
|
||||||
|
# present.
|
||||||
|
host = config.get(CONF_HOST)
|
||||||
|
username = config.get(CONF_USERNAME)
|
||||||
|
password = config.get(CONF_PASSWORD)
|
||||||
|
|
||||||
|
# Setup connection with devices/cloud
|
||||||
|
hub = awesomelights.Hub(host, username, password)
|
||||||
|
|
||||||
|
# Verify that passed in configuration works
|
||||||
|
if not hub.is_valid_login():
|
||||||
|
_LOGGER.error("Could not connect to AwesomeLight hub")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add devices
|
||||||
|
add_devices(AwesomeLight(light) for light in hub.lights())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AwesomeLight(Light):
|
||||||
|
"""Representation of an Awesome Light."""
|
||||||
|
|
||||||
|
def __init__(self, light):
|
||||||
|
"""Initialize an AwesomeLight."""
|
||||||
|
self._light = light
|
||||||
|
self._name = light.name
|
||||||
|
self._state = None
|
||||||
|
self._brightness = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the display name of this light."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def brightness(self):
|
||||||
|
"""Return the brightness of the light.
|
||||||
|
|
||||||
|
This method is optional. Removing it indicates to Home Assistant
|
||||||
|
that brightness is not supported for this light.
|
||||||
|
"""
|
||||||
|
return self._brightness
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return true if light is on."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
"""Instruct the light to turn on.
|
||||||
|
|
||||||
|
You can skip the brightness part if your light does not support
|
||||||
|
brightness control.
|
||||||
|
"""
|
||||||
|
self._light.brightness = kwargs.get(ATTR_BRIGHTNESS, 255)
|
||||||
|
self._light.turn_on()
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
"""Instruct the light to turn off."""
|
||||||
|
self._light.turn_off()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Fetch new state data for this light.
|
||||||
|
|
||||||
|
This is the only method that should fetch new data for Home Assistant.
|
||||||
|
"""
|
||||||
|
self._light.update()
|
||||||
|
self._state = self._light.is_on()
|
||||||
|
self._brightness = self._light.brightness
|
||||||
|
```
|
@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
title: Example sensor platform
|
||||||
|
id: version-0.91.0-creating_platform_example_sensor
|
||||||
|
original_id: creating_platform_example_sensor
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a minimum implementation of a platform for the sensor component.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
Copy the code below and create it as a file in `<config_dir>/custom_components/example/sensor.py`.
|
||||||
|
|
||||||
|
Add the following to your `configuration.yaml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Example configuration.yaml entry
|
||||||
|
sensor:
|
||||||
|
platform: example
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
```python
|
||||||
|
from homeassistant.const import TEMP_CELSIUS
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
"""Setup the sensor platform."""
|
||||||
|
add_devices([ExampleSensor()])
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleSensor(Entity):
|
||||||
|
"""Representation of a Sensor."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the sensor."""
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the sensor."""
|
||||||
|
return 'Example Temperature'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state of the sensor."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return the unit of measurement."""
|
||||||
|
return TEMP_CELSIUS
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Fetch new state data for the sensor.
|
||||||
|
|
||||||
|
This is the only method that should fetch new data for Home Assistant.
|
||||||
|
"""
|
||||||
|
self._state = 23
|
||||||
|
```
|
63
website/versioned_docs/version-0.91.0/dev_101_events.md
Normal file
63
website/versioned_docs/version-0.91.0/dev_101_events.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
title: Using Events
|
||||||
|
id: version-0.91.0-dev_101_events
|
||||||
|
original_id: dev_101_events
|
||||||
|
---
|
||||||
|
|
||||||
|
The core of Home Assistant is driven by events. That means that if you want to respond to something happening, you'll have to respond to events. Most of the times you won't interact directly with the event system but use one of the [event listener helpers][helpers].
|
||||||
|
|
||||||
|
The event system is very flexible. There are no limitations on the event type, as long as it's a string. Each event can contain data. The data is a dictionary that can contain any data as long as it's JSON serializable. This means that you can use number, string, dictionary and list.
|
||||||
|
|
||||||
|
[List of events that Home Assistant fires.][object]
|
||||||
|
|
||||||
|
## Firing events
|
||||||
|
|
||||||
|
To fire an event, you have to interact with the event bus. The event bus is available on the Home Assistant instance as `hass.bus`.
|
||||||
|
|
||||||
|
Example component that will fire an event when loaded. Note that custom event names are prefixed with the component name.
|
||||||
|
|
||||||
|
```python
|
||||||
|
DOMAIN = 'example_component'
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
"""Set up is called when Home Assistant is loading our component."""
|
||||||
|
|
||||||
|
# Fire event example_component_my_cool_event with event data answer=42
|
||||||
|
hass.bus.fire('example_component_my_cool_event', {
|
||||||
|
'answer': 42
|
||||||
|
})
|
||||||
|
|
||||||
|
# Return successful setup
|
||||||
|
return True
|
||||||
|
```
|
||||||
|
|
||||||
|
## Listening to events
|
||||||
|
|
||||||
|
Most of the times you'll not be firing events but instead listen to events. For example, the state change of an entity is broadcasted as an event.
|
||||||
|
|
||||||
|
```python
|
||||||
|
DOMAIN = 'example_component'
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
"""Set up is called when Home Assistant is loading our component."""
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
# Listener to handle fired events
|
||||||
|
def handle_event(event):
|
||||||
|
nonlocal count
|
||||||
|
count += 1
|
||||||
|
print('Answer {0} is: {1}'.format(count, event.data.get('answer')))
|
||||||
|
|
||||||
|
# Listen for when example_component_my_cool_event is fired
|
||||||
|
hass.bus.listen('example_component_my_cool_event', handle_event)
|
||||||
|
|
||||||
|
# Return successful setup
|
||||||
|
return True
|
||||||
|
```
|
||||||
|
|
||||||
|
### Helpers
|
||||||
|
|
||||||
|
Home Assistant comes with a lot of bundled helpers to listen to specific types of event. There are helpers to track a point in time, to track a time interval, a state change or the sun set. [See available methods.][helpers]
|
||||||
|
|
||||||
|
[helpers]: https://dev-docs.home-assistant.io/en/master/api/helpers.html#module-homeassistant.helpers.event
|
||||||
|
[object]: https://www.home-assistant.io/docs/configuration/events/
|
68
website/versioned_docs/version-0.91.0/entity_media_player.md
Normal file
68
website/versioned_docs/version-0.91.0/entity_media_player.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
title: Media Player Entity
|
||||||
|
sidebar_label: Media Player
|
||||||
|
id: version-0.91.0-entity_media_player
|
||||||
|
original_id: entity_media_player
|
||||||
|
---
|
||||||
|
|
||||||
|
> This entry is incomplete. Contribution welcome.
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
> Properties should always only return information from memory and not do I/O (like network requests). Implement `update()` or `async_update()` to fetch data.
|
||||||
|
|
||||||
|
| Name | Type | Default | Description
|
||||||
|
| ---- | ---- | ------- | -----------
|
||||||
|
| sound_mode | string | None | The current sound mode of the media player
|
||||||
|
| sound_mode_list | list | None | Dynamic list of available sound modes (set by platform, empty means sound mode not supported)
|
||||||
|
| source | string | None | The currently selected input source for the media player.
|
||||||
|
| source_list | list | None | The list of possible input sources for the media player. (This list should contain human readable names, suitible for frontend display)
|
||||||
|
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
### Select sound mode
|
||||||
|
Optional. Switch the sound mode of the media player.
|
||||||
|
|
||||||
|
class MyMediaPlayer(MediaPlayerDevice):
|
||||||
|
# Implement one of these methods.
|
||||||
|
|
||||||
|
def select_sound_mode(self, sound_mode):
|
||||||
|
"""Switch the sound mode of the entity."""
|
||||||
|
|
||||||
|
def async_select_sound_mode(self, sound_mode):
|
||||||
|
"""Switch the sound mode of the entity."""
|
||||||
|
|
||||||
|
### Select source
|
||||||
|
Optional. Switch the selected input source for the media player.
|
||||||
|
|
||||||
|
class MyMediaPlayer(MediaPlayerDevice):
|
||||||
|
# Implement one of these methods.
|
||||||
|
|
||||||
|
def select_source(self, source):
|
||||||
|
"""Select input source."""
|
||||||
|
|
||||||
|
def async_select_source(self, source):
|
||||||
|
"""Select input source."""
|
||||||
|
|
||||||
|
### Mediatype
|
||||||
|
Required. Returns one of the defined constants from the below list that matches the mediatype
|
||||||
|
|
||||||
|
| CONST |
|
||||||
|
|-------|
|
||||||
|
|MEDIA_TYPE_MUSIC|
|
||||||
|
|MEDIA_TYPE_TVSHOW|
|
||||||
|
|MEDIA_TYPE_MOVIE|
|
||||||
|
|MEDIA_TYPE_VIDEO|
|
||||||
|
|MEDIA_TYPE_EPISODE|
|
||||||
|
|MEDIA_TYPE_CHANNEL|
|
||||||
|
|MEDIA_TYPE_PLAYLIST|
|
||||||
|
|MEDIA_TYPE_IMAGE|
|
||||||
|
|MEDIA_TYPE_URL|
|
||||||
|
|MEDIA_TYPE_GAME|
|
||||||
|
|
||||||
|
class MyMediaPlayer(MediaPlayerDevice):
|
||||||
|
# Implement the following method.
|
||||||
|
|
||||||
|
def media_content_type(self):
|
||||||
|
"""Content type of current playing media."""
|
||||||
|
|
32
website/versioned_docs/version-0.91.0/entity_sensor.md
Normal file
32
website/versioned_docs/version-0.91.0/entity_sensor.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
title: Sensor Entity
|
||||||
|
sidebar_label: Sensor
|
||||||
|
id: version-0.91.0-entity_sensor
|
||||||
|
original_id: entity_sensor
|
||||||
|
---
|
||||||
|
|
||||||
|
A sensor is a read-only entity that provides some information. Information has a value and optionally, a unit of measurement.
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
> Properties should always only return information from memory and not do I/O (like network requests). Implement `update()` or `async_update()` to fetch data.
|
||||||
|
|
||||||
|
| Name | Type | Default | Description
|
||||||
|
| ---- | ---- | ------- | -----------
|
||||||
|
| state | string | **Required** | The value of the sensor.
|
||||||
|
| unit_of_measurement | string | `None` | The unit of measurement that the sensor is expressed in.
|
||||||
|
| device_class | string | `None` | Type of sensor.
|
||||||
|
|
||||||
|
### Available device classes
|
||||||
|
|
||||||
|
If specifying a device class, your sensor entity will need to also return the correct unit of measurement.
|
||||||
|
|
||||||
|
| Type | Unit | Description
|
||||||
|
| ---- | ---- | -----------
|
||||||
|
| battery | % | % of battery that is left.
|
||||||
|
| humidity | % | % of humidity in the air.
|
||||||
|
| illuminance | lx/lm | Light level.
|
||||||
|
| temperature | °C/°F | Temperature.
|
||||||
|
| timestamp | ISO8601 | Timestamp.
|
||||||
|
| power | W,kW | Power.
|
||||||
|
| pressure | hPa,mbar | Pressure.
|
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
title: Integration Quality Scale
|
||||||
|
sidebar_label: Introduction
|
||||||
|
id: version-0.91.0-integration_quality_scale_index
|
||||||
|
original_id: integration_quality_scale_index
|
||||||
|
---
|
||||||
|
|
||||||
|
The Integration Quality Scale scores each integration based on the code quality and user experience. Each level of the quality scale consists of a list of requirements. If an integration matches all requirements, it's considered to have reached that level.
|
||||||
|
|
||||||
|
> Suggestions for changes can be done by creating an issue in the [architecture repo](https://github.com/home-assistant/architecture/issues/).
|
||||||
|
|
||||||
|
# No score
|
||||||
|
|
||||||
|
This integration passes the bare minimum requirements to become part of the index.
|
||||||
|
|
||||||
|
- Satisfy all requirements for [creating components](creating_component_code_review.md) and [creating platforms](creating_platform_code_review.md).
|
||||||
|
- Configurable via `configuration.yaml`
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
- Connection/configuration is handled via a component.
|
||||||
|
- Set an appropriate `SCAN_INTERVAL` (if a polling integration)
|
||||||
|
- Raise `PlatformNotReady` 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.
|
||||||
|
- 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](entity_index.md#generic-properties))
|
||||||
|
- Entities have unique ID (if available) ([docs](entity_registry_index.md#unique-id-requirements))
|
||||||
|
|
||||||
|
# Gold 🥇
|
||||||
|
|
||||||
|
This is a solid integration that is able to survive poor conditions and can be configured via the user interface.
|
||||||
|
|
||||||
|
- Configurable via config entries.
|
||||||
|
- Don't allow configuring already configured device/service (example: no 2 entries for same hub)
|
||||||
|
- Tests for the config flow
|
||||||
|
- Discoverable (if available)
|
||||||
|
- Entities have device info (if available) ([docs](device_registry_index.md#defining-devices))
|
||||||
|
- States are translated in the frontend (text-based sensors only, [docs](internationalization_index.md))
|
||||||
|
- Tests for reading data from/controlling the integration ([docs](development_testing.md))
|
||||||
|
- Has a code owner
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
- Set appropriate `PARALLEL_UPDATES` constant
|
||||||
|
- Support config entry unloading (called when config entry is removed)
|
||||||
|
- Integration + dependency are async
|
||||||
|
- Uses aiohttp and allows passing in websession (if making HTTP requests)
|
||||||
|
|
||||||
|
# Internal 🏠
|
||||||
|
|
||||||
|
Integrations which are part of Home Assistant are not rated but marked as **internal**.
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
[
|
[
|
||||||
|
"0.91.0",
|
||||||
"0.90.0",
|
"0.90.0",
|
||||||
"0.89.0",
|
"0.89.0",
|
||||||
"0.88.0",
|
"0.88.0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user