Add version 0.74.0

This commit is contained in:
Paulus Schoutsen 2018-07-25 22:34:04 +02:00
parent dfcbf9a891
commit 8503275f05
9 changed files with 855 additions and 0 deletions

View File

@ -0,0 +1,108 @@
---
title: Working with Async
id: version-0.74.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 youre 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
from homeassistant.util.async_ import run_callback_threadsafe
def say_hello(hass, target):
return run_callback_threadsafe(
hass.loop, async_say_hello, target).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

View File

@ -0,0 +1,89 @@
---
title: Authentication API
sidebar_label: API
id: version-0.74.0-auth_api
original_id: auth_api
---
> This is experimental. It is not persisted and is not yet intended for production.
This page will describe the steps required to fetch an access token for a user and how to refresh it. We follow the OAuth 2 specification.
## Requirements
A client needs to be created inside Home Assistant before a client can request users to authorize it or fetch a new access token. The only way currently to create a client is programmatically:
```python
client = await hass.auth.async_get_or_create_client(
'Example client',
redirect_uris=['http://www.example.com/hass_callback']
)
print(client.id)
```
## Authorize
[![Authorization flow sequence diagram](/img/en/auth/authorize_flow.png)](https://www.websequencediagrams.com/?lz=dGl0bGUgQXV0aG9yaXphdGlvbiBGbG93CgpVc2VyIC0-IENsaWVudDogTG9nIGludG8gSG9tZSBBc3Npc3RhbnQKABoGIC0-IFVzZXI6AEMJZSB1cmwgAD4JACgOOiBHbyB0bwAeBWFuZCBhAC0ICgBQDgB1DACBFw5jb2RlAHELAE4RZXQgdG9rZW5zIGZvcgAoBgBBGlQAJQUK&s=qsd)
- The authorize url should contain `client_id`, `redirect_uri` and, if available, `client_secret` as query parameters. Example: `http://your-instance.com/auth/authorize?client_id=ABCDE&client_secret=QWERTY&redirect_uri=https%3A%2F%2Fexample.com%2Fhass_callback`
- The user will navigate to this link, log into Home Assistant and authorize the client.
- Once authorized, the user will be redirected back to the passed in redirect uri with the authorization code as part of the query parameters. Example: https://example.com/hass_callback?code=12345
- This authorization code can be exchanged for tokens by sending it to the token endpoint (see next section).
- As specified in the OAuth 2 specification, it is possible to pass an optional state string to the authorize url using the `state` query parameter. This string will be added as query parameter to the redirect url.
## Token
The token endpoint returns tokens given valid grants. This grant is either an authorization code retrieved from the authorize endpoint or a refresh token.
All interactions with this endpoint need to be HTTP POST requests to `http://your-instance.com/auth/token` with the request body encoded in `application/x-www-form-urlencoded`.
### Authorization code
Use the grant type `authorization_code` to retrieve the tokens after a user has successfully finished the authorize step. The request body is:
```
grant_type=authorization_code&code=12345
```
The return response will be an access and refresh token:
```json
{
"access_token": "ABCDEFGH",
"expires_in": 1800,
"refresh_token": "IJKLMNOPQRST",
"token_type": "Bearer"
}
```
### Refresh token
Use the grant type `refresh_token` to retrieve an access token using a refresh token. The request body is:
```
grant_type=refresh_token&refresh_token=QWERTY
```
The return response will be an access token:
```json
{
"access_token": "ABCDEFGH",
"expires_in": 1800,
"token_type": "Bearer"
}
```
## Making authenticated requests
Once you have an access token, you can make authenticated requests to the Home Assistant APIs.
For the websocket connection, pass the access token in the [authentication message](https://developers.home-assistant.io/docs/en/external_api_websocket.html#authentication-phase).
For HTTP requests, pass the token type and access token as the authorization header:
```
Authorization: Bearer ABCDEFGH
```
If the access token is no longer valid, you will get a response with HTTP status code 401 unauthorized. This means that you will need to refresh the token. If the refresh token doesn't work, the tokens are no longer valid and the client should ask the user to authorize again.

View File

@ -0,0 +1,45 @@
---
title: Media Player Entity
sidebar_label: Media Player
id: version-0.74.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."""

View File

@ -0,0 +1,57 @@
---
title: Vacuum Entity
sidebar_label: Vacuum
id: version-0.74.0-entity_vacuum
original_id: entity_vacuum
---
## 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
| ---- | ---- | ------- | -----------
| name | string | **Required** | Name of the device.
| state | string | **Required** | One of the states listed in the states section.
| battery_level | int | `none` | Current battery level.
| battery_icon | string | function | Battery icon to show in UI.
| cleaning_mode | string | `none` | The current cleaning mode.
| cleaning_mode_list | list | `NotImplementedError()`| List of avaliable fan speeds and cleaning modes.
| error | string | **Required** with `STATE_ERROR` | An error message if the vacuum is in `STATE_ERROR`.
## States
| State | Description
| ----- | -----------
| `STATE_CLEANING` | The vacuum is currently cleaning.
| `STATE_DOCKED` | The vacuum is currently docked, it is assumed that docked can also mean charging.
| `STATE_PAUSED` | The vacuum was cleaning but was paused without returning to the dock.
| `STATE_IDLE` | The vacuum is not paused, not docked and does not have any errors.
| `STATE_RETURNING` | The vacuum is done cleaning and is currently returning to the dock, but not yet docked.
| `STATE_ERROR` | The vacuum encountered an error while cleaning, the error can be specified as a property on the entity.
## Methods
### `turn_on` or `async_turn_on`
Turn the vacuum on and start cleaning.
### `turn_off`or `async_turn_off`
Turn the vacuum off stopping the cleaning and returning home.
### `return_to_base` or `async_return_to_base`
Set the vacuum cleaner to return to the dock.
### `stop` or `async_stop`
Stop the vacuum cleaner, do not return to base.
### `clean_spot` or `async_clean_spot`
Perform a spot clean-up.
### `locate` or `async_locate`
Locate the vacuum cleaner.
### `set_cleaning_mode` or `async_set_cleaning_mode`
Set the cleaning mode.
### `send_command` or `async_send_command`
Send a command to a vacuum cleaner.

View File

@ -0,0 +1,180 @@
---
title: Tutorial: Making your first add-on
id: version-0.74.0-hassio_addon_tutorial
original_id: hassio_addon_tutorial
---
So you've got Home Assistant going and you've been enjoying the built-in add-ons but you're missing this one application. Time to make your own add-on! In Hass.io 0.24 we introduced the option to have local add-ons be build on your device. This is great for developing new add-ons locally.
To get started with developing add-ons, we first need access to where Hass.io looks for local add-ons. For this you can use the Samba add-on or the SSH add-on.
For Samba, once you have enabled and started it, your Hass.io instance will show up in your local network tab and share a folder called "addons". This is the folder to store your custom add-ons.
If you are on macOS and the folder is not showing up automatically, go to Finder and press CMD+K then enter 'smb://hassio.local'
![Screenshot of Windows Explorer showing a folder on the Hass.io server](/img/en/hass.io/tutorial/samba.png)
For SSH, you will have to install it. Before you can start it, you will have to have a private/public key pair and store your public key in the add-on config ([see docs for more info][ssh]). Once started, you can SSH to Hass.io and store your custom add-ons in "/addons".
![Screenshot of Putty connected to Hass.io](/img/en/hass.io/tutorial/ssh.png)
Once you have located your add-on directory, it's time to get started!
[ssh]: https://www.home-assistant.io/addons/ssh/
## Step 1: The basics
- Create a new directory called `hello_world`
- Inside that directory create three files.
`Dockerfile`:
```
ARG BUILD_FROM
FROM $BUILD_FROM
ENV LANG C.UTF-8
# Copy data for add-on
COPY run.sh /
RUN chmod a+x /run.sh
CMD [ "/run.sh" ]
```
`config.json`:
```json
{
"name": "Hello world",
"version": "1",
"slug": "hello_world",
"description": "My first real add-on!",
"startup": "before",
"boot": "auto",
"options": {},
"schema": {}
}
```
`run.sh`:
```bash
echo Hello world!
```
Make sure your editor is using UNIX-like line breaks (LF), not Dos/Windows (CRLF).
## Step 2: Installing and testing your add-on
Now comes the fun part, time to open the Hass.io UI and install and run your add-on.
- Open the Home Assistant frontend
- Go to the Hass.io panel
- On the top right click the shopping basket to go to the add-on store.
![Screenshot of the Hass.io main panel](/img/en/hass.io/screenshots/main_panel_addon_store.png)
- On the top right click the refresh button
- You should now see a new card called "Local" that lists your add-on!
![Screenshot of the local repository card](/img/en/hass.io/screenshots/local_repository.png)
- Click on your add-on to go to the add-on details page.
- Install your add-on
- Start your add-on
- Refresh the logs of your add-on, you should now see "Hello world!" in your logs.
![Screenshot of the add-on logs](/img/en/hass.io/tutorial/addon_hello_world_logs.png)
### I don't see my add-on?!
Oops! You clicked refresh in the store and your add-on didn't show up. Or maybe you just updated an option, clicked refresh and saw your add-on disappear.
When this happens, it means that your `config.json` is invalid. It's either invalid JSON or one of the specified options is incorrect. To see what went wrong, go to the Hass.io panel and in the supervisor card click on "View logs". This should bring you to a page with the logs of the supervisor. Scroll to the bottom and you should be able to find the validation error.
Once you fixed the error, go to the add-on store and click refresh again.
## Step 3: Hosting a server
Until now we've been able to do some basic stuff, but it's not very useful yet. So let's take it one step further and host a server that we expose on a port. For this we're going to use the built-in HTTP server that comes with Python 3.
To do this, we will need to update our files as follows:
- `Dockerfile`: Install Python 3
- `config.json`: Make the port from the container available on the host
- `run.sh`: Run the Python 3 command to start the HTTP server
Add to your `Dockerfile` before `RUN`:
```
# Install requirements for add-on
RUN apk add --no-cache python3
# Python 3 HTTP Server serves the current working dir
# So let's set it to our add-on persistent data directory.
WORKDIR /data
```
Add "ports" to `config.json`. This will make TCP on port 8000 inside the container available on the host on port 8000.
```json
{
"name": "Hello world",
"version": "0.2",
"slug": "hello_world",
"description": "My first real add-on!",
"startup": "before",
"boot": "auto",
"options": {},
"schema": {},
"ports": {
"8000/tcp": 8000
}
}
```
Update `run.sh` to start the Python 3 server:
```
python3 -m http.server
```
## Step 4: Installing the update
Since we updated the version number in our `config.json`, Home Assistant will show an update button when looking at the add-on details. You might have to refresh your browser or click the refresh button in the add-on store for it to show up. If you did not update the version number, you can also uninstall and install the add-on again. After installing the add-on again, make sure you start it.
Now navigate to [http://hassio.local:8000](http://hassio.local:8000) to see our server in action!
![Screenshot of the file index served by the add-on](/img/en/hass.io/tutorial/python3-http-server.png)
## Bonus: Working with add-on options
In the screenshot you've probably seen that our server only served up 1 file: `options.json`. This file contains the user configuration for this add-on. Because we specified an empty "config" and "schema" in our `config.json`, the file is currently empty.
Let's see if we can get some data into that file!
To do this, we need to specify the default options and a schema for the user to change the options.
Change the options and schema entries in your `config.json` with the following:
```json
{
"options": {
"beer": true,
"wine": true,
"liquor": false,
"name": "world",
"year": 2017
},
"schema": {
"beer": "bool",
"wine": "bool",
"liquor": "bool",
"name": "str",
"year": "int"
},
}
```
Refresh the add-on store and re-install your add-on. You will now see the options available in the add-on config screen. When you now go back to our Python 3 server and download `options.json`, you'll see the options you set. [Example of how options.json can be used inside `run.sh`](https://github.com/home-assistant/hassio-addons/blob/master/mosquitto/run.sh#L4-L6)

View File

@ -0,0 +1,13 @@
---
title: Internationalization
id: version-0.74.0-internationalization_index
original_id: internationalization_index
---
The Home Assistant internationalization project includes preparing platforms and the frontend for localization, as well as the actual translation of localized strings.
Some components and platforms will have strings that need to be localized specifically for that platform. These strings are managed in the core [home-assistant](https://github.com/home-assistant/home-assistant) repository. The Home Assistant backend will serve strings to the clients based on the loaded components in the running instance.
There are also localizable strings that exist only on the frontend. These strings are managed in the [home-assistant-polymer](https://github.com/home-assistant/home-assistant-polymer) repository. These strings are stored with the frontend and dont depend on the backend configuration.
Our strings are translated by the community using the online translation tool [Lokalise](https://lokalise.co/).

View File

@ -0,0 +1,211 @@
---
title: Lovelace: Custom Cards
id: version-0.74.0-lovelace_custom_card
original_id: lovelace_custom_card
---
[Lovelace](https://www.home-assistant.io/lovelace/) is our new approach to defining your user interface for Home Assistant. We offer a lot of built-in cards, but you're not just limited to the ones that we decided to include in the Lovelace UI. You can build and use your own!
## API
You define your custom card as a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements). It's up to you to decide how to render your DOM inside your element. You can use Polymer, Angular, Preact or any other popular framework (except for React [more info on React here](https://custom-elements-everywhere.com/#react)).
```js
const element = document.createElement('some-custom-card');
```
Home Assistant will call `setConfig(config)` when the configuration changes (rare). If you throw an exception if the configuration is invalid, Lovelace will render an error card to notify the user.
```js
try {
element.setConfig(config);
} catch (err) {
showErrorCard(err.message, config);
}
```
Home Assistant will set the `hass` property when the state of Home Assistant changes (frequent). Whenever the state changes, the component will have to update itself to represent the latest state.
```js
element.hass = hass;
```
Your card can define a `getCardSize` method that returns the size of your card as a number. A height of 1 is equivalent to 50 pixels. This will help Home Assistant distribute the cards evenly over the columns. A card size of `1` will be assumed if the method is not defined.
```js
if ('getCardSize' in element) {
return element.getCardSize();
} else {
return 1;
}
```
## Defining your card
Create a new file in your Home Assistant config dir as `<config>/www/content-card-example.js` and put in the following contents:
```js
class ContentCardExample extends HTMLElement {
set hass(hass) {
if (!this.content) {
const card = document.createElement('ha-card');
card.header = 'Example card';
this.content = document.createElement('div');
this.content.style.padding = '0 16px 16px';
card.appendChild(this.content);
this.appendChild(card);
}
const entityId = this.config.entity;
const state = hass.states[entityId];
const stateStr = state ? state.state : 'unavailable';
this.content.innerHTML = `
The state of ${entityId} is ${stateStr}!
<br><br>
<img src="http://via.placeholder.com/350x150">
`;
}
setConfig(config) {
if (!config.entity) {
throw new Error('You need to define an entity');
}
this.config = config;
}
// The height of your card. Home Assistant uses this to automatically
// distribute all cards over the available columns.
getCardSize() {
return 3;
}
}
customElements.define('content-card-example', ContentCardExample);
```
## Referencing your new card
In our example card we defined a card with the tag `content-card-example` (see last line), so our card type will be `custom:content-card-example`. And because you created the file in your `<config>/www` directory, it will be accessible in your browser via the url `/local/`.
```yaml
# Example ui-lovelace.yaml
resources:
- url: /local/content-card-example.js
type: js
views:
- name: Example
cards:
- type: "custom:content-card-example"
entity: input_boolean.switch_tv
```
## Advanced example
Resources to load in Lovelace can be imported as a JS script, an HTML import or as a JS module import. Below is an example of a custom card using JS modules that does all the fancy things.
![Screenshot of the wired card](/img/en/frontend/lovelace-ui-custom-card-screenshot.png)
Create a new file in your Home Assistant config dir as `<config>/www/wired-cards.js` and put in the following contents:
```js
import 'https://unpkg.com/wired-card@0.6.5/wired-card.js?module';
import 'https://unpkg.com/wired-toggle@0.6.5/wired-toggle.js?module';
import {
LitElement, html
} from 'https://unpkg.com/@polymer/lit-element@^0.5.2/lit-element.js?module';
function loadCSS(url) {
const link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
document.head.appendChild(link);
}
loadCSS('https://fonts.googleapis.com/css?family=Gloria+Hallelujah');
class WiredToggleCard extends LitElement {
static get properties() {
return {
hass: Object,
config: Object,
}
}
_render({ hass, config }) {
return html`
<style>
:host {
font-family: 'Gloria Hallelujah', cursive;
}
wired-card {
background-color: white;
padding: 16px;
display: block;
font-size: 18px;
}
.state {
display: flex;
justify-content: space-between;
padding: 8px;
align-items: center;
}
wired-toggle {
margin-left: 8px;
}
</style>
<wired-card elevation="2">
${config.entities.map(ent => hass.states[ent]).map((state) =>
html`
<div class='state'>
${state.attributes.friendly_name}
<wired-toggle
checked="${state.state === 'on'}"
on-change="${ev => this._toggle(state)}"
></wired-toggle>
</div>
`
)}
</wired-card>
`;
}
setConfig(config) {
if (!config.entities) {
throw new Error('You need to define entities');
}
this.config = config;
}
// The height of your card. Home Assistant uses this to automatically
// distribute all cards over the available columns.
getCardSize() {
return this.config.entities.length + 1;
}
_toggle(state) {
this.hass.callService('homeassistant', 'toggle', {
entity_id: state.entity_id
});
}
}
customElements.define('wired-toggle-card', WiredToggleCard);
```
And for your configuration:
```yaml
# Example ui-lovelace.yaml
resources:
- url: /local/wired-cards.js
type: module
views:
- name: Example
cards:
- type: "custom:wired-toggle-card"
entities:
- input_boolean.switch_ac_kitchen
- input_boolean.switch_ac_livingroom
- input_boolean.switch_tv
```

View File

@ -0,0 +1,151 @@
{
"version-0.74.0-Architecture": {
"Architecture": [
"version-0.74.0-architecture_index",
"version-0.74.0-architecture_components",
"version-0.74.0-architecture_entities",
"version-0.74.0-architecture_hassio"
],
"Entities": [
"version-0.74.0-entity_index",
"version-0.74.0-entity_alarm_control_panel",
"version-0.74.0-entity_binary_sensor",
"version-0.74.0-entity_climate",
"version-0.74.0-entity_cover",
"version-0.74.0-entity_fan",
"version-0.74.0-entity_light",
"version-0.74.0-entity_lock",
"version-0.74.0-entity_media_player",
"version-0.74.0-entity_remote",
"version-0.74.0-entity_sensor",
"version-0.74.0-entity_switch",
"version-0.74.0-entity_vacuum",
"version-0.74.0-entity_weather"
],
"Authentication": [
"version-0.74.0-auth_index",
"version-0.74.0-auth_api",
"version-0.74.0-auth_auth_provider"
],
"Configuration.yaml": [
"version-0.74.0-configuration_yaml_index"
],
"Config Entries": [
"version-0.74.0-config_entries_index",
"version-0.74.0-config_entries_config_flow_handler"
],
"Data Entry Flow": [
"version-0.74.0-data_entry_flow_index"
],
"Entity Registry": [
"version-0.74.0-entity_registry_index"
]
},
"version-0.74.0-Extending Frontend": {
"Frontend": [
"version-0.74.0-frontend_index",
"version-0.74.0-frontend_architecture",
"version-0.74.0-frontend_development"
],
"Extending the frontend": [
"version-0.74.0-frontend_add_card",
"version-0.74.0-frontend_add_more_info",
"version-0.74.0-frontend_add_websocket_api"
],
"Custom UI": [
"version-0.74.0-lovelace_custom_card",
"version-0.74.0-frontend_creating_custom_ui",
"version-0.74.0-frontend_creating_custom_panels"
]
},
"version-0.74.0-Extending HASS": {
"Developing a feature": [
"version-0.74.0-development_index",
"version-0.74.0-development_environment",
"version-0.74.0-development_submitting",
"version-0.74.0-development_checklist",
"version-0.74.0-development_guidelines",
"version-0.74.0-development_testing",
"version-0.74.0-development_catching_up",
"version-0.74.0-development_validation",
"version-0.74.0-development_typing"
],
"Development 101": [
"version-0.74.0-dev_101_index",
"version-0.74.0-dev_101_hass",
"version-0.74.0-dev_101_events",
"version-0.74.0-dev_101_states",
"version-0.74.0-dev_101_services",
"version-0.74.0-dev_101_config"
],
"Creating Platforms": [
"version-0.74.0-creating_platform_index",
"version-0.74.0-creating_platform_code_review",
"version-0.74.0-creating_platform_example_light",
"version-0.74.0-creating_platform_example_sensor"
],
"Creating Components": [
"version-0.74.0-creating_component_index",
"version-0.74.0-creating_component_code_review",
"version-0.74.0-creating_component_deps_and_reqs",
"version-0.74.0-creating_component_events",
"version-0.74.0-creating_component_states",
"version-0.74.0-creating_component_discovery",
"version-0.74.0-creating_component_loading",
"version-0.74.0-creating_component_generic_discovery"
]
},
"version-0.74.0-Misc": {
"Introduction": [
"version-0.74.0-misc"
],
"External API": [
"version-0.74.0-external_api_rest",
"version-0.74.0-external_api_rest_python",
"version-0.74.0-external_api_websocket",
"version-0.74.0-external_api_server_sent_events"
],
"Internationalization": [
"version-0.74.0-internationalization_index",
"version-0.74.0-internationalization_backend_localization",
"version-0.74.0-internationalization_custom_component_localization",
"version-0.74.0-internationalization_translation"
],
"Documentation": [
"version-0.74.0-documentation_index",
"version-0.74.0-documentation_standards",
"version-0.74.0-documentation_create_page"
],
"Intents": [
"version-0.74.0-intent_index",
"version-0.74.0-intent_firing",
"version-0.74.0-intent_handling",
"version-0.74.0-intent_conversation",
"version-0.74.0-intent_builtin"
],
"asyncio": [
"version-0.74.0-asyncio_index",
"version-0.74.0-asyncio_101",
"version-0.74.0-asyncio_categorizing_functions",
"version-0.74.0-asyncio_working_with_async"
],
"Hass.io": [
"version-0.74.0-hassio_debugging",
"version-0.74.0-hassio_hass"
],
"Hass.io Add-Ons": [
"version-0.74.0-hassio_addon_index",
"version-0.74.0-hassio_addon_tutorial",
"version-0.74.0-hassio_addon_config",
"version-0.74.0-hassio_addon_communication",
"version-0.74.0-hassio_addon_testing",
"version-0.74.0-hassio_addon_publishing",
"version-0.74.0-hassio_addon_presentation",
"version-0.74.0-hassio_addon_repository"
],
"Maintainer docs": [
"version-0.74.0-maintenance",
"version-0.74.0-releasing"
]
}
}

View File

@ -1,4 +1,5 @@
[
"0.74.0",
"0.73.0",
"0.72"
]