New Crowdin translations (#258)

* New translations frontend_external_auth.md (Norwegian)

* New translations frontend_development.md (Norwegian)

* New translations frontend_data.md (Norwegian)

* New translations frontend_creating_custom_ui.md (Norwegian)

* New translations frontend_creating_custom_panels.md (Norwegian)

* New translations hassio_addon_tutorial.md (Norwegian)

* New translations hassio_hass.md (Norwegian)

* New translations frontend_add_websocket_api.md (Norwegian)

* New translations internationalization_translation.md (Norwegian)

* New translations en.json (Norwegian)

* New translations releasing.md (Norwegian)

* New translations misc.md (Norwegian)

* New translations maintenance.md (Norwegian)

* New translations lovelace_index.md (Norwegian)

* New translations documentation_index.md (Korean)

* New translations hassio_hass.md (Korean)

* New translations lovelace_custom_card.md (Norwegian)

* New translations internationalization_index.md (Norwegian)

* New translations integration_quality_scale_index.md (Norwegian)

* New translations internationalization_custom_component_localization.md (Norwegian)

* New translations internationalization_backend_localization.md (Norwegian)

* New translations intent_index.md (Norwegian)

* New translations intent_handling.md (Norwegian)

* New translations intent_firing.md (Norwegian)

* New translations intent_conversation.md (Norwegian)

* New translations intent_builtin.md (Norwegian)

* New translations frontend_architecture.md (Norwegian)

* New translations frontend_add_more_info.md (Norwegian)

* New translations app_integration_notifications.md (Polish)

* New translations development_validation.md (Norwegian)

* New translations entity_alarm_control_panel.md (Norwegian)

* New translations entity_air_quality.md (Norwegian)

* New translations documentation_standards.md (Norwegian)

* New translations documentation_index.md (Norwegian)

* New translations documentation_create_page.md (Norwegian)

* New translations device_registry_index.md (Norwegian)

* New translations development_typing.md (Norwegian)

* New translations entity_climate.md (Norwegian)

* New translations development_testing.md (Norwegian)

* New translations development_submitting.md (Norwegian)

* New translations development_index.md (Norwegian)

* New translations development_guidelines.md (Norwegian)

* New translations development_environment.md (Norwegian)

* New translations development_checklist.md (Norwegian)

* New translations development_catching_up.md (Norwegian)

* New translations entity_binary_sensor.md (Norwegian)

* New translations entity_cover.md (Norwegian)

* New translations frontend_add_card.md (Norwegian)

* New translations entity_vacuum.md (Norwegian)

* New translations external_api_websocket.md (Norwegian)

* New translations external_api_server_sent_events.md (Norwegian)

* New translations external_api_rest_python.md (Norwegian)

* New translations external_api_rest.md (Norwegian)

* New translations entity_weather.md (Norwegian)

* New translations entity_water_heater.md (Norwegian)

* New translations entity_switch.md (Norwegian)

* New translations entity_fan.md (Norwegian)

* New translations entity_sensor.md (Norwegian)

* New translations entity_remote.md (Norwegian)

* New translations entity_registry_index.md (Norwegian)

* New translations entity_media_player.md (Norwegian)

* New translations entity_lock.md (Norwegian)

* New translations entity_light.md (Norwegian)

* New translations entity_index.md (Norwegian)

* New translations app_integration_index.md (Polish)

* New translations app_integration_sending_data.md (Polish)

* New translations dev_101_services.md (Norwegian)

* New translations documentation_create_page.md (Polish)

* New translations entity_climate.md (Polish)

* New translations entity_binary_sensor.md (Polish)

* New translations entity_alarm_control_panel.md (Polish)

* New translations entity_air_quality.md (Polish)

* New translations documentation_standards.md (Polish)

* New translations documentation_index.md (Polish)

* New translations device_registry_index.md (Polish)

* New translations entity_fan.md (Polish)

* New translations development_validation.md (Polish)

* New translations development_typing.md (Polish)

* New translations development_testing.md (Polish)

* New translations development_submitting.md (Polish)

* New translations development_index.md (Polish)

* New translations development_guidelines.md (Polish)

* New translations development_checklist.md (Polish)

* New translations entity_cover.md (Polish)

* New translations entity_index.md (Polish)

* New translations dev_101_states.md (Polish)

* New translations entity_weather.md (Polish)

* New translations app_integration_index.md (Dutch)

* New translations frontend_add_card.md (Polish)

* New translations external_api_websocket.md (Polish)

* New translations external_api_server_sent_events.md (Polish)

* New translations external_api_rest_python.md (Polish)

* New translations external_api_rest.md (Polish)

* New translations entity_water_heater.md (Polish)

* New translations entity_light.md (Polish)

* New translations entity_vacuum.md (Polish)

* New translations entity_switch.md (Polish)

* New translations entity_sensor.md (Polish)

* New translations entity_remote.md (Polish)

* New translations entity_registry_index.md (Polish)

* New translations entity_media_player.md (Polish)

* New translations entity_lock.md (Polish)

* New translations development_catching_up.md (Polish)

* New translations dev_101_services.md (Polish)

* New translations app_integration_sensors.md (Polish)

* New translations asyncio_categorizing_functions.md (Polish)

* New translations auth_index.md (Polish)

* New translations auth_auth_provider.md (Polish)

* New translations auth_auth_module.md (Polish)

* New translations auth_api.md (Polish)

* New translations asyncio_working_with_async.md (Polish)

* New translations asyncio_index.md (Polish)

* New translations asyncio_101.md (Polish)

* New translations config_entries_config_flow_handler.md (Polish)

* New translations area_registry_index.md (Polish)

* New translations architecture_index.md (Polish)

* New translations architecture_hassio.md (Polish)

* New translations architecture_entities.md (Polish)

* New translations architecture_components.md (Polish)

* New translations app_integration_webview.md (Polish)

* New translations app_integration_setup.md (Polish)

* New translations auth_permissions.md (Polish)

* New translations config_entries_index.md (Polish)

* New translations dev_101_index.md (Polish)

* New translations creating_platform_example_light.md (Polish)

* New translations dev_101_hass.md (Polish)

* New translations dev_101_events.md (Polish)

* New translations dev_101_config.md (Polish)

* New translations data_entry_flow_index.md (Polish)

* New translations creating_platform_index.md (Polish)

* New translations creating_platform_example_sensor.md (Polish)

* New translations creating_platform_code_review.md (Polish)

* New translations config_entries_options_flow_handler.md (Polish)

* New translations creating_integration_manifest.md (Polish)

* New translations creating_integration_file_structure.md (Polish)

* New translations creating_component_index.md (Polish)

* New translations creating_component_generic_discovery.md (Polish)

* New translations creating_component_deps_and_reqs.md (Polish)

* New translations creating_component_code_review.md (Polish)

* New translations configuration_yaml_index.md (Polish)

* New translations dev_101_states.md (Norwegian)

* New translations development_environment.md (Polish)

* New translations dev_101_index.md (Norwegian)

* New translations development_testing.md (Dutch)

* New translations documentation_standards.md (Dutch)

* New translations documentation_index.md (Dutch)

* New translations documentation_create_page.md (Dutch)

* New translations device_registry_index.md (Dutch)

* New translations development_validation.md (Dutch)

* New translations development_typing.md (Dutch)

* New translations development_submitting.md (Dutch)

* New translations entity_alarm_control_panel.md (Dutch)

* New translations development_index.md (Dutch)

* New translations development_guidelines.md (Dutch)

* New translations development_environment.md (Dutch)

* New translations development_checklist.md (Dutch)

* New translations development_catching_up.md (Dutch)

* New translations dev_101_states.md (Dutch)

* New translations dev_101_services.md (Dutch)

* New translations entity_air_quality.md (Dutch)

* New translations entity_binary_sensor.md (Dutch)

* New translations dev_101_hass.md (Dutch)

* New translations entity_sensor.md (Dutch)

* New translations external_api_rest_python.md (Dutch)

* New translations external_api_rest.md (Dutch)

* New translations entity_weather.md (Dutch)

* New translations entity_water_heater.md (Dutch)

* New translations entity_vacuum.md (Dutch)

* New translations entity_switch.md (Dutch)

* New translations entity_remote.md (Dutch)

* New translations entity_climate.md (Dutch)

* New translations entity_registry_index.md (Dutch)

* New translations entity_media_player.md (Dutch)

* New translations entity_lock.md (Dutch)

* New translations entity_light.md (Dutch)

* New translations entity_index.md (Dutch)

* New translations entity_fan.md (Dutch)

* New translations entity_cover.md (Dutch)

* New translations dev_101_index.md (Dutch)

* New translations dev_101_events.md (Dutch)

* New translations external_api_websocket.md (Dutch)

* New translations architecture_hassio.md (Dutch)

* New translations asyncio_working_with_async.md (Dutch)

* New translations asyncio_index.md (Dutch)

* New translations asyncio_categorizing_functions.md (Dutch)

* New translations asyncio_101.md (Dutch)

* New translations area_registry_index.md (Dutch)

* New translations architecture_index.md (Dutch)

* New translations architecture_entities.md (Dutch)

* New translations auth_auth_module.md (Dutch)

* New translations architecture_components.md (Dutch)

* New translations app_integration_webview.md (Dutch)

* New translations app_integration_setup.md (Dutch)

* New translations app_integration_sensors.md (Dutch)

* New translations app_integration_sending_data.md (Dutch)

* New translations app_integration_notifications.md (Dutch)

* New translations dev_101_hass.md (Norwegian)

* New translations auth_api.md (Dutch)

* New translations auth_auth_provider.md (Dutch)

* New translations dev_101_config.md (Dutch)

* New translations creating_integration_file_structure.md (Dutch)

* New translations data_entry_flow_index.md (Dutch)

* New translations creating_platform_index.md (Dutch)

* New translations creating_platform_example_sensor.md (Dutch)

* New translations creating_platform_example_light.md (Dutch)

* New translations creating_platform_code_review.md (Dutch)

* New translations creating_integration_manifest.md (Dutch)

* New translations creating_component_index.md (Dutch)

* New translations auth_permissions.md (Dutch)

* New translations creating_component_generic_discovery.md (Dutch)

* New translations creating_component_deps_and_reqs.md (Dutch)

* New translations creating_component_code_review.md (Dutch)

* New translations configuration_yaml_index.md (Dutch)

* New translations config_entries_options_flow_handler.md (Dutch)

* New translations config_entries_index.md (Dutch)

* New translations config_entries_config_flow_handler.md (Dutch)

* New translations external_api_server_sent_events.md (Dutch)

* New translations auth_index.md (Dutch)

* New translations frontend_add_card.md (Dutch)

* New translations asyncio_101.md (Norwegian)

* New translations auth_auth_provider.md (Norwegian)

* New translations auth_auth_module.md (Norwegian)

* New translations auth_api.md (Norwegian)

* New translations asyncio_working_with_async.md (Norwegian)

* New translations asyncio_index.md (Norwegian)

* New translations asyncio_categorizing_functions.md (Norwegian)

* New translations area_registry_index.md (Norwegian)

* New translations auth_permissions.md (Norwegian)

* New translations architecture_index.md (Norwegian)

* New translations architecture_hassio.md (Norwegian)

* New translations architecture_entities.md (Norwegian)

* New translations architecture_components.md (Norwegian)

* New translations app_integration_webview.md (Norwegian)

* New translations app_integration_setup.md (Norwegian)

* New translations app_integration_sensors.md (Norwegian)

* New translations auth_index.md (Norwegian)

* New translations config_entries_config_flow_handler.md (Norwegian)

* New translations app_integration_notifications.md (Norwegian)

* New translations creating_platform_example_light.md (Norwegian)

* New translations dev_101_events.md (Norwegian)

* New translations dev_101_config.md (Norwegian)

* New translations frontend_add_more_info.md (Dutch)

* New translations data_entry_flow_index.md (Norwegian)

* New translations creating_platform_index.md (Norwegian)

* New translations creating_platform_example_sensor.md (Norwegian)

* New translations creating_platform_code_review.md (Norwegian)

* New translations config_entries_index.md (Norwegian)

* New translations creating_integration_manifest.md (Norwegian)

* New translations creating_integration_file_structure.md (Norwegian)

* New translations creating_component_index.md (Norwegian)
This commit is contained in:
Home Assistant Bot 2019-05-16 23:36:57 -07:00 committed by Robbie Trencheny
parent ba9006c3b9
commit 0ffe2b4edf
301 changed files with 24952 additions and 0 deletions

1529
website/i18n/no-NO.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,212 @@
---
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,15 @@
---
title: Adding more info dialogs
id: version-0.78.0-frontend_add_more_info
original_id: frontend_add_more_info
---
Whenever the user taps or clicks on one of the cards, a more info dialog will show. The header of this dialog will be the state card, followed by the history of this entity for the last 24 hours. Below this the more info component is rendered for that entity. The more info component can show more information or allow more ways of control.
![The more info dialog for a light allows the user to control the color and the brightness.](/img/en/frontend/frontend-more-info-light.png)
The instructions to add a more info dialog are very similar to adding a new card type. This example will add a new more info component for the domain `camera`:
1. Add `'camera'` to the array `DOMAINS_WITH_MORE_INFO` in the file [/common/const.js](https://github.com/home-assistant/home-assistant-polymer/blob/master/src/common/const.js).
2. Create the files `more-info-camera.js` in the folder [/dialogs/more-info/controls](https://github.com/home-assistant/home-assistant-polymer/tree/master/src/dialogs/more-info/controls).
3. Add `import './more-info-camera.js';` to [/dialogs/more-info/controls/more-info-content.js](https://github.com/home-assistant/home-assistant-polymer/blob/master/src/dialogs/more-info/controls/more-info-content.js)

View File

@ -0,0 +1,68 @@
---
title: External Authentication
id: version-0.78.0-frontend_external_auth
original_id: frontend_external_auth
---
By default, the frontend will take care of its own authentication tokens. If none found, it will redirect the user to the login page and it will take care that the token is up to date.
If you want to embed the Home Assistant frontend in an external app, you will want to store the authentication inside the app but make it available to the frontend. To support this, Home Assistant exposes an external authentication API.
To activate this API, load the frontend with `?external_auth=1` appended to the URL. If this is passed in, Home Assistant will expect either `window.externalApp` (for Android) or `window.webkit.messageHandlers` (for iOS) to be defined containing the methods described below.
## Get Access Token
*This API has been introduced in Home Assistant 0.78.*
When the frontend loads, it will request an access token from the external authentication. It does so by calling one of the following methods with an options object. The options object defines the callback method to be called with the response.
```js
window.externalApp.getExternalAuth({
callback: 'externalAuthSetToken'
});
// or
window.webkit.messageHandlers.getExternalAuth.postMessage({
callback: 'externalAuthSetToken'
});
```
The response should contain a boolean if it was successful and an object containing an access token and the number of seconds that it will remain valid. Pass the response to the function defined in the options object.
```js
// To be called by external app
window.externalAuthSetToken(true, {
"access_token": "qwere",
"expires_in": 1800
});
// If unable to get new access token
window.externalAuthSetToken(false);
```
The frontend will call this method when the page first loads and whenever it needs a valid token but the previous received token has expired.
## Revoke Token
*This API has been introduced in Home Assistant 0.78.*
When the user presses the logout button on the profile page, the external app will have to [revoke the refresh token](auth_api.md#revoking-a-refresh-token), and log the user out.
```js
window.externalApp.revokeExternalAuth({
callback: 'externalAuthSetToken'
});
// or
window.webkit.messageHandlers.revokeExternalAuth.postMessage({
callback: 'externalAuthSetToken'
});
```
When done, the external app has to call the function defined in the options object.
```js
// To be called by external app
window.externalAuthRevokeToken(true);
// If unable to logout
window.externalAuthRevokeToken(false);
```

View File

@ -0,0 +1,37 @@
---
title: Add-On Communication
id: version-0.78.0-hassio_addon_communication
original_id: hassio_addon_communication
---
There are different ways for communication between add-ons inside Hass.io.
## Network
We use an internal network that allows to communicate with every add-on, even to/from Home Assistant, by using its name or alias. Only the add-ons which run on the host network are a bit limited. These can talk with all internal add-ons by their name but all other add-on can't address these add-on by name - using an alias works for both!
Name/alias are used for communication inside Hass.io. The name is generated using the following format: `{REPO}_{SLUG}`, e.g., `local_xy` or `3283fh_myaddon`. In this example, `{SLUG}` is defined in an add-ons `config.json`. You can use this name also as DNS name but you need replace the `_` with `-` to have a valid hostname. If an add-on is installed locally, `{REPO}` will be `local`. If the add-on is installed from a Github repository, `{REPO}` is a hashed identifier generated from the GitHub repository's URL (ex: https://github.com/xy/my_hassio_addons). See [here](https://github.com/home-assistant/hassio/blob/587047f9d648b8491dc8eef17dc6777f81938bfd/hassio/addons/utils.py#L17) to understand how this identifier is generated. Note that this identifier is required in certain service calls that use the [Hass.io add-on API](https://github.com/home-assistant/hassio/blob/dev/API.md#restful-for-api-addons). You can view the repository identifiers for all currently installed add-ons via a GET request to the hassio API `addons` endpoint.
Use `hassio` for communication with the internal API.
## Home Assistant
An add-on can talk to the [Home Assistant API](https://www.home-assistant.io/developers/rest_api/) using the internal proxy. That makes it very easy to communicate with the API without knowing the password, port or any other information of the Home Assistant instance. Use this URL: `http://hassio/homeassistant/api` and internal communication is redirected to the right place. The next stept is to add `homeassistant_api: true` to `config.json` and read the environment variable `HASSIO_TOKEN` and use this as Home-Assistant password.
There is also a proxy for the [Home Assistant Websocket API](https://www.home-assistant.io/developers/websocket_api/). It works like the API proxy above and requires `HASSIO_TOKEN` as password. Use this URL: `http://hassio/homeassistant/websocket`.
It is also possible to talk direct to the Home Assistant instance which is named `homeassistant` over the internal network. But you need to know the configuration that is used by the running instance.
We have severals services for Hass.io inside Home Assistant to run tasks. To send data over STDIN to an add-on use the `hassio.addon_stdin` service.
## Hass.io API
To enables calls to the [Hass.io API](https://github.com/home-assistant/hassio/blob/master/API.md), add `hassio_api: true` to `config.json` and read the environment variable `HASSIO_TOKEN`. Now you can use the API over the URL: `http://hassio/`. Use the `HASSIO_TOKEN` with header `X-HASSIO-KEY`. It could be that you need also change the Hass.io API role like `hassio_role: default`.
Add-ons can call some API commands without need set `hassio_api: true`:
- `/homeassistant/info`
- `/supervisor/info`
- `/addons`
- `/addons/self/...`
- `/services*`

View File

@ -0,0 +1,207 @@
---
title: Add-On Configuration
id: version-0.78.0-hassio_addon_config
original_id: hassio_addon_config
---
Each add-on is stored in a folder. The file structure looks like this:
```text
addon_name/
build.json
CHANGELOG.md
config.json
Dockerfile
icon.png
logo.png
README.md
run.sh
```
## Add-on script
As with every Docker container, you will need a script to run when the container is started. A user might run many add-ons, so it is encouraged to try to stick to Bash scripts if you're doing simple things.
When developing your script:
- `/data` is a volume for persistent storage.
- `/data/options.json` contains the user configuration. You can use `jq` inside your shell script to parse this data. However, you might have to install `jq` as a separate package in your container (see `Dockerfile` below).
```bash
CONFIG_PATH=/data/options.json
TARGET="$(jq --raw-output '.target' $CONFIG_PATH)"
```
So if your `options` contain
```json
{ "target": "beer" }
```
then there will be a variable `TARGET` containing `beer` in the environment of your bash file afterwards.
## Add-on Docker file
All add-ons are based on Alpine Linux 3.6. Hass.io will automatically substitute the right base image based on the machine architecture. Add `tzdata` if you need run in a different timezone. `tzdata` Is is already added to our base images.
ARG BUILD_FROM
FROM $BUILD_FROM
ENV LANG C.UTF-8
# Install requirements for add-on
RUN apk add --no-cache jq
# Copy data for add-on
COPY run.sh /
RUN chmod a+x /run.sh
CMD [ "/run.sh" ]
If you don't use local build on device or our build script, make sure that the Dockerfile have also a set of labels include:
LABEL io.hass.version="VERSION" io.hass.type="addon" io.hass.arch="armhf|aarch64|i386|amd64"
It is possible to use own base image with `build.json` or if you do not need support for automatic multi-arch building you can also use a simple docker `FROM`.
### Build Args
We support the following build arguments by default:
| ARG | 설명 |
| ------------- | ------------------------------------------------------------ |
| BUILD_FROM | Hold image for dynamic builds or buildings over our systems. |
| BUILD_VERSION | Add-on version (read from `config.json`). |
| BUILD_ARCH | Hold current build arch inside. |
## Add-on config
The config for an add-on is stored in `config.json`.
```json
{
"name": "xy",
"version": "1.2",
"slug": "folder",
"description": "long description",
"arch": ["amd64"],
"url": "website with more information about add-on (ie a forum thread for support)",
"startup": "application",
"boot": "auto",
"ports": {
"123/tcp": 123
},
"map": ["config:rw", "ssl"],
"options": {},
"schema": {},
"image": "repo/{arch}-my-custom-addon"
}
```
| 키 | 구분 | Required | 설명 |
| ----------------- | ----------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | string | yes | Name of the add-on |
| version | string | yes | Version of the add-on |
| slug | string | yes | Slug of the add-on |
| description | string | yes | Description of the add-on |
| arch | list | no | List of supported arch: `armhf`, `aarch64`, `amd64`, `i386`. Default all. |
| url | url | no | Homepage of the addon. Here you can explain the add-ons and options. |
| startup | bool | yes | `initialize` will start addon on setup of Hass.io. `system` is for things like databases and not dependent on other things. `services` will start before Home Assistant, while `application` is started afterwards. Finally `once` is for applications that don't run as a daemon. |
| webui | string | no | A URL for web interface of this add-on. Like `http://[HOST]:[PORT:2839]/dashboard`, the port needs the internal port, which will be replaced with the effective port. It is also possible to bind the proto part to a config options with: `[PROTO:option_name]://[HOST]:[PORT:2839]/dashboard` and he lookup if they is True and going to `https`. |
| boot | string | yes | `auto` by system and manual or only `manual` |
| ports | dict | no | Network ports to expose from the container. Format is `"container-port/type": host-port`. |
| host_network | bool | no | If that is True, the add-on run on host network. |
| host_ipc | bool | no | Default False. Allow to share the IPC namespace with others. |
| host_dbus | bool | no | Default False. Map Host dbus service into add-on. |
| host_pid | bool | no | Default False. Allow to run container on host PID namespace. Work only for not protected add-ons. |
| devices | list | no | Device list to map into the add-on. Format is: `<path_on_host>:<path_in_container>:<cgroup_permissions>`. i.e. `/dev/ttyAMA0:/dev/ttyAMA0:rwm` |
| auto_uart | bool | no | Default False. Auto mapping all UART/Serial device from host into add-on. |
| hassio_role | str | no | Default `default`. Role based access to Hass.io API. Available: `default`, `homeassistant`, `manager`, `admin`. |
| hassio_api | bool | no | This add-on can access to Hass.io REST API. It set the host alias `hassio`. |
| homeassistant_api | bool | no | This add-on can access to Hass.io Home-Assistant REST API proxy. Use `http://hassio/homeassistant/api`. |
| docker_api | bool | no | Allow read-oly access to docker API for add-on. Work only for not protected add-ons. |
| privileged | list | no | Privilege for access to hardware/system. Available access: `NET_ADMIN`, `SYS_ADMIN`, `SYS_RAWIO`, `SYS_TIME`, `SYS_NICE`, `SYS_RESOURCE`, `SYS_PTRACE`. |
| full_access | bool | no | Give full access to hardware like the privileged mode in docker. Work only for not protected add-ons. |
| apparmor | bool/string | no | Enable or disable AppArmor support. If it is enable, you can also use custom profiles with the name of the profile. |
| map | list | no | List of maps for additional Hass.io folders. Possible values: `config`, `ssl`, `addons`, `backup`, `share`. Defaults to `ro`, which you can change by adding `:rw` to the end of the name. |
| environment | dict | no | A dict of environment variable to run add-on. |
| audio | bool | no | Boolean. Mark this add-on to use internal an audio system. The ALSA configuration for this add-on will be mount automatic. |
| gpio | bool | no | Boolean. If this is set to True, `/sys/class/gpio` will map into add-on for access to GPIO interface from kernel. Some library need also `/dev/mem` and `SYS_RAWIO` for read/write access to this device. On system with AppArmor enabled, you need disable AppArmor or better for security, provide you own profile for the add-on. |
| devicetree | bool | no | Boolean. If this is set to True, `/device-tree` will map into add-on. |
| stdin | bool | no | Boolean. If that is enable, you can use the STDIN with Hass.io API. |
| legacy | bool | no | Boolean. If the docker image have no hass.io labels, you can enable the legacy mode to use the config data. |
| options | dict | yes | Default options value of the add-on |
| schema | dict | yes | Schema for options value of the add-on. It can be `False` to disable schema validation and use custom options. |
| image | string | no | For use with Docker Hub and other container registries. |
| timeout | integer | no | Default 10 (second). The timeout to wait until the docker is done or will be killed. |
| tmpfs | string | no | Mount a tmpfs file system in `/tmpfs`. Valide format for this option is : `size=XXXu,uid=N,rw`. Size is mandatory, valid units (`u`) are `k`, `m` and `g` and `XXX` has to be replaced by a number. `uid=N` (with `N` the uid number) and `rw` are optional. |
### Options / Schema
The `options` dictionary contains all available options and their default value. Set the default value to `null` if the value is required to be given by the user before the add-on can start, and it show it inside default values. Only nested arrays and dictionaries are supported with a deep of two size. If you want make an option optional, put `?` to the end of data type, otherwise it will be a required value.
```json
{
"message": "custom things",
"logins": [
{ "username": "beer", "password": "123456" },
{ "username": "cheep", "password": "654321" }
],
"random": ["haha", "hihi", "huhu", "hghg"],
"link": "http://example.com/",
"size": 15,
"count": 1.2
}
```
The `schema` looks like `options` but describes how we should validate the user input. For example:
```json
{
"message": "str",
"logins": [
{ "username": "str", "password": "str" }
],
"random": ["match(^\w*$)"],
"link": "url",
"size": "int(5,20)",
"count": "float",
"not_need": "str?"
}
```
We support:
- str
- bool
- int / int(min,) / int(,max) / int(min,max)
- float / float(min,) / float(,max) / float(min,max)
- email
- url
- port
- match(REGEX)
## Add-on extended build
Additional build options for an add-on is stored in `build.json`. This file will be read from our build systems. You need this only, if you not use the default images or need additionals things.
```json
{
"build_from": {
"armhf": "mycustom/base-image:latest"
},
"squash": false,
"args": {
"my_build_arg": "xy"
}
}
```
| 키 | Required | 설명 |
| ---------- | -------- | ------------------------------------------------------------------------------------------------------ |
| build_from | no | A dictionary with the hardware architecture as the key and the base Docker image as value. |
| squash | no | Default `False`. Be carfully with this option, you can not use the image for caching stuff after that! |
| args | no | Allow to set additional Docker build arguments as a dictionary. |

View File

@ -0,0 +1,33 @@
---
title: Add-on security
id: version-0.78.0-hassio_addon_security
original_id: hassio_addon_security
---
Hass.io rates every add-on based on the wanted rights. An add-on with a rating of 6 is very secure. If an add-on has a rating of 1, you shouldn't run this add-on unless you are 100% sure that you can trust the source.
## API Role
For access to Hass.io API you need define a role or you run in default mode. This is only required for Hass.io API not Home Assistant proxy. Any of the role have also the default API calls inheret for that are no settings are required.
### Available Roles
| Role | 설명 |
| ------------- | ------------------------------------------------------------------------------------------------------ |
| default | Have access to all `info` calls |
| homeassistant | Can access to all Home Assistant API endpoints |
| manager | Is for Add-ons they run CLIs and need extended rights |
| admin | Have access to every API call. That is the only one they can disable/enable the Add-on protection mode |
## Protection
Default, all add-ons run in protection enabled mode. This mode prevents the add-on from getting any rights on the system. If an add-on requires more rights, you can disable this protection via the API add-on options for that add-on. But be carful, an add-on with disabled protection can destroy your system!
## Making a secure add-on
As a developer, follow the following best practices to make your add-on secure:
- Don't run on host network
- Create an AppArmor profile
- Map folders read only if you don't need write access
- If you need any API access, make sure you that you not grant to highest permission if you don't need it

View File

@ -0,0 +1,49 @@
---
title: Checklist for creating a component
id: version-0.79.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. 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()
```

View File

@ -0,0 +1,82 @@
---
title: Checklist for creating a platform
id: version-0.79.0-creating_platform_code_review
original_id: creating_platform_code_review
---
A checklist of things to do when you're adding a new platform.
> 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 platform level
- Use `CONF_MONITORED_CONDITIONS` instead of `CONF_MONITORED_VARIABLES`
### 1. Requirements
1. Requirement version should be 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. This is necessary because requirements are installed on the fly.
### 2. Dependencies
1. If you depend on a component for the connection, add it to your dependencies: `DEPENDENCIES = ['nest']`
### 3. Configuration
1. Voluptuous schema present for [configuration validation](development_validation.md)
2. Voluptuous schema extends schema from component
(e.g., `light.hue.PLATFORM_SCHEMA` extends `light.PLATFORM_SCHEMA`)
3. Default parameters specified in voluptuous schema, not in `setup_platform(...)`
4. Your `PLATFORM_SCHEMA` should use as many generic config keys as possible from `homeassistant.const`
```python
import voluptuous as vol
from homeassistant.const import CONF_FILENAME, CONF_HOST
from homeassistant.components.light import PLATFORM_SCHEMA
import homeassistant.helpers.config_validation as cv
CONF_ALLOW_UNREACHABLE = 'allow_unreachable'
DEFAULT_UNREACHABLE = False
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_ALLOW_UNREACHABLE,
default=DEFAULT_UNREACHABLE): cv.boolean,
vol.Optional(CONF_FILENAME): cv.string,
})
```
5. Never depend on users adding things to `customize` to configure behavior inside your platform.
### 4. Setup Platform
1. Test if passed in info (user/pass/host etc.) works.
2. Group your calls to `add_devices` if possible.
3. If platform adds extra services, format should be `<component>.<platform>_<service name>`.
### 5. Entity
1. Extend entity from component, e.g., `class HueLight(Light)`.
2. Avoid passing in `hass` as a parameter to the entity. When the entity has been added to Home Assistant, `hass` will be set on the entity by the helper in entity_platform.py. This means you can access `hass` as `self.hass` inside the entity.
3. Do not call `update()` in constructor, use `add_entities(devices, True)` instead.
4. Do not do any I/O inside properties. Cache values inside `update()` instead.
5. The state and/or attributes should not contain relative time since something happened. Instead it should store UTC timestamps.
### 6. 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()
```

View File

@ -0,0 +1,113 @@
---
title: Set up Development Environment
id: version-0.79.0-development_environment
original_id: development_environment
---
You'll need to set up a development environment if you want to develop a new feature or component for Home Assistant. Read on to learn how to set up.
## Preparing your environment
### Developing on Linux
Install the core dependencies.
```bash
$ sudo apt-get install python3-pip python3-dev python3-venv
```
In order to run `script/setup` below you will need some more dependencies.
```bash
$ sudo apt-get install autoconf libssl-dev libxml2-dev libxslt1-dev libjpeg-dev libffi-dev libudev-dev zlib1g-dev
```
> Different distributions have different package installation mechanisms and sometimes packages names as well. For example Centos would use: `sudo yum install epel-release && sudo yum install python36 python36-devel mysql-devel gcc`
Additional dependencies exist if you plan to perform Frontend Development, please read the [Frontend](frontend_index.md) section to learn more.
### Developing on Windows
If you are using Windows as a development platform, make sure that you have the correct Microsoft [Visual C++ build tools](http://landinghub.visualstudio.com/visual-cpp-build-tools) installed. The installation of the most requirements and validation using `tox` will fail if this is not done correctly. Check the [Windows Compilers](https://wiki.python.org/moin/WindowsCompilers) section on the [Python website](https://www.python.org/) for details.
Due to Home Assistant is mainly designed and developed on Linux distributions it is not recommended to develop on Windows machines. However on Windows 10 machines you should decide to set up a [Linux subsystem](https://docs.microsoft.com/de-de/windows/wsl/install-win10).
Setup Linux subsystem.
```bash
$ sudo apt-get update
$ sudo apt-get upgrade
$ echo 'export DISPLAY=:0' >> ~/.bashrc && . ~/.bashrc
$ sudo apt-get install xubuntu-desktop -y
```
It is recommended using [PyCharm](https://www.jetbrains.com/pycharm/download/) as debugger. Download and start PyCharm.
```bash
$ wget https://download.jetbrains.com/python/pycharm-community-20XX.X.tar.gz
$ tar -xzf pycharm-community-20XX.X
$ ./pycharm.sh
```
In order to display the PyCharm GUI on Windows you need to run a X-Server like [VcXserv](https://sourceforge.net/projects/vcxsrv/).
Also, make sure to install or upgrade the `setuptools` Python package. It contains compatibility improvements and adds automatic use of compilers:
```bash
$ pip install --upgrade setuptools
```
### Developing on OS X
Install [Homebrew](https://brew.sh/), then use that to install Python 3:
```bash
$ brew install python3
```
## Setup Local Repository
Visit the [Home Assistant repository](https://github.com/home-assistant/home-assistant) and click **Fork**. Once forked, setup your local copy of the source using the commands:
```bash
$ git clone https://github.com/YOUR_GIT_USERNAME/home-assistant.git
$ cd home-assistant
$ git remote add upstream https://github.com/home-assistant/home-assistant.git
```
## Setting up virtual environment
To isolate your environment from the rest of the system, set up a [`venv`](https://docs.python.org/3/library/venv.html). Within the `home-assistant` directory, create and activate your virtual environment.
```bash
$ python3 -m venv .
$ source bin/activate
```
Install the requirements with a provided script named `setup`.
```bash
$ script/setup
```
Invoke your installation.
```bash
$ hass
```
## Logging
By default logging in home-assistant is tuned for operating in production (set to INFO by default, with some modules set to even less verbose logging levels).
You can use the [logger](https://www.home-assistant.io/components/logger/) component to adjust logging to DEBUG to see even more details about what is going on:
```yaml
logger:
default: info
logs:
homeassistant.core: debug
nest.nest: debug
asyncio: debug
homeassistant.components.cloud.iot: debug
```

View File

@ -0,0 +1,134 @@
---
title: Create a new page
id: version-0.79.0-documentation_create_page
original_id: documentation_create_page
---
For a platform or component page, the fastest way is to make a copy of an existing page and edit it. The [Component overview](https://www.home-assistant.io/components/) and the [Examples section](https://www.home-assistant.io/cookbook/) are generated automatically, so there is no need to add a link to those pages.
Please honor the [Standards](documentation_standards.md) we have for the documentation.
If you start from scratch with a page, you need to add a header. Different sections of the documentation may need different headers.
```text
---
layout: page
title: "Awesome Sensor"
description: "home-assistant.io web presence"
date: 2015-06-17 08:00
sidebar: true
comments: false
sharing: true
footer: true
ha_release: "0.38"
ha_category: Sensor
ha_iot_class: "Local Polling"
ha_qa_scale: silver
---
Content...Written in markdown.
### {% linkable_title Linkable Header %}
...
```
Please keep in mind that if the `date:` entry is in the future then the page will not show up.
Additional keys for the file header:
- `logo`: Please check the separate section below.
- `ha_release`: The release when the intregration was included, e.g., "0.38". If the current release is 0.37, make `ha_release` 0.38. If it's 0.30 or 0.40 please quote it with `" "`.
- `ha_category`: This entry is used to group the integration on the [Components overview](https://www.home-assistant.io/components/).
- `ha_iot_class`: [IoT class(/blog/2016/02/12/classifying-the-internet-of-things) is the classifier for the device's behavior.
- `ha_qa_scale`: [Quality scale](https://www.home-assistant.io/docs/quality_scale/) is the representation of the integration's quality.
There are [pre-definied variables](https://jekyllrb.com/docs/variables/) available but usually, it's not necessary to use them when writing documentation.
A couple of points to remember:
- Document the needed steps to retrieve API keys or access token for the third party service or device if needed.
- Add screenshot to support the user where it make sense.
- Add the type of the device(s) (incl. firmware) you have tested when you know that there are multiple out there.
### Configuration
Every platform page should contain a configuration sample. This sample must contain only the **required** variables to make it easy to copy and paste it for users into their `configuration.yaml` file.
The **Configuration Variables** section must use the `{% configuration %} ... {% endconfiguration %}` tag.
```text
{% configuration %}
api_key:
description: The API key to access the service.
required: true
type: string
name:
description: Name to use in the frontend.
required: false
default: The default name to use in the frontend.
type: string
monitored_conditions:
description: Conditions to display in the frontend.
required: true
type: map
keys:
weather:
description: A human-readable text summary.
temperature:
description: The current temperature.
{% endconfiguration %}
```
Available keys:
- **`description:`**: That the variable is about.
- **`required:`**: If the variable is required.
```text
required: true #=> Required
required: false #=> Optional
required: inclusive #=> Inclusive
required: exclusive #=> Exclusive
required: any string here #=> Any string here
```
- **`type:`**: The type of the variable. Allowed entries: `string`, `int`, `time`, `template` or `map` (for a list of entries). For multiple possibilities use `[string, int]`. If you use `map` then you need to define `keys:` (see the [`template` sensor](/components/sensor.template/) for an example).
- **`default:`**: The default value for the variable.
### Embedding Code
You can use the [default markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code) to generate syntax highlighted code. For inline code wrap your code in back-ticks.
When you're writing code that is to be executed on the terminal, prefix it with `$`.
### Templates
For the [configuration templating](https://www.home-assistant.io/docs/configuration/templating/) is [Jinja](http://jinja.pocoo.org/) used. Check the [Documentation Standards](documentation_standards.md) for further details.
If you are don't escape templates then they will be rendered and appear blank on the website.
### HTML
The direct usage of HTML is supported but not recommended. The note boxes are an exception.
```html
<p class='note warning'>
You need to enable telnet on your router.
</p>
```
### Images, icons and logos
The images which are displayed on the pages are stored in various directories according to their purpose. If you want to use a logo and placed `logo:` in the file header then this image should be stored in `source/images/supported_brands`. The background must be transparent.
| 구분 | Location |
|:----------- |:------------------------------ |
| logos | source/images/supported_brands |
| blog | source/images/blog |
| screenshots | source/images/components |
Not everything (product, component, etc.) should have a logo. To show something for internal parts of Home Assistant we are using the [Material Design Icons](https://materialdesignicons.com/).
### Linking From The Sidebar
If you are adding a new page that requires linking from the sidebar you need to edit the `docs_navigation.html` file in `home-assistant.github.io/source/_includes/asides/docs_navigation.html`.

View File

@ -0,0 +1,37 @@
---
title: Documentation
id: version-0.79.0-documentation_index
original_id: documentation_index
---
The user documentation is located at <https://www.home-assistant.io>. This section here is the place where we provide documentation and additional details about creating or modifying content.
The [home-assistant.io](https://home-assistant.io) website is built using [Jekyll](http://github.com/mojombo/jekyll) and [these dependencies](https://pages.github.com/versions/). The pages are written in [Markdown](http://daringfireball.net/projects/markdown/). To add a page, you don't need to know about HTML.
You can use the "**Edit this page on GitHub**" link to edit pages without creating a fork. Keep in mind that you can't upload images while working this way.
For larger changes, we suggest that you clone the website repository. This way, you can review your changes locally. The process for working on the website is no different from working on Home Assistant itself. You work on your change and propose it via a Pull Request (PR).
To test your changes locally, you need to install **Ruby** and its dependencies (gems):
- [Install Ruby](https://www.ruby-lang.org/en/documentation/installation/) if you don't have it already. Ruby version 2.3.0 or higher is required.
- Install `bundler`, a dependency manager for Ruby: `$ gem install bundler`
- In your home-assistant.io root directory, run `$ bundle` to install the gems you need.
Shortcut for Fedora: `$ sudo dnf -y install gcc-c++ ruby ruby-devel rubygem-bundler rubygem-json && bundle`
Then you can work on the documentation:
- Fork home-assistant.io [git repository](https://github.com/home-assistant/home-assistant.io).
- Create/edit/update a page in the directory `source/_components/` for your platform/component. The Home Assistant documention itself is located in the directory `source/_docs/`.
- Test your changes to home-assistant.io locally: run `rake preview` and navigate to <http://127.0.0.1:4000>
- Create a Pull Request (PR) against the **next** branch of home-assistant.io if your documentation is a new feature, platform, or component.
- Create a Pull Request (PR) against the **current** branch of home-assistant.io if you fix stuff, create Cookbook entries, or expand existing documentation.
It could be necessary that you run `rake generate` prior to `rake preview` for the very first preview.
Site generated by `rake` is only available locally. If you are developing on a headless machine use port forwarding:
```bash
$ ssh -L 4000:localhost:4000 user_on_headless_machine@ip_of_headless_machine
```

View File

@ -0,0 +1,37 @@
---
title: Add-On Communication
id: version-0.79.0-hassio_addon_communication
original_id: hassio_addon_communication
---
There are different ways for communication between add-ons inside Hass.io.
## Network
We use an internal network that allows to communicate with every add-on, even to/from Home Assistant, by using its name or alias. Only the add-ons which run on the host network are a bit limited. These can talk with all internal add-ons by their name but all other add-on can't address these add-on by name - using an alias works for both!
Name/alias are used for communication inside Hass.io. The name is generated using the following format: `{REPO}_{SLUG}`, e.g., `local_xy` or `3283fh_myaddon`. In this example, `{SLUG}` is defined in an add-ons `config.json`. You can use this name also as DNS name but you need replace the `_` with `-` to have a valid hostname. If an add-on is installed locally, `{REPO}` will be `local`. If the add-on is installed from a Github repository, `{REPO}` is a hashed identifier generated from the GitHub repository's URL (ex: https://github.com/xy/my_hassio_addons). See [here](https://github.com/home-assistant/hassio/blob/587047f9d648b8491dc8eef17dc6777f81938bfd/hassio/addons/utils.py#L17) to understand how this identifier is generated. Note that this identifier is required in certain service calls that use the [Hass.io add-on API](https://github.com/home-assistant/hassio/blob/dev/API.md#restful-for-api-addons). You can view the repository identifiers for all currently installed add-ons via a GET request to the hassio API `addons` endpoint.
Use `hassio` for communication with the internal API.
## Home Assistant
An add-on can talk to the [Home Assistant API](https://www.home-assistant.io/developers/rest_api/) using the internal proxy. That makes it very easy to communicate with the API without knowing the password, port or any other information of the Home Assistant instance. Use this URL: `http://hassio/homeassistant/api` and internal communication is redirected to the right place. The next stept is to add `homeassistant_api: true` to `config.json` and read the environment variable `HASSIO_TOKEN` and use this as Home-Assistant password.
There is also a proxy for the [Home Assistant Websocket API](https://www.home-assistant.io/developers/websocket_api/). It works like the API proxy above and requires `HASSIO_TOKEN` as password. Use this URL: `http://hassio/homeassistant/websocket`.
It is also possible to talk direct to the Home Assistant instance which is named `homeassistant` over the internal network. But you need to know the configuration that is used by the running instance.
We have severals services for Hass.io inside Home Assistant to run tasks. To send data over STDIN to an add-on use the `hassio.addon_stdin` service.
## Hass.io API
To enables calls to the [Hass.io API](https://github.com/home-assistant/hassio/blob/master/API.md), add `hassio_api: true` to `config.json` and read the environment variable `HASSIO_TOKEN`. Now you can use the API over the URL: `http://hassio/`. Use the `HASSIO_TOKEN` with header `X-HASSIO-KEY`. It could be that you need also change the Hass.io API role like `hassio_role: default`.
Add-ons can call some API commands without need set `hassio_api: true`:
- `/homeassistant/api`
- `/homeassistant/websocket`
- `/homeassistant/stream`
- `/addons/self/...`
- `/services*`

View File

@ -0,0 +1,54 @@
---
title: Hass.io <> Home Assistant integration development
sidebar_label: HASS Integration development
id: version-0.79.0-hassio_hass
original_id: hassio_hass
---
These steps will help you connect your local Home Assistant to a remote Hass.io instance. You can then make changes locally to either the Hass.io component or the frontend and test it out against a real instance.
For this guide, we're going to assume that you have an Hass.io instance up and running. If you don't, you can use the generic installation method to install it inside a [virtual machine](https://github.com/home-assistant/hassio-build/tree/master/install#install-hassio).
## API Access
To develop for the frontend, we're going to need API access to the supervisor.
- Add our developer Add-on repository: https://github.com/home-assistant/hassio-addons-development
- Install the Add-on "Remote API proxy"
## Having Home Assistant connect to remote Hass.io
The connection with the supervisor is hidden inside the host and is only accessible from applications running on the host. So to make it accessible for our Home Assistant instance, we will need to route the connection to our computer running Home Assistant. We're going to do this by forwarding the API with "Remote API proxy" Add-on.
First, make sure Home Assistant will load the Hass.io component by adding `hassio:` to your `configuration.yaml` file. Next, we will need to tell Hass.io component how to connect to the remote Hass.io instance, we do this by setting the `HASSIO` and `HASSIO_TOKEN` environment variables when starting Home Assistant. Note that the `HASSIO` value is not the same as the one that we saw above and the `HASSIO_TOKEN` is available inside log output of "Remote API Add-on" (This change every restart of this Add-on!).
```bash
HASSIO=<IP OF HASS.IO>:80 HASSIO_TOKEN=<VALUE OF HASSIO_TOKEN> hass
```
Voila. Your local Home Assistant installation will now connect to a remote Hass.io instance.
## Frontend development
> This requires Home Assistant 0.71 or later.
We need a couple more steps to do frontend development. First, make sure you have a Home Assistant frontend development set up ([instructions](frontend_index.md)).
Update the Hass.io component configuration in your `configuration.yaml` to point at the frontend repository:
```yaml
# configuration.yaml
hassio:
development_repo: /home/paulus/dev/hass/home-assistant-polymer
```
To build a local version of the Hass.io panel, go to the frontend repository and run:
```bash
cd hassio
script/build_hassio
```
Now start Home Assistant as discussed in the previous section and it will now connect to the remote Hass.io but show your local frontend.
We're currently transitioning in how we're building the frontend so we don't have an incremental development mode just yet. For now, after making a local change, run `script/build_hassio` again.

View File

@ -0,0 +1,212 @@
---
title: Add-On Configuration
id: version-0.86.0-hassio_addon_config
original_id: hassio_addon_config
---
Each add-on is stored in a folder. The file structure looks like this:
```text
addon_name/
build.json
CHANGELOG.md
config.json
Dockerfile
icon.png
logo.png
README.md
run.sh
```
## Add-on script
As with every Docker container, you will need a script to run when the container is started. A user might run many add-ons, so it is encouraged to try to stick to Bash scripts if you're doing simple things.
When developing your script:
- `/data` is a volume for persistent storage.
- `/data/options.json` contains the user configuration. You can use `jq` inside your shell script to parse this data. However, you might have to install `jq` as a separate package in your container (see `Dockerfile` below).
```bash
CONFIG_PATH=/data/options.json
TARGET="$(jq --raw-output '.target' $CONFIG_PATH)"
```
So if your `options` contain
```json
{ "target": "beer" }
```
then there will be a variable `TARGET` containing `beer` in the environment of your bash file afterwards.
## Add-on Docker file
All add-ons are based on Alpine Linux 3.6. Hass.io will automatically substitute the right base image based on the machine architecture. Add `tzdata` if you need run in a different timezone. `tzdata` Is is already added to our base images.
ARG BUILD_FROM
FROM $BUILD_FROM
ENV LANG C.UTF-8
# Install requirements for add-on
RUN apk add --no-cache jq
# Copy data for add-on
COPY run.sh /
RUN chmod a+x /run.sh
CMD [ "/run.sh" ]
If you don't use local build on device or our build script, make sure that the Dockerfile have also a set of labels include:
LABEL io.hass.version="VERSION" io.hass.type="addon" io.hass.arch="armhf|aarch64|i386|amd64"
It is possible to use own base image with `build.json` or if you do not need support for automatic multi-arch building you can also use a simple docker `FROM`.
### Build Args
We support the following build arguments by default:
| ARG | 설명 |
| ------------- | ------------------------------------------------------------ |
| BUILD_FROM | Hold image for dynamic builds or buildings over our systems. |
| BUILD_VERSION | Add-on version (read from `config.json`). |
| BUILD_ARCH | Hold current build arch inside. |
## Add-on config
The config for an add-on is stored in `config.json`.
```json
{
"name": "xy",
"version": "1.2",
"slug": "folder",
"description": "long description",
"arch": ["amd64"],
"url": "website with more information about add-on (ie a forum thread for support)",
"startup": "application",
"boot": "auto",
"ports": {
"123/tcp": 123
},
"map": ["config:rw", "ssl"],
"options": {},
"schema": {},
"image": "repo/{arch}-my-custom-addon"
}
```
| 키 | 구분 | Required | 설명 |
| ----------------- | ----------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | string | yes | Name of the add-on |
| version | string | yes | Version of the add-on |
| slug | string | yes | Slug of the add-on |
| description | string | yes | Description of the add-on |
| arch | list | no | List of supported arch: `armhf`, `aarch64`, `amd64`, `i386`. Default all. |
| machine | list | no | Default it support any machine type. You can select that this add-on run only on specific machines. |
| url | url | no | Homepage of the addon. Here you can explain the add-ons and options. |
| startup | bool | yes | `initialize` will start addon on setup of Hass.io. `system` is for things like databases and not dependent on other things. `services` will start before Home Assistant, while `application` is started afterwards. Finally `once` is for applications that don't run as a daemon. |
| webui | string | no | A URL for web interface of this add-on. Like `http://[HOST]:[PORT:2839]/dashboard`, the port needs the internal port, which will be replaced with the effective port. It is also possible to bind the proto part to a config options with: `[PROTO:option_name]://[HOST]:[PORT:2839]/dashboard` and he lookup if they is True and going to `https`. |
| boot | string | yes | `auto` by system and manual or only `manual` |
| ports | dict | no | Network ports to expose from the container. Format is `"container-port/type": host-port`. |
| host_network | bool | no | If that is True, the add-on run on host network. |
| host_ipc | bool | no | Default False. Allow to share the IPC namespace with others. |
| host_dbus | bool | no | Default False. Map Host dbus service into add-on. |
| host_pid | bool | no | Default False. Allow to run container on host PID namespace. Work only for not protected add-ons. |
| devices | list | no | Device list to map into the add-on. Format is: `<path_on_host>:<path_in_container>:<cgroup_permissions>`. i.e. `/dev/ttyAMA0:/dev/ttyAMA0:rwm` |
| auto_uart | bool | no | Default False. Auto mapping all UART/Serial device from host into add-on. |
| hassio_role | str | no | Default `default`. Role based access to Hass.io API. Available: `default`, `homeassistant`, `backup`, `manager`, `admin`. |
| hassio_api | bool | no | This add-on can access to Hass.io REST API. It set the host alias `hassio`. |
| homeassistant_api | bool | no | This add-on can access to Hass.io Home-Assistant REST API proxy. Use `http://hassio/homeassistant/api`. |
| docker_api | bool | no | Allow read-oly access to docker API for add-on. Work only for not protected add-ons. |
| privileged | list | no | Privilege for access to hardware/system. Available access: `NET_ADMIN`, `SYS_ADMIN`, `SYS_RAWIO`, `SYS_TIME`, `SYS_NICE`, `SYS_RESOURCE`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH`. |
| full_access | bool | no | Give full access to hardware like the privileged mode in docker. Work only for not protected add-ons. |
| apparmor | bool/string | no | Enable or disable AppArmor support. If it is enable, you can also use custom profiles with the name of the profile. |
| map | list | no | List of maps for additional Hass.io folders. Possible values: `config`, `ssl`, `addons`, `backup`, `share`. Defaults to `ro`, which you can change by adding `:rw` to the end of the name. |
| environment | dict | no | A dict of environment variable to run add-on. |
| audio | bool | no | Boolean. Mark this add-on to use internal an audio system. The ALSA configuration for this add-on will be mount automatic. |
| gpio | bool | no | Boolean. If this is set to True, `/sys/class/gpio` will map into add-on for access to GPIO interface from kernel. Some library need also `/dev/mem` and `SYS_RAWIO` for read/write access to this device. On system with AppArmor enabled, you need disable AppArmor or better for security, provide you own profile for the add-on. |
| devicetree | bool | no | Boolean. If this is set to True, `/device-tree` will map into add-on. |
| kernel_modules | bool | no | Map host kernel modules and config into add-on (readonly). |
| stdin | bool | no | Boolean. If that is enable, you can use the STDIN with Hass.io API. |
| legacy | bool | no | Boolean. If the docker image have no hass.io labels, you can enable the legacy mode to use the config data. |
| options | dict | yes | Default options value of the add-on |
| schema | dict | yes | Schema for options value of the add-on. It can be `False` to disable schema validation and use custom options. |
| image | string | no | For use with Docker Hub and other container registries. |
| timeout | integer | no | Default 10 (second). The timeout to wait until the docker is done or will be killed. |
| tmpfs | string | no | Mount a tmpfs file system in `/tmpfs`. Valide format for this option is : `size=XXXu,uid=N,rw`. Size is mandatory, valid units (`u`) are `k`, `m` and `g` and `XXX` has to be replaced by a number. `uid=N` (with `N` the uid number) and `rw` are optional. |
| discovery | list | no | A list of services they this Add-on allow to provide for Home Assistant. Currently supported: `mqtt` |
| services | list | no | A list of services they will be provided or consumed with this Add-on. Format is `service`:`function` and functions are: `provide` (this add-on can provide this service), `want` (this add-on can use this service) or `need` (this add-on need this service to work correctly). |
| auth_api | bool | no | Allow access to Home Assistent user backend. |
### Options / Schema
The `options` dictionary contains all available options and their default value. Set the default value to `null` if the value is required to be given by the user before the add-on can start, and it show it inside default values. Only nested arrays and dictionaries are supported with a deep of two size. If you want make an option optional, put `?` to the end of data type, otherwise it will be a required value.
```json
{
"message": "custom things",
"logins": [
{ "username": "beer", "password": "123456" },
{ "username": "cheep", "password": "654321" }
],
"random": ["haha", "hihi", "huhu", "hghg"],
"link": "http://example.com/",
"size": 15,
"count": 1.2
}
```
The `schema` looks like `options` but describes how we should validate the user input. For example:
```json
{
"message": "str",
"logins": [
{ "username": "str", "password": "str" }
],
"random": ["match(^\w*$)"],
"link": "url",
"size": "int(5,20)",
"count": "float",
"not_need": "str?"
}
```
We support:
- str
- bool
- int / int(min,) / int(,max) / int(min,max)
- float / float(min,) / float(,max) / float(min,max)
- email
- url
- port
- match(REGEX)
## Add-on extended build
Additional build options for an add-on is stored in `build.json`. This file will be read from our build systems. You need this only, if you not use the default images or need additionals things.
```json
{
"build_from": {
"armhf": "mycustom/base-image:latest"
},
"squash": false,
"args": {
"my_build_arg": "xy"
}
}
```
| 키 | Required | 설명 |
| ---------- | -------- | ------------------------------------------------------------------------------------------------------ |
| build_from | no | A dictionary with the hardware architecture as the key and the base Docker image as value. |
| squash | no | Default `False`. Be carfully with this option, you can not use the image for caching stuff after that! |
| args | no | Allow to set additional Docker build arguments as a dictionary. |

View File

@ -0,0 +1,13 @@
---
title: Area Registry
sidebar_label: 대하여
id: version-0.87.0-area_registry_index
original_id: area_registry_index
---
The area registry is a registry where Home Assistant keeps track of areas. An area represents a physical location for Home Assistant. It can be used to place devices in different areas.
| Attribute | 설명 |
| --------- | ----------------------------------------------- |
| id | Unique ID of area (generated by Home Assistant) |
| name | Name of this area |

View File

@ -0,0 +1,71 @@
---
title: Checklist for creating a component
sidebar_label: Component Checklist
id: version-0.91.2-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. Requirements have been added to [`manifest.json`](creating_integration_manifest.md). The `REQUIREMENTS` constant is deprecated.
2. Requirement version should be pinned: `"requirements": ['phue==0.8.1']`
3. We no longer want requirements hosted on GitHub. Please upload to PyPi.
4. Requirements should only be imported inside functions. 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. You can share data with your platforms by leveraging `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()
```
[Tutorial on publishing your own PyPI package](https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/)
### 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 domain name. 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.

View File

@ -0,0 +1,9 @@
---
title: creating_component_deps_and_reqs
id: version-0.91.2-creating_component_deps_and_reqs
original_id: creating_component_deps_and_reqs
---
[This page has moved.](creating_integration_manifest.md)
<script>document.location = 'creating_integration_manifest.html';</script>

View File

@ -0,0 +1,22 @@
---
title: Integration with Multiple Platforms
sidebar_label: Multiple platforms
id: version-0.91.2-creating_component_generic_discovery
original_id: creating_component_generic_discovery
---
Most integrations consist of a single platform. And in that case, it's fine to just define that one platform. However, if you are going to add a second platform, you will want to centralize your connection logic. This is done inside the component (`__init__.py`).
If your integration is configurable via `configuration.yaml`, it will cause the entry point of your configuration to change, as now users will need to set up your integration directly, and it is up to your integration to set up the platforms.
## Loading platforms when configured via a config entry
If your integration is set up via a config entry, you will need to forward the config entry to the appropriate integration to set up your platform. For more info, see the [config entry documentation](config_entries_index.md#for-platforms).
## Loading platforms when configured via configuration.yaml
If your integration is not using config entries, it will have to use our discovery helpers to set up its platforms. Note, this approach does not support unloading.
To do this, you will need to use the `load_platform` and `async_load_platform` methods from the discovery helper.
- See also a [full example that implementing this logic](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_load_platform/)

View File

@ -0,0 +1,40 @@
---
title: Creating a Minimal Component
sidebar_label: Minimal Component
id: version-0.91.2-creating_component_index
original_id: creating_component_index
---
Alright, you learned about the [manifest](creating_integration_manifest.md), so it's time to write your first code for your integration. AWESOME. Don't worry, we've tried hard to keep it as easy as possible.
More extensive examples of integrations are available from [our example repository](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/).
## The code
Each component needs to have 2 basic parts: it needs to define a `DOMAIN` constant that contains the domain of the integration. The second part is that it needs to define a setup method that returns a boolean if the set up was successful. So let's take a look at how this looks:
```python
DOMAIN = 'hello_state'
def setup(hass, config):
hass.states.set('hello_state.world', 'Paulus')
# Return boolean to indicate that initialization was successful.
return True
```
And if you prefer an async component:
```python
DOMAIN = 'hello_state'
async def async_setup(hass, config):
hass.states.async_set('hello_state.world', 'Paulus')
# Return boolean to indicate that initialization was successful.
return True
```
That's it! If you load this, you will see a new state in the state machine.
To load this, add `hello_state:` to your `configuration.yaml` file and create a file `<config_dir>/custom_components/hello_state/__init__.py` with the below code to test it locally.

View File

@ -0,0 +1,33 @@
---
title: Integration File Structure
sidebar_label: File Structure
id: version-0.91.2-creating_integration_file_structure
original_id: creating_integration_file_structure
---
Each integration is stored inside a directory named after the integration domain. The domain is a short name consisting of characters and underscores. This domain has to be unique and cannot be changed. Example of the domain for the mobile app integration: `mobile_app`. So all files for this integration are in the folder `mobile_app/`.
The bare minimum content of this folder looks like this:
- `manifest.json`: The manifest file describes the integration and its dependencies. [More info](creating_integration_manifest.md)
- `__init__.py`: The component file. If the integration only offers a platform, you can keep this file limited to a docstring introducing the integration `"""The Mobile App integration."""`.
## Integrating devices - `light.py`, `switch.py` etc
If your integration is going to integrate one or more devices, you will need to do this by creating a platform that interacts with an entity integration. For example, if you want to represent a light device inside Home Assistant, you will create `light.py`, which will contain a light platform for the light integration.
- More info on [available entity integrations](entity_index.md).
- More info on [creating platforms](creating_platform_index.md).
## Integrating services - `services.yaml`
If your integration is going to register services, it will need to provide a description of the available services. The description is stored in `services.yaml`. [More information about `services.yaml`.](dev_101_services.md)
## Where Home Assistant looks for integrations
Home Assistant will look for an integration when it sees the domain referenced in the config file (i.e. `mobile_app:`) or if it is a dependency of another integration. Home Assistant will look at the following locations:
- `<config directory>/custom_components/<domain>`
- `homeassistant/components/<domain>` (built-in integrations)
You can override a built-in integration by having an integration with the same domain in your `config/custom_components` folder. Note that overriding built-in components is not recommended as you will no longer get updates. It is recommended to pick a unique name.

View File

@ -0,0 +1,79 @@
---
title: Integration Manifest
sidebar_label: Manifest
id: version-0.91.2-creating_integration_manifest
original_id: creating_integration_manifest
---
Each integration has a manifest file to specify basic information about an integration. This file is stored as `manifest.json` in your integration directory. It is required to add such a file, including for custom components.
```json
{
"domain": "hue",
"name": "Philips Hue",
"documentation": "https://www.home-assistant.io/components/hue",
"dependencies": ["mqtt"],
"codeowners": ["@balloob"],
"requirements": ["aiohue==1.9.1"]
}
```
Or a minimal example that you can copy into your project:
```json
{
"domain": "your_domain_name",
"name": "Your Intgration",
"documentation": "https://www.example.com",
"dependencies": [],
"codeowners": [],
"requirements": []
}
```
## Domain
The domain is a short name consisting of characters and underscores. This domain has to be unique and cannot be changed. Example of the domain for the mobile app integration: `mobile_app`.
## Name
The name of the integration.
## Documentation
The website containing documentation on how to use your integration. If this integration is being submitted for inclusion in Home Assistant, it should be `https://www.home-assistant.io/components/<domain>`
## Dependencies
Dependencies are other Home Assistant integrations that you want Home Assistant to set up successfully prior to the integration being loaded. This can be necessary in case you want to offer functionality from that other integration, like using webhooks or an MQTT connection.
## Code Owners
GitHub usernames or team names of people that are responsible for this integration. You should add at least your GitHub username here, as well as anyone who helped you to write code that is being included.
## Requirements
Requirements are Python libraries or modules that you would normally install using `pip` for your component. Home Assistant will try to install the requirements into the `deps` subdirectory of the Home Assistant [configuration directory](https://www.home-assistant.io/docs/configuration/) if you are not using a `venv` or in something like `path/to/venv/lib/python3.6/site-packages` if you running in a virtual environment. This will make sure that all requirements are present at startup. If steps fail, like missing packages for the compilation of a module or other install errors, the component will fail to load.
Requirements is a list of strings. Each entry is a `pip` compatible string. For example, the media player Cast platform depends on the Python package PyChromecast v0.6.12: `['pychromecast==0.6.12']`.
> Because of how Home Assistant installs requirements on demand, actual Python imports of your requirements should be done inside functions instead of at the root level of your Python files.
### Custom requirements during development & testing
During the development of a component, it can be useful to test against different versions of a requirement. This can be done in two steps, using `pychromecast` as an example:
```bash
pip install pychromecast==0.6.13 --target ~/.homeassistant/deps
hass --skip-pip
```
This will use the specified version, and prevent Home Assistant from trying to override it with what is specified in `requirements`.
If you need to make changes to a requirement to support your component, it's also possible to install a development version of the requirement using `pip install -e`:
```bash
git clone https://github.com/balloob/pychromecast.git
pip install ./pychromecast
hass --skip-pip
```

View File

@ -0,0 +1,95 @@
---
title: Checklist for creating a platform
sidebar_label: Platform Checklist
id: version-0.91.2-creating_platform_code_review
original_id: creating_platform_code_review
---
A checklist of things to do when you're adding a new platform.
> 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 platform level
- Use `CONF_MONITORED_CONDITIONS` instead of `CONF_MONITORED_VARIABLES`
### 1. Requirements
1. Requirements have been added to [`manifest.json`](creating_integration_manifest.md). The `REQUIREMENTS` constant is deprecated.
2. Requirement version should be pinned: `"requirements": ['phue==0.8.1']`
3. We no longer want requirements hosted on GitHub. Please upload to PyPi.
4. Requirements should only be imported inside functions. This is necessary because requirements are installed on the fly.
### 2. Dependencies
1. If you depend on a component for the connection, add it to your dependencies in [`manifest.json`](creating_integration_manifest.md): `"dependencies": ['nest']`. The `DEPENDENCIES` constant is deprecated.
### 3. Configuration
1. Voluptuous schema present for [configuration validation](development_validation.md)
2. Voluptuous schema extends schema from component
(e.g., `hue.light.PLATFORM_SCHEMA` extends `light.PLATFORM_SCHEMA`)
3. Default parameters specified in voluptuous schema, not in `setup_platform(...)`
4. Your `PLATFORM_SCHEMA` should use as many generic config keys as possible from `homeassistant.const`
5. Never depend on users adding things to `customize` to configure behavior inside your platform.
```python
import voluptuous as vol
from homeassistant.const import CONF_FILENAME, CONF_HOST
from homeassistant.components.light import PLATFORM_SCHEMA
import homeassistant.helpers.config_validation as cv
CONF_ALLOW_UNREACHABLE = 'allow_unreachable'
DEFAULT_UNREACHABLE = False
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_ALLOW_UNREACHABLE,
default=DEFAULT_UNREACHABLE): cv.boolean,
vol.Optional(CONF_FILENAME): cv.string,
})
```
### 4. Setup Platform
1. Verify that the passed in configuration (user/pass/host etc.) works.
2. Group your calls to `add_devices` if possible.
3. If the platform adds extra services, the format should be `<domain of your integration>.<service name>`. So if your integration's domain is "awesome_sauce" and you are making a light platform, you would register services under the `awesome_sauce` domain. Make sure that your services [verify permissions](auth_permissions.md#checking-permissions).
### 5. Entity
1. Extend the entity from the integration you're building a platform for.
```python
from homeassistant.components.light import Light
class HueLight(Light):
...
```
2. Avoid passing in `hass` as a parameter to the entity. When the entity has been added to Home Assistant, `hass` will be set on the entity when the entity is added to Home Assistant. This means you can access `hass` as `self.hass` inside the entity.
3. Do not call `update()` in constructor, use `add_entities(devices, True)` instead.
4. Do not do any I/O inside properties. Cache values inside `update()` instead.
5. When dealing with time, state and/or attributes should not contain relative time since something happened. Instead, it should store UTC timestamps.
6. Leverage the [entity lifecycle callbacks](entity_index.md#lifecycle-hooks) to attach event listeners or clean up connections.
### 6. 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()
```
[Tutorial on publishing your own PyPI package](https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/)

View File

@ -0,0 +1,9 @@
---
title: creating_platform_example_light
id: version-0.91.2-creating_platform_example_light
original_id: creating_platform_example_light
---
[This page has moved.](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light)
<script>document.location = 'https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light';</script>

View File

@ -0,0 +1,9 @@
---
title: creating_platform_example_sensor
id: version-0.91.2-creating_platform_example_sensor
original_id: creating_platform_example_sensor
---
[This page has moved.](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor)
<script>document.location = 'https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor';</script>

View File

@ -0,0 +1,23 @@
---
title: Integration Platforms
sidebar_label: Platforms
id: version-0.91.2-creating_platform_index
original_id: creating_platform_index
---
Home Assistant has various built-in integrations that abstract device types. There are [lights](entity_light.md), [switches](entity_switch.md), [covers](entity_cover.md), [climate devices](entity_climate.md), and [many more](entity_index.md). Your integration can hook into these integrations by creating a platform. You will need a platform for each integration that you are integrating with.
To create a platform, you will need to create a file with the domain name of the integration that you are building a platform for. So if you are building a light, you will add a new file `light.py` to your integration folder.
We have created two example integrations that should give you a look at how this works:
- [Example sensor platform](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor/): hello world of platforms.
- [Example light platform](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light/): showing best practices.
### Interfacing with devices
One Home Assistant rule is that the integration should never interface directly with devices. Instead, it should interact with a third-party Python 3 library. This way, Home Assistant can share code with the Python community and keep the project maintainable.
Once you have your Python library ready and published to PyPi, add it to the [manifest](creating_integration_manifest.md). It will now be time to implement the Entity base class that is provided by the integration that you are creating a platform for.
Find your integration at the [entity index](entity_index.md) to see what methods and properties are available to implement.

View File

@ -0,0 +1,78 @@
---
title: Integration Services
sidebar_label: Custom Services
id: version-0.91.2-dev_101_services
original_id: dev_101_services
---
Home Assistant provides ready-made services for a lot of things, but it doesn't always cover everything. Instead of trying to change Home Assistant, it is preferred to add it as a service under your own integration first. Once we see a pattern in these services, we can talk about generalizing them.
This is a simple "hello world" example to show the basics of registering a service. To use this example, create the file `<config dir>/custom_components/hello_service/__init__.py` and copy the below example code.
Services can be called from automations and from the service "Developer tools" in the frontend.
```python
DOMAIN = 'hello_service'
ATTR_NAME = 'name'
DEFAULT_NAME = 'World'
def setup(hass, config):
"""Set up is called when Home Assistant is loading our component."""
def handle_hello(call):
"""Handle the service call."""
name = call.data.get(ATTR_NAME, DEFAULT_NAME)
hass.states.set('hello_service.hello', name)
hass.services.register(DOMAIN, 'hello', handle_hello)
# Return boolean to indicate that initialization was successfully.
return True
```
Load the integration by adding the following to your `configuration.yaml`. When your component is loaded, a new service should be available to call.
```yaml
# configuration.yaml entry
hello_service:
```
Open the frontend and in the sidebar, click the first icon in the developer tool section. This will open the Call Service developer tool. On the right, find your service and click on it. This will automatically fill in the correct values.
Pressing "Call Service" will now call your service without any parameters. This will cause your service to create a state with the default name 'World'. If you want to specify the name, you have to specify parameters. Add the following JSON as Service Data and press "Call Service again".
```json
{
"name": "Planet"
}
```
The service will now overwrite the previous state with "Planet".
## Service descriptions
Adding services is only useful if users know about them. In Home Assistant we use a `services.yaml` as part of your integration to describe the services.
Services are published under the domain name of your integration, so in `services.yaml` we only use the service name as the base key.
```yaml
# Example services.yaml entry
set_speed:
# Description of the service
description: Sets fan speed.
# Different fields that your service accepts
fields:
# Key of the field
entity_id:
# Description of the field
description: Name(s) of the entities to set
# Example value that can be passed for this field
example: 'fan.living_room'
speed:
description: Speed setting
example: 'low'
```

View File

@ -0,0 +1,128 @@
---
title: Using States
id: version-0.91.2-dev_101_states
original_id: dev_101_states
---
Home Assistant keeps track of the states of entities in a state machine. The state machine has very few requirements:
- Each state is related to an entity identified by an entity id. This id is made up of a domain and an object id. For example `light.kitchen_ceiling`. You can make up any combination of domain and object id, even overwriting existing states.
- Each state has a primary attribute that describes the state of the entity. In the case of a light this could be for example "on" and "off". You can store anything you want in the state, as long as it's a string (will be converted if it's not).
- You can store more information about an entity by setting attributes. Attributes is a dictionary that can contain any data that you want. The only requirement is that it's JSON serializable, so you're limited to numbers, strings, dictionaries and lists.
[Description of the state object.](https://www.home-assistant.io/docs/configuration/state_object/)
## Using states in your component
This is a simple tutorial/example on how to create and set states. We will do our work in a component called "hello_state". The purpose of this component is to display a given text in the frontend.
To get started, create the file `<config dir>/custom_components/hello_state.py` and copy the below example code.
```python
"""
Support for showing text in the frontend.
For more details about this component, please refer to the documentation at
https://home-assistant.io/cookbook/python_component_basic_state/
"""
import logging
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'hello_state'
def setup(hass, config):
"""Setup the Hello State component. """
_LOGGER.info("The 'hello state' component is ready!")
return True
```
1. In the file header we decided to add some details: A short description and the link to the documentation.
2. We want to do some logging. This means that we import the Python logging module and create an alias.
3. The component name is equal to the domain name.
4. The `setup` function will take care of the initialization of our component. The component will only write a log message. Keep in mind for later that you have several options for the severity:
- `_LOGGER.info(msg)`
- `_LOGGER.warning(msg)`
- `_LOGGER.error(msg)`
- `_LOGGER.critical(msg)`
- `_LOGGER.exception(msg)`
5. We return `True` if everything is ok.
Add the component to your `configuration.yaml` file.
```yaml
hello_state:
```
After a start or a restart of Home Assistant the component will create an entry in the log.
```bash
16-03-12 14:16:42 INFO (MainThread) [custom_components.hello_state] The 'hello state' component is ready!
```
The next step is the introduction of configuration options. A user can pass configuration options to our component via `configuration.yaml`. To use them we'll use the passed in `config` variable to our `setup` method.
```python
import logging
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'hello_state'
CONF_TEXT = 'text'
DEFAULT_TEXT = 'No text!'
def setup(hass, config):
"""Set up the Hello State component. """
# Get the text from the configuration. Use DEFAULT_TEXT if no name is provided.
text = config[DOMAIN].get(CONF_TEXT, DEFAULT_TEXT)
# States are in the format DOMAIN.OBJECT_ID
hass.states.set('hello_state.Hello_State', text)
return True
```
To use the latest feature of our component, update the entry in your `configuration.yaml` file.
```yaml
hello_state:
text: 'Hello, World!'
```
Thanks to `DEFAULT_TEXT` variable the component will launch even if no `text:` field is used in the `configuration.yaml` file. Quite often there are variables which are required. It's important to check if all mandatory configuration variables are provided. If not, the setup should fail. We will use `voluptuous` as a helper to achieve this. The next listing shows the essential parts.
```python
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_TEXT): cv.string,
})
}, extra=vol.ALLOW_EXTRA)
```
Now, when `text:` is missing from the config, Home Assistant will alert the user and not setup your component.
After a start or a restart of Home Assistant the component will be visible in the frontend if the `configuration.yaml` file is up-to-date.
<p class='img'>
<img src='/img/en/development/create-component01.png' />
</p>
In order to expose attributes for a platform, you will need to define a property called `device_state_attributes` on the entity class, which will return a dictionary of attributes:
@property
def device_state_attributes(self):
"""Return device specific state attributes."""
return self._attributes
> Entities also have a similar property `state_attributes`, which normally doesn't need to be defined by new platforms. This property is used by base components to add standard sets of attributes to a state. Example: The light component uses `state_attributes` to add brightness to the state dictionary. If you are designing a new component, you should define `state_attributes` instead.
To get your component included in the Home Assistant releases, follow the steps described in the [Submit your work](development_submitting.md) section. Basically you only need to move your component in the `homeassistant/component/` directory of your fork and create a Pull Request.

View File

@ -0,0 +1,17 @@
---
title: Development Checklist
sidebar_label: 대하여
id: version-0.91.2-development_checklist
original_id: development_checklist
---
Before you commit any changes, check your work against these requirements:
- All communication to external devices or services must be wrapped in an external Python library hosted on [pypi](https://pypi.python.org/pypi).
- New dependencies are added to `requirements_all.txt` (if applicable), using `script/gen_requirements_all.py`
- New codeowners are added to `CODEOWNERS` (if applicable), using `script/manifest/codeowners.py`
- The `.coveragerc` file is updated to exclude your platform if there are no tests available or your new code uses a third-party library for communication with the device, service, or sensor
- Documentation is developed for [home-assistant.io](https://home-assistant.io/)
- Visit the [website documentation](https://www.home-assistant.io/developers/documentation/) for more information about contributing to [home-assistant.io](https://github.com/home-assistant/home-assistant.github.io).
- All dependencies are only imported inside functions that use them.

View File

@ -0,0 +1,83 @@
---
title: Style guidelines
id: version-0.91.2-development_guidelines
original_id: development_guidelines
---
Home Assistant enforces strict [PEP8 style](https://www.python.org/dev/peps/pep-0008/) and [PEP 257 (Docstring Conventions)](https://www.python.org/dev/peps/pep-0257/) compliance on all code submitted. We automatically test every pull request as part of the linting process.
Summary of the most relevant points:
- Line length is limited to 79 characters (see below).
- Use 4 spaces per indentation level. We don't use tabs.
- Comments should be full sentences and end with a period.
- [Imports](https://www.python.org/dev/peps/pep-0008/#imports) should be ordered.
- Constants and the content of lists and dictionaries should be in alphabetical order.
- Avoid trailing whitespace but surround binary operators with a single space.
- Line separator should be set to `LF`.
The maximum line length comes directly from the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/#maximum-line-length), and is also used by the Python standard library. All code must pass these linting checks, and no exceptions will be made. There have already been numerous requests to increase the maximum line length, but after evaluating the options, the Home Assistant maintainers have decided to stay at 79 characters. This decision is final.
Those points may require that you adjust your IDE or editor settings.
## Our recommendations
For some cases [PEPs](https://www.python.org/dev/peps/) don't make a statement. This section covers our recommendations about the code style. Those points were collected from the existing code and based on what contributors and developers were using the most. This is basically a majority decision, thus you may not agree with it. But we would like to encourage you follow those recommendations to keep the code unified.
### Quotes
Use single quotes `'` for single word and `"` for multiple words or sentences.
```python
ATTR_WATERLEVEL = 'level'
CONF_ATTRIBUTION = "Data provided by the WUnderground weather service"
SENSOR_TYPES = {
'alerts': ['Alerts', None],
}
```
### File headers
The docstring in the file header should describe what the file is about.
```python
"""Support for MQTT lights."""
```
### Log messages
There is no need to add the platform or component name to the log messages. This will be added automatically. Like `syslog` messages there shouldn't be any period at the end. Try to avoid brackets and additional quotes around the output to make it easier for users to parse the log. A widely style is shown below but you are free to compose the messages as you like.
```python
_LOGGER.error("No route to device: %s", self._resource)
```
```bash
2017-05-01 14:28:07 ERROR [homeassistant.components.sensor.arest] No route to device: 192.168.0.18
```
Don't print out wrong API keys, tokens, usernames, or passwords. Also note that `_LOGGER.info` is reserved for the core, use `_LOGGER.debug` in anything else.
### Ordering of imports
Instead of order the imports manually, use [`isort`](https://github.com/timothycrosley/isort).
```bash
$ pip3 install isort
$ isort homeassistant/components/sensor/fixer.py
```
### Use new style string formatting
Prefer [new style string formatting](https://www.python.org/dev/peps/pep-3101/) over old.
```python
"{} {}".format('New', 'style')
"%s %s" % ('Old', 'style')
```
Except when doing logging here the format is:
```python
_LOGGER.info("Can't connect to the webservice %s at %s", string1, string2)
```

View File

@ -0,0 +1,12 @@
---
title: Starting with Development
sidebar_label: 대하여
id: version-0.91.2-development_index
original_id: development_index
---
Home Assistant is built from the ground up to be easily extensible using integrations. In this section, we're focusing on how to develop integrations.
Before you start, make sure that you have read up on the [Home Assistant architecture](architecture_index.md) so that you are familiar with the concepts that make up Home Assistant.
If you run into trouble following this documentation, don't hesitate to join our #devs_backend channel on [Discord](https://www.home-assistant.io/join-chat/).

View File

@ -0,0 +1,82 @@
---
title: Validate the input
id: version-0.91.2-development_validation
original_id: development_validation
---
The `configuration.yaml` file contains the configuration options for components and platforms. We use [voluptuous](https://pypi.python.org/pypi/voluptuous) to make sure that the configuration provided by the user is valid. Some entries are optional or could be required to set up a platform or a component. Others must be a defined type or from an already-defined list.
We test the configuration to ensure that users have a great experience and minimize notifications if something is wrong with a platform or component setup before Home Assistant runs.
Besides [voluptuous](https://pypi.python.org/pypi/voluptuous) default types, many custom types are available. For an overview, take a look at the [config_validation.py](https://github.com/home-assistant/home-assistant/blob/master/homeassistant/helpers/config_validation.py) helper.
- Types: `string`, `byte`, and `boolean`
- Entity ID: `entity_id` and `entity_ids`
- Numbers: `small_float` and `positive_int`
- Time: `time`, `time_zone`
- Misc: `template`, `slug`, `temperature_unit`, `latitude`, `longitude`, `isfile`, `sun_event`, `ensure_list`, `port`, `url`, and `icon`
To validate platforms using [MQTT](https://www.home-assistant.io/components/mqtt/), `valid_subscribe_topic` and `valid_publish_topic` are available.
Some things to keep in mind:
- Use the constants defined in `const.py`
- Import `PLATFORM_SCHEMA` from the integration you are integrating with and extend it.
- Preferred order is `required` first and `optional` second
- Default values for optional configuration keys need to be valid values. Don't use a default which is `None` like `vol.Optional(CONF_SOMETHING, default=None): cv.string`, set the default to `default=''` if required.
### Snippets
This section contains snippets for the validation we use.
#### Default name
It's common to set a default for a sensor if the user doesn't provide a name to use.
```python
DEFAULT_NAME = 'Sensor name'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
```
#### Limit the values
You might want to limit the user's input to a couple of options.
```python
DEFAULT_METHOD = 'GET'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']),
```
#### Port
All port numbers are from a range of 1 to 65535.
```python
DEFAULT_PORT = 993
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
```
#### Lists
If a sensor has a pre-defined list of available options, test to make sure the configuration entry matches the list.
```python
SENSOR_TYPES = {
'article_cache': ('Article Cache', 'MB'),
'average_download_rate': ('Average Speed', 'MB/s'),
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_MONITORED_VARIABLES, default=[]):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
```

View File

@ -0,0 +1,33 @@
---
title: Sensor Entity
sidebar_label: Sensor
id: version-0.91.2-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 | 구분 | Default | 설명 |
| --------------------- | ------ | ------------ | -------------------------------------------------------- |
| 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.
| 구분 | Unit | 설명 |
| --------------- | -------- | -------------------------- |
| battery | % | % of battery that is left. |
| humidity | % | % of humidity in the air. |
| illuminance | lx/lm | Light level. |
| signal_strength | dB/dBm | Signal strength. |
| temperature | °C/°F | Temperature. |
| timestamp | ISO8601 | Timestamp. |
| power | W,kW | Power. |
| pressure | hPa,mbar | Pressure. |

View File

@ -0,0 +1,44 @@
---
title: Translation
id: version-0.91.2-internationalization_translation
original_id: internationalization_translation
---
Translations for Home Assistant are managed through [Lokalise](https://lokalise.co/), an online translation management tool. Our translations are split between two projects, a backend project for platform-specific translations, and a frontend project for UI translations. Click the links below to join both projects! Even if your language is completely translated, extra proofreading is a big help! Please feel free to review the existing translations, and vote for alternatives that might be more appropriate.
- [Join the frontend translation team](https://lokalise.co/signup/3420425759f6d6d241f598.13594006/all/)
- [Join the backend translation team](https://lokalise.co/signup/130246255a974bd3b5e8a1.51616605/all/)
- [Join the iOS translation team](https://lokalise.co/signup/834452985a05254348aee2.46389241/all/)
For more information about the translation workflow, please see the [Lokalise translation workflow documents](https://docs.lokalise.co/category/iOzEuQPS53-for-team-leads-and-translators).
> The translation of the Home Assistant frontend is still a work in progress. More phrases will be available for translation soon.
## Translation placeholders
Some translation strings will contain special placeholders that will be replaced later. Placeholders shown in square brackets `[]` are [Lokalise key references](https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing). These are primarily used to link translation strings that will be duplicated. Different languages may not have the same duplicates as English, and are welcome to link duplicate translations that are not linked in English. Placeholders shown in curly brackets `{}` are [translation arguments](https://formatjs.io/guides/message-syntax/) that will be replaced with a live value when Home Assistant is running. Any translation argument placeholders present in the original string must be included in the translated string. These may include special syntax for defining plurals or other replacement rules. The linked format.js guide explains the syntax for adding plural definitions and other rules.
## Rules
1. Only native speakers should submit translations.
2. Stick to [Material Design guidelines](https://material.io/guidelines/style/writing.html).
3. Don't translate or change proper nouns like `Home Assistant`, `Hass.io` or `Hue`.
4. For a region specific translation, keys that will be the same as the base translation should be filled with `[VOID]`. These will be replaced during our translation build process.
5. Translations under the `state_badge` keys will be used for the notification badge display. These translations should be short enough to fit in the badge label without overflowing. This can be tested in the Home Assistant UI either by editing the label text with your browsers development tools, or by using the States <img src='/img/dev-tools/states-icon.png' alt='states dev tool icon' class="inline" width="38" /> developer tool in the Home Assistant UI. In the UI, enter a new entity ID (`device_tracker.test`), and enter the text you want to test in state.
6. If text will be duplicated across different translation keys, make use of the Lokalise key reference feature where possible. The base translation provides examples of this underneath the `states` translations. Please see the [Lokalise key referencing](https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing) documentation for more details.
## Adding a new language
If your language is not listed you can request it at [GitHub](https://github.com/home-assistant/home-assistant-polymer/issues/new). Please provide both the English name and the native name for your language. For example:
English Name: German
Native Name: Deutsch
> Region specific translations (`en-US`, `fr-CA`) will only be included if translations for that region need to differ from the base language translation.
### Maintainer steps to add a new language
1. Language tags have to follow [BCP 47](https://tools.ietf.org/html/bcp47). A list of most language tags can be found here: [IANA sutbtag registry](http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry). Examples: `fr`, `fr-CA`, `zh-Hans`. Only include the country code if country specific overrides are being included, and the base language is already translated.
2. Add the language tag and native name in `src/translations/translationMetadata.json`. Examples: "Français", "Français (CA)"
3. Add the new language in Lokalize. Note: Sometimes you have to change the tag in Lokalise (Language -> Language settings -> custom ISO code).

View File

@ -0,0 +1,45 @@
---
title: Maintenance
id: version-0.91.2-maintenance
original_id: maintenance
---
This page documents a couple of points for maintaining the Home Assistant code. Most of the tasks don't need to be performed on a regular base thus the steps, used tools, or details are preserved here.
## Source code
### Line separator
People are using various operating systems to develop components and platforms for Home Assistant. This could lead to different line endings on file. We prefer `LN`. Especially Microsoft Windows tools tend to use `CRLF`.
```bash
$ find homeassistant -name "*.py" -exec file {} \; | grep BOM
$ find homeassistant -name "*.py" -exec file {} \; | grep CRLF
```
To fix the line separator, use `dos2unix` or `sed`.
```bash
$ dos2unix homeassistant/components/notify/kodi.py
```
### File permissions
Most files don't need to the be executable. `0644` is fine.
### Dependencies
A lot of components and platforms depends on third-party Python modules. The dependencies which are stored in the `requirements_*.txt` files are tracked by [Requires.io](https://requires.io/github/home-assistant/home-assistant/requirements/?branch=dev).
If you update the requirements of a component/platform by updating `manifest.json`, run the provided script to update the `requirements_*.txt` file(s).
```bash
$ script/gen_requirements_all.py
```
Start a test run of Home Assistant. If that was successful, include all files in a Pull Request. Add a short summary of the changes, a sample configuration entry, details about the tests you performed to ensure the update works, and other useful information to the description.
## Documentation
- Merge `current` into `next` on a regular base.
- Optimize the images.

View File

@ -0,0 +1,82 @@
---
title: Connecting to an instance
id: version-0.92.0-app_integration_setup
original_id: app_integration_setup
---
When a user first opens the app, they will need to connect to their local instance to authenticate and register the device.
## Authenticating the user
The local instance can be discovered if Home Assistant has the [zeroconf component](https://www.home-assistant.io/components/zeroconf) configured by searching for `_home-assistant._tcp.local.`. If not configured, the user will need to be asked for the local address of their instance.
When the address of the instance is known, the app will ask the user to authenticate via [OAuth2 with Home Assistant](auth_api.md). Home Assistant uses IndieAuth, which means that to be able to redirect to a url that triggers your app, you need to take some extra steps. Make sure to read the last paragraph of the "Clients" section thoroughly.
## Registering the device
*This requires Home Assistant 0.90 or later.*
Home Assistant has a `mobile_app` component that allows applications to register themselves and interact with the instance. This is a generic component to handle most common mobile application tasks. This component is extendable with custom interactions if your app needs more types of interactions than are offered by this component.
Once you have tokens to authenticate as a user, it's time to register the app with the mobile app component in Home Assistant.
### Getting Ready
First, you must ensure that the `mobile_app` component is loaded. There are two ways to do this:
- You can publish a Zeroconf/Bonjour record `_hass-mobile-app._tcp.local.` to trigger the automatic load of the `mobile_app` component. You should wait at least 60 seconds after publishing the record before continuing.
- You can ask the user to add `mobile_app` to their configuration.yaml and restart Home Assistant. If the user already has `default_config` in their configuration, then `mobile_app` will have been already loaded.
You can confirm the `mobile_app` component has been loaded by checking the `components` array of the [`/api/config` REST API call](external_api_rest.md#get-api-config). If you continue to device registration and receive a 404 status code, then it most likely hasn't been loaded yet.
### Registering the device
To register the device, make an authenticated POST request to `/api/mobile_app/registrations`. [More info on making authenticated requests.](auth_api.md#making-authenticated-requests)
Example payload to send to the registration endpoint:
```json
{
"app_id": "awesome_home",
"app_name": "Awesome Home",
"app_version": "1.2.0",
"device_name": "Robbies iPhone",
"manufacturer": "Apple, Inc.",
"model": "iPhone X",
"os_version": "iOS 10.12",
"supports_encryption": true,
"app_data": {
"push_notification_key": "abcdef",
}
}
```
| 키 | Required | 구분 | 설명 |
| --------------------- | -------- | ------ | --------------------------------------------------------------------------------------------------- |
| `app_id` | V | string | A unique identifier for this app. |
| `app_name` | V | string | Name of the mobile app. |
| `app_version` | V | string | Version of the mobile app. |
| `device_name` | V | string | Name of the device running the app. |
| `manufacturer` | V | string | The manufacturer of the device running the app. |
| `model` | V | string | The model of the device running the app. |
| `os_version` | V | string | The OS version of the device running the app. |
| `supports_encryption` | V | bool | If the app supports encryption. See also the [encryption section](#encryption). |
| `app_data` | | Dict | App data can be used if the app has a supporting component that extends `mobile_app` functionality. |
When you get a 200 response, the mobile app is registered with Home Assistant. The response is a JSON document and will contain the URLs on how to interact with the Home Assistant instance. You should permanently store this information.
```json
{
"cloudhook_url": "https://hooks.nabu.casa/randomlongstring123",
"remote_ui_url": "https://randomlongstring123.ui.nabu.casa",
"secret": "qwerty",
"webhook_id": "abcdefgh"
}
```
| 키 | 구분 | 설명 |
| --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cloudhook_url` | string | The cloudhook URL provided by Home Assistant Cloud. Only will be provided if user is actively subscribed to Nabu Casa. |
| `remote_ui_url` | string | The remote UI URL provided by Home Assistant Cloud. Only will be provided if user is actively subscribed to Nabu Casa. |
| `secret` | string | The secret to use for encrypted communication. Will only be included if encryption is supported by both the app and the Home Assistant instance. [More info](app_integration_sending_data.md#implementing-encryption). |
| `webhook_id` | string | The webhook ID that can be used to send data back. |

View File

@ -0,0 +1,68 @@
---
title: Multi-factor Authentication Modules
id: version-0.92.0-auth_auth_module
original_id: auth_auth_module
---
Multi-factor Authentication Modules are used in conjunction with [Authentication Provider](auth_auth_provider.html) to provide a fully configurable authentication framework. Each MFA module may provide one multi-factor authentication function. User can enable multiple mfa modules, but can only select one module in login process.
## Defining an mfa auth module
> We currently only support built-in mfa auth modules. Support for custom auth modules might arrive in the future.
Multi-factor Auth modules are defined in `homeassistant/auth/mfa_modules/<name of module>.py`. The auth module will need to provide an implementation of the `MultiFactorAuthModule` class.
For an example of a fully implemented auth module, please see [insecure_example.py](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/auth/mfa_modules/insecure_example.py).
Multi-factor Auth modules shall extend the following methods of `MultiFactorAuthModule` class.
| method | Required | 설명 |
| ---------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `@property def input_schema(self)` | Yes | Return a schema defined the user input form. |
| `async def async_setup_flow(self, user_id)` | Yes | Return a SetupFlow to handle the setup workflow. |
| `async def async_setup_user(self, user_id, setup_data)` | Yes | Set up user for use this auth module. |
| `async def async_depose_user(self, user_id)` | Yes | Remove user information from this auth module. |
| `async def async_is_user_setup(self, user_id)` | Yes | Return whether user is set up. |
| `async def async_validate(self, user_id, user_input)` | Yes | Given a user_id and user input, return validation result. |
| `async def async_initialize_login_mfa_step(self, user_id)` | No | Will be called once before display the mfa step of login flow. This is not initialization for the MFA module but the mfa step in login flow. |
## Setup Flow
Before user can use a multi-factor auth module, it has to be enabled or set up. All available modules will be listed in user profile page, user can enable the module he/she wants to use. A setup data entry flow will guide user finish the necessary steps.
Each MFA module need to implement a setup flow handler extends from `mfa_modules.SetupFlow` (if only one simple setup step need, `SetupFlow` can be used as well). For example for Google Authenticator (TOTP, Time-based One Time Password) module, the flow will need to be:
- Generate a secret and store it on instance of setup flow
- Return `async_show_form` with a QR code in the description (injected as base64 via `description_placeholders`)
- User scans code and enters a code to verify it scanned correctly and clock in synced
- TOTP module saved the secret along with user_id, module is enabled for user
## Workflow
![Multi Factor Authentication Workflow](/img/en/auth/mfa_workflow.png)
<!--
Source: https://drive.google.com/file/d/12_nANmOYnOdqM56BND01nPjJmGXe-M9a/view
-->
## Configuration example
```yaml
# configuration.xml
homeassistant:
auth_providers:
- type: homeassistant
- type: legacy_api_password
auth_mfa_modules:
- type: totp
- type: insecure_example
users: [{'user_id': 'a_32_bytes_length_user_id', 'pin': '123456'}]
```
In this example, user will first select from `homeassistant` or `legacy_api_password` auth provider. For `homeassistant` auth provider, user will first input username/password, if that user enabled both `totp` and `insecure_example`, then user need select one auth module, then input Google Authenticator code or input pin code base on the selection.
> insecure_example is only for demo purpose, please do not use it in production.
## Validation session
Not like auth provider, auth module use session to manage the validation. After auth provider validated, mfa module will create a validation session, include an experiation time and user_id from auth provider validate result. Mutli-factor auth module will not only verify the user input, but also verify the session is not expired. The validation session data is stored in your configuration directory.

View File

@ -0,0 +1,79 @@
---
title: Integration Manifest
sidebar_label: Manifest
id: version-0.92.0-creating_integration_manifest
original_id: creating_integration_manifest
---
Since 0.92.0, every integration has a manifest file to specify basic information about an integration. This file is stored as `manifest.json` in your integration directory. It is required to add such a file, including for custom components.
```json
{
"domain": "hue",
"name": "Philips Hue",
"documentation": "https://www.home-assistant.io/components/hue",
"dependencies": ["mqtt"],
"codeowners": ["@balloob"],
"requirements": ["aiohue==1.9.1"]
}
```
Or a minimal example that you can copy into your project:
```json
{
"domain": "your_domain_name",
"name": "Your Intgration",
"documentation": "https://www.example.com",
"dependencies": [],
"codeowners": [],
"requirements": []
}
```
## Domain
The domain is a short name consisting of characters and underscores. This domain has to be unique and cannot be changed. Example of the domain for the mobile app integration: `mobile_app`.
## Name
The name of the integration.
## Documentation
The website containing documentation on how to use your integration. If this integration is being submitted for inclusion in Home Assistant, it should be `https://www.home-assistant.io/components/<domain>`
## Dependencies
Dependencies are other Home Assistant integrations that you want Home Assistant to set up successfully prior to the integration being loaded. This can be necessary in case you want to offer functionality from that other integration, like using webhooks or an MQTT connection.
## Code Owners
GitHub usernames or team names of people that are responsible for this integration. You should add at least your GitHub username here, as well as anyone who helped you to write code that is being included.
## Requirements
Requirements are Python libraries or modules that you would normally install using `pip` for your component. Home Assistant will try to install the requirements into the `deps` subdirectory of the Home Assistant [configuration directory](https://www.home-assistant.io/docs/configuration/) if you are not using a `venv` or in something like `path/to/venv/lib/python3.6/site-packages` if you running in a virtual environment. This will make sure that all requirements are present at startup. If steps fail, like missing packages for the compilation of a module or other install errors, the component will fail to load.
Requirements is an array of strings. Each entry is a `pip` compatible string. For example, the media player Cast platform depends on the Python package PyChromecast v3.2.0: `["pychromecast==3.2.0"]`.
> Because of how Home Assistant installs requirements on demand, actual Python imports of your requirements should be done inside functions instead of at the root level of your Python files.
### Custom requirements during development & testing
During the development of a component, it can be useful to test against different versions of a requirement. This can be done in two steps, using `pychromecast` as an example:
```bash
pip install pychromecast==3.2.0 --target ~/.homeassistant/deps
hass --skip-pip
```
This will use the specified version, and prevent Home Assistant from trying to override it with what is specified in `requirements`.
If you need to make changes to a requirement to support your component, it's also possible to install a development version of the requirement using `pip install -e`:
```bash
git clone https://github.com/balloob/pychromecast.git
pip install -e ./pychromecast
hass --skip-pip
```

View File

@ -0,0 +1,23 @@
---
title: Integration Platforms
sidebar_label: Platforms
id: version-0.92.0-creating_platform_index
original_id: creating_platform_index
---
Home Assistant has various built-in integrations that abstract device types. There are [lights](entity_light.md), [switches](entity_switch.md), [covers](entity_cover.md), [climate devices](entity_climate.md), and [many more](entity_index.md). Your integration can hook into these integrations by creating a platform. You will need a platform for each integration that you are integrating with.
To create a platform, you will need to create a file with the domain name of the integration that you are building a platform for. So if you are building a light, you will add a new file `light.py` to your integration folder.
We have created two example integrations that should give you a look at how this works:
- [Example sensor platform](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor/): hello world of platforms.
- [Example light platform](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light/): showing best practices.
### Interfacing with devices
One Home Assistant rule is that the integration should never interface directly with devices. Instead, it should interact with a third-party Python 3 library. This way, Home Assistant can share code with the Python community and keep the project maintainable.
Once you have your Python library ready and published to PyPI, add it to the [manifest](creating_integration_manifest.md). It will now be time to implement the Entity base class that is provided by the integration that you are creating a platform for.
Find your integration at the [entity index](entity_index.md) to see what methods and properties are available to implement.

View File

@ -0,0 +1,43 @@
---
title: Submit your work
id: version-0.92.0-development_submitting
original_id: development_submitting
---
> Always base your Pull Requests of of the current **`dev`** branch, not `master`.
Submit your improvements, fixes, and new features to Home Assistant one at a time, using GitHub [Pull Requests](https://help.github.com/articles/using-pull-requests). Here are the steps:
1. From your fork's dev branch, create a new branch to hold your changes:
`git checkout -b some-feature`
2. Make your changes, create a [new platform](creating_platform_index.md), develop a [new component](creating_component_index.md), or fix [issues](https://github.com/home-assistant/home-assistant/issues).
3. [Test your changes](development_testing.md) and check for style violations.
4. If everything looks good according to these [musts](development_checklist.md), commit your changes:
`git add .`
`git commit -m "Add some-feature"`
- Write a meaningful commit message and not only `Update` or `Fix`.
- Use a capital letter to start with your commit message.
- Don't prefix your commit message with `[bla.bla]` or `platform:`.
- Consider adding tests to ensure that your code works.
5. Push your committed changes back to your fork on GitHub:
`git push origin HEAD`
6. Follow [these steps](https://help.github.com/articles/creating-a-pull-request/) to create your pull request.
- On GitHub, navigate to the main page of the Home Assistant repository.
- In the "Branch" menu, choose the branch that contains your commits (from your fork).
- To the right of the Branch menu, click **New pull request**.
- Use the base branch dropdown menu to select the branch you'd like to merge your changes into, then use the compare branch drop-down menu to choose the topic branch you made your changes in. Make sure the Home Assistant branch matches with your forked branch (`dev`) else you will propose ALL commits between branches.
- Type a title and complete the provided description for your pull request.
- Click **Create pull request**.
7. Check for comments and suggestions on your pull request and keep an eye on the [CI output](https://travis-ci.org/home-assistant/home-assistant/).

View File

@ -0,0 +1,232 @@
---
title: Climate Entity
sidebar_label: Climate
id: version-0.92.0-entity_climate
original_id: entity_climate
---
> A climate entity is a device that controls temperature, humidity, or fans, such as A/C systems and humidifiers. Derive entity platforms from [`homeassistant.components.climate.ClimateDevice`](https://github.com/home-assistant/home-assistant/blob/master/homeassistant/components/climate/__init__.py)
## 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 | 구분 | Default | 설명 |
| ------------------------- | ---------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| current_fan_mode | string | None | Returns the current fan mode. |
| current_hold_mode | string | None | The current hold mode, e.g., home, away, temp. |
| current_humidity | float | None | The current humidity. |
| current_operation | string | None | The current operation (e.g. heat, cool, idle). Used to determine `state`. |
| current_swing_mode | string | None | Returns the fan setting. |
| current_temperature | float | None | The current temperature. |
| fan_list | list | None | Returns the list of available fan modes. |
| is_aux_heat_on | bool | None | Returns True if an auxiliary heater is on. |
| is_away_mode_on | bool | None | Return true if away mode is on. |
| is_on | bool | None | Returns True if device is on. Used to determine `state`. |
| max_humidity | int | `DEFAULT_MAX_HUMIDITY` (value == 99) | Returns the maximum humidity. |
| max_temp | int | `DEFAULT_MAX_TEMP` (value == 35) | Returns the maximum temperature. |
| min_humidity | int | `DEFAULT_MIN_HUMIDITY` (value == 30) | Returns the minimum humidity. |
| min_temp | int | `DEFAULT_MIN_TEMP` (value == 7) | Returns the minimum temperature. |
| operation_list | list | None | List of available operation modes. |
| precision | float | PRECISION_WHOLE | The precision of the temperature in the system: tenths for TEMP_CELSIUS, whole number otherwise. |
| state | string | None | Returns the current state. |
| state_attributes | dictionary | N/A | The optional state attributes: current temperature, minimum temperature, maximum temperature, and target temperature. |
| supported_features | list | `NotImplementedError()` | Returns list of supported features. |
| swing_list | list | None | Returns the list of available swing modes. |
| target_humidity | float | None | The target humidity. |
| target_temperature | float | None | The temperature currently set to be reached. |
| target_temperature_high | float | None | The upper bound target temperature |
| target_temperature_low | float | None | The lower bound target temperature |
| target_temperature_step | float | None | The supported step of target temperature |
| temperature_unit | string | `NotImplementedError` | The unit of temperature measurement for the system (e.g. Celsius). |
### States
| Name | 설명 |
| ---------------- | ------------------------------ |
| STATE_HEAT | The device is set to heat. |
| STATE_COOL | The device is set to cool. |
| STATE_IDLE | The device is idle. |
| STATE_AUTO | The device is set to auto. |
| STATE_MANUAL | The device is set to manual. |
| STATE_DRY | The device is set to dry. |
| STATE_FAN_ONLY | The device is set to fan-only. |
| STATE_ECO | The device is set to eco-mode. |
### Supported features
Supported features constants are combined using the bitwise or (`|`) operator.
| Name | 설명 |
| --------------------------------- | ------------------------------------------------------ |
| SUPPORT_TARGET_TEMPERATURE | The device supports a target temperature. |
| SUPPORT_TARGET_TEMPERATURE_HIGH | The device supports an upper bound target temperature. |
| SUPPORT_TARGET_TEMPERATURE_LOW | The device supports a lower bound target temperature. |
| SUPPORT_TARGET_HUMIDITY | The device supports a target humidity. |
| SUPPORT_TARGET_HUMIDITY_HIGH | The device supports an upper bound target humidity. |
| SUPPORT_TARGET_HUMIDITY_LOW | The device supports a lower bound target humidity. |
| SUPPORT_FAN_MODE | The device supports fan modes. |
| SUPPORT_OPERATION_MODE | The device supports operation modes. |
| SUPPORT_HOLD_MODE | The device supports hold modes. |
| SUPPORT_SWING_MODE | The device supports swing modes. |
| SUPPORT_AWAY_MODE | The device supports away mode. |
| SUPPORT_AUX_HEAT | The device supports auxiliary heaters. |
| SUPPORT_ON_OFF | The device supports on/off states. |
## Methods
### Set fan mode
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
async def async_set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
```
### Set hold mode
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def set_hold_mode(self, hold_mode):
"""Set new target hold mode."""
async def async_set_hold_mode(self, hold_mode):
"""Set new target hold mode."""
```
### Set humidity
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def set_humidity(self, humidity):
"""Set new target humidity."""
async def async_set_humidity(self, humidity):
"""Set new target humidity."""
```
### Set operation mode
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def set_operation_mode(self, operation_mode):
"""Set new target operation mode."""
async def async_set_operation_mode(self, operation_mode):
"""Set new target operation mode."""
```
### Set swing mode
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def set_swing_mode(self, swing_mode):
"""Set new target swing operation."""
async def async_set_swing_mode(self, swing_mode):
"""Set new target swing operation."""
```
### Set temperature
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def set_temperature(self, **kwargs):
"""Set new target temperature."""
async def async_set_temperature(self, **kwargs):
"""Set new target temperature."""
```
### Turn auxiliary heater on
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def turn_aux_heat_on(self):
"""Turn auxiliary heater on."""
async def async_turn_aux_heat_on(self):
"""Turn auxiliary heater on."""
```
### Turn auxiliary heater off
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def turn_aux_heat_off(self):
"""Turn auxiliary heater off."""
async def async_turn_aux_heat_off(self):
"""Turn auxiliary heater off."""
```
### Turn away mode on
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def turn_away_mode_on(self):
"""Turn away mode on."""
async def async_turn_away_mode_on(self):
"""Turn away mode on."""
```
### Turn away mode off
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def turn_away_mode_off(self):
"""Turn away mode off."""
async def async_turn_away_mode_off(self):
"""Turn away mode off."""
```
### Turn the device on
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def turn_on(self):
"""Turn device on."""
async def async_turn_on(self):
"""Turn device on."""
```
### Turn the device off
```python
class MyClimateDevice(ClimateDevice):
# Implement one of these methods.
def turn_off(self):
"""Turn device off."""
async def async_turn_off(self):
"""Turn device off."""
```

View File

@ -0,0 +1,89 @@
---
title: Fan Entity
sidebar_label: Fan
id: version-0.92.0-entity_fan
original_id: entity_fan
---
A fan entity is a device that controls the different vetors of your fan susch as speed, direction and oscillation. Derive enitity platforms from ['homeassistant.components.fan.FanDevice'](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/fan/__init__.py).
## 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 | 구분 | Default | 설명 |
| ------------------ | ------- | ------- | --------------------------------------- |
| current_direction | str | None | Return the current direction of the fan |
| is_on | boolean | None | Return true if the entity is on |
| speed | str | None | Return the current speed |
| speed_list | list | None | Get the list of available speeds |
| state_attributes | dict | None | Return optional state attributes |
| supported_features | int | None | Flag supported features |
## Supported Features
| Constant | 설명 |
| --------------------- | ---------------------------------------------- |
| 'SUPPORT_DIRECTION' | The fan supports changing the direction of it. |
| 'SUPPORT_SET_SPEED' | The fan supports setting the speed. |
| 'SUPPORT_OSCILLATE' | The fan supports oscillation. |
## Methods
### Set direction
Only implement this method if the flag `SUPPORT_DIRECTION` is set.
```python
class FanEntity(ToggleEntity):
# Implement one of these methods.
def set_direction(self, direction: str) -> None:
"""Set the direction of the fan."""
async def async_set_direction(self, direction: str):
"""Set the direction of the fan."""
```
### Set speed
Only implement this method if the flag `SUPPORT_SET_SPEED` is set.
```python
class FanEntity(ToggleEntity):
# Implement one of these methods.
def set_speed(self, speed: str) -> None:
"""Set the speed of the fan."""
async def async_set_speed(self, speed: str):
"""Set the speed of the fan."""
```
### Turn on
```python
class FanEntity(ToggleEntity):
# Implement one of these methods.
def turn_on(self, speed: str = None, **kwargs) -> None:
"""Turn on the fan."""
async def async_turn_on(self, speed: str = None, **kwargs):
"""Turn on the fan."""
```
### Oscillate
Only implement this method if the flag `SUPPORT_OSCILLATE` is set.
```python
class FanEntity(ToggleEntity):
# Implement one of these methods.
def oscillate(self, oscillating: bool) -> None:
"""Oscillate the fan."""
def async_oscillate(self, oscillating: bool):
"""Oscillate the fan."""
```

View File

@ -0,0 +1,24 @@
---
title: Entity Registry
sidebar_label: 대하여
id: version-0.92.0-entity_registry_index
original_id: entity_registry_index
---
The entity registry is a registry where Home Assistant keeps track of entities. Any entity that is added to Home Assistant and has a unique ID will be registered in the registry.
Being registered has the advantage that the same entity will always get the same entity ID. It will also prevent other entities from using that entity ID.
A user is also able to override the name of an entity in the entity registry. When set, the name of the entity registry is used in favor of the name the device might give itself.
## Unique ID requirements
An entity is looked up in the registry based on a combination of the plaform type (e.g., `light`), and the integraion name (domain) (ie hue) and the unique ID of the entity. It is therefore very important that the unique ID is unique! It is also important that it is not possible for the user to change the unique ID, because that means it will lose all its settings related to it.
Good sources for a unique ID:
- Serial number of a device
- MAC address of a device
- latitude/longitude
If a device has a single serial but provides multiple entities, combine the serial with unique identifiers for the entities. For example, if a device measures both temperature and humidity, you can uniquely identify the entities using `{serial}-{sensor_type}`.

View File

@ -0,0 +1,235 @@
---
title: "푸시 알림"
---
`mobile_app` 컴포넌트는 별도의 외부 컴포넌트를 설치하지 않고도 푸시 알림을 사용자에게 보낼 수 있는 알림 플랫폼이 내장되어 있습니다.
## 푸시 알림 활성화시키기
애플리케이션에서 알림 플랫폼을 활성화하려면, 최초 등록 또는 기존 등록을 업데이트하는 동안 `app_data` 객체에 두 개의 키를 설정해야 합니다.
| 키 | 구분 | 설명 |
| ------------ | ------ | -------------------------------------------------------------- |
| `push_token` | string | 사용자 기기의 고유한 푸시 알림 토큰 예를 들어 APNS 토큰이나 FCM 인스턴스 ID/토큰이 될 수 있습니다. |
| `push_url` | string | 푸시 알림이 HTTP POSTed 될 서버의 URL 주소. |
이러한 키를 설정 한 후에는 알림 대상을 인식 할 수 있도록 Home Assistant 를 다시 시작하도록 사용자에게 알려주어야 합니다. 형식은 `notify.mobile_app_<safed_device_name>` 입니다.
## 서버 컴포넌트 배치하기
알림 플랫폼은 사용자에게 알리는 방법을 가리지 않습니다. 단순히 실제 요청을 처리하는 외부 서버로 알림을 전달할 뿐입니다. 이러한 접근방식은 푸시 알림 인프라를 완전하게 제어할 수 있도록 해줍니다.
Firebase Cloud Functions 와 Firebase Cloud Messaging 을 사용하는 푸시 알림 전달자의 서버 구현 예제는 이 문서의 다음 섹션을 참조해주세요.
서버는 다음과 같이 HTTP POST 페이로드를 받을수 있어야 합니다.
```json
{
"message": "Hello World",
"title": "Test message sent via mobile_app.notify",
"push_token": "my-secure-token",
"registration_info": {
"app_id": "io.home-assistant.iOS",
"app_version": "1.0.0",
"os_version": "12.2"
},
"data": {
"key": "value"
}
}
```
알림이 성공적으로 전달 대기중인 것으로 가정 할 경우 201 상태 코드로 응답해야 합니다.
### 오류 관련 사항들
만약 오류가 발생하면 상태 코드 201 또는 429 *이외의* 오류에 대한 설명을 반환해야합니다. 오류 응답은 JSON 객체여야하며 다음 키 중 하나를 포함 할 수 있습니다:
| 키 | 구분 | 설명 |
| -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `errorMessage` | string | 제공된 경우 미리 설정된 오류 메시지에 추가됩니다. 예를 들어, `errorMessage`가 "Apple 과 통신할 수 없습니다" 라면, "내부 서버 오류입니다. 나중에 다시 시도해주세요: Apple 과 통신할 수 없습니다"라는 로그가 출력됩니다. |
| `message` | string | If provided, it will be output directly to the logs at the warning log level. |
No matter what key you use, you should try to be as descriptive as possible about what went wrong and, if possible, how the user can fix it.
### Rate limits
The notify platform also supports exposing rate limits to users. Home Assistant suggests you implement a conservative rate limit to keep your costs low and also so that users don't overload themselves with too many notifications. For reference, Home Assistant Companion has a maximum sendable notifications per 24 hours of 150 notifications. The rate limit resets for all users at midnight, UTC. You of course are free to use whatever configuration for your own rate limiting.
If you choose to implement rate limiting, your successful server response should look like the following:
```json
{
"rateLimits": {
"successful": 1,
"errors": 5,
"maximum": 150,
"resetsAt": "2019-04-08T00:00:00.000Z"
}
}
```
| 키 | 구분 | 설명 |
| ------------ | ----------------- | ------------------------------------------------------------------------------------------------ |
| `successful` | integer | The number of successful push notifications the user has sent during the rate limit period. |
| `errors` | integer | The number of failed push notifications the user has sent during the rate limit period. |
| `maximum` | integer | The maximum number of push notifications the user can send during the users rate limit period. |
| `resetsAt` | ISO8601 timestamp | The timestamp that the users rate limit period expires at. Must be provided in the UTC timezone. |
The rate limits will be output to the log at the warning log level after every notification is successfully sent. Home Assistant will also output the exact time remaining until the rate limit period resets.
Once the user hits their maximum amount of notifications sent in the rate limit period, you should start responding with a 429 status code until the rate limit period expires. The response object can optionally contain a key, `message` which will be output to the Home Assistant log instead of the standard error message.
The notify platform does not itself implement any kind of rate limit protections. Users will be able to keep sending you notifications, so you should reject them with a 429 status code as early in your logic as possible.
## Example server implementation
The below code is a Firebase Cloud Function that forwards notifications to Firebase Cloud Messaging. To deploy this, you should create a new Firestore database named `rateLimits`. Then, you can deploy the following code. Also, ensure that you have properly configured your project with the correct authentication keys for APNS and FCM.
```javascript
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
var db = admin.firestore();
const MAX_NOTIFICATIONS_PER_DAY = 150;
exports.sendPushNotification = functions.https.onRequest(async (req, res) => {
console.log('Received payload', req.body);
var today = getToday();
var token = req.body.push_token;
var ref = db.collection('rateLimits').doc(today).collection('tokens').doc(token);
var payload = {
notification: {
body: req.body.message,
},
token: token,
};
if(req.body.title) {
payload.notification.title = req.body.title;
}
if(req.body.data) {
if(req.body.data.android) {
payload.android = req.body.data.android;
}
if(req.body.data.apns) {
payload.apns = req.body.data.apns;
}
if(req.body.data.data) {
payload.data = req.body.data.data;
}
if(req.body.data.webpush) {
payload.webpush = req.body.data.webpush;
}
}
console.log('Notification payload', JSON.stringify(payload));
var docExists = false;
var docData = {
deliveredCount: 0,
errorCount: 0,
totalCount: 0,
};
try {
let currentDoc = await ref.get();
docExists = currentDoc.exists;
if(currentDoc.exists) {
docData = currentDoc.data();
}
} catch(err) {
console.error('Error getting document!', err);
return handleError(res, 'getDoc', err);
}
if(docData.deliveredCount > MAX_NOTIFICATIONS_PER_DAY) {
return res.status(429).send({
errorType: 'RateLimited',
message: 'The given target has reached the maximum number of notifications allowed per day. Please try again later.',
target: token,
rateLimits: getRateLimitsObject(docData),
});
}
docData.totalCount = docData.totalCount + 1;
var messageId;
try {
messageId = await admin.messaging().send(payload);
docData.deliveredCount = docData.deliveredCount + 1;
} catch(err) {
docData.errorCount = docData.errorCount + 1;
await setRateLimitDoc(ref, docExists, docData, res);
return handleError(res, 'sendNotification', err);
}
console.log('Successfully sent message:', messageId);
await setRateLimitDoc(ref, docExists, docData, res);
return res.status(201).send({
messageId: messageId,
sentPayload: payload,
target: token,
rateLimits: getRateLimitsObject(docData),
});
});
async function setRateLimitDoc(ref, docExists, docData, res) {
try {
if(docExists) {
console.log('Updating existing doc!');
await ref.update(docData);
} else {
console.log('Creating new doc!');
await ref.set(docData);
}
} catch(err) {
if(docExists) {
console.error('Error updating document!', err);
} else {
console.error('Error creating document!', err);
}
return handleError(res, 'setDocument', err);
}
return true;
}
function handleError(res, step, incomingError) {
if (!incomingError) return null;
console.error('InternalError during', step, incomingError);
return res.status(500).send({
errorType: 'InternalError',
errorStep: step,
message: incomingError.message,
});
}
function getToday() {
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0');
var yyyy = today.getFullYear();
return yyyy + mm + dd;
}
function getRateLimitsObject(doc) {
var d = new Date();
return {
successful: (doc.deliveredCount || 0),
errors: (doc.errorCount || 0),
total: (doc.totalCount || 0),
maximum: MAX_NOTIFICATIONS_PER_DAY,
remaining: (MAX_NOTIFICATIONS_PER_DAY - doc.deliveredCount),
resetsAt: new Date(d.getFullYear(), d.getMonth(), d.getDate()+1)
};
}
```

View File

@ -0,0 +1,11 @@
---
title: "Native App Integration"
sidebar_label: "Introduction"
---
This guide describes how to build a native Home Assistant app that communicates with Home Assistant and offers a seamless integration. Below is a list of the things that we will discuss in this guide.
- Allow the user to establish a connection and authenticate with their own Home Assistant instance.
- Send location and device info back to Home Assistant.
- Call services, fire events and render templates.
- A view to control the house via an authenticated webview.

View File

@ -0,0 +1,235 @@
---
title: "Push Notifications"
---
The `mobile_app` component has a notify platform built in that allows for a generic way to send push notifications to your users without requiring installation of a external custom component.
## Enabling push notifications
To enable the notify platform for your application, you must set two keys in the `app_data` object during the initial registration or later update of an existing registration.
| Key | Type | Description |
| ------------ | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| `push_token` | string | A push notification token unique to your users device. For example, this could be a APNS token or a FCM Instance ID/token. |
| `push_url` | string | The URL on your server that push notifications will be HTTP POSTed to. |
You should advise the user to restart Home Assistant after you set these keys in order for them to see the notify target. It will have the format `notify.mobile_app_<safed_device_name>`.
## Deploying a server component
The notify platform doesn't concern itself with how to notify your users. It simply forwards a notification to your external server where you should actually handle the request. This approach allows you to maintain full control over your push notification infrastructure.
See the next section of this document for an example server implementation of a push notification forwarder that uses Firebase Cloud Functions and Firebase Cloud Messaging.
Your server should accept a HTTP POST payload like this:
```json
{
"message": "Hello World",
"title": "Test message sent via mobile_app.notify",
"push_token": "my-secure-token",
"registration_info": {
"app_id": "io.home-assistant.iOS",
"app_version": "1.0.0",
"os_version": "12.2"
},
"data": {
"key": "value"
}
}
```
It should respond with a 201 status code assuming the notification was queued for delivery successfully.
### Errors
If an error occurs you should return a description of what went wrong with a status code *other than* 201 or 429. An error response must be a JSON object and can contain one of the following keys:
| Key | Type | Description |
| -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `errorMessage` | string | If provided, it will be appended to a preset error message. For example, if `errorMessage` is "Could not communicate with Apple" it will be output in the log like "Internal server error, please try again later: Could not communicate with Apple" |
| `message` | string | If provided, it will be output directly to the logs at the warning log level. |
No matter what key you use, you should try to be as descriptive as possible about what went wrong and, if possible, how the user can fix it.
### Rate limits
The notify platform also supports exposing rate limits to users. Home Assistant suggests you implement a conservative rate limit to keep your costs low and also so that users don't overload themselves with too many notifications. For reference, Home Assistant Companion has a maximum sendable notifications per 24 hours of 150 notifications. The rate limit resets for all users at midnight, UTC. You of course are free to use whatever configuration for your own rate limiting.
If you choose to implement rate limiting, your successful server response should look like the following:
```json
{
"rateLimits": {
"successful": 1,
"errors": 5,
"maximum": 150,
"resetsAt": "2019-04-08T00:00:00.000Z"
}
}
```
| Key | Type | Description |
| ------------ | ----------------- | ------------------------------------------------------------------------------------------------ |
| `successful` | integer | The number of successful push notifications the user has sent during the rate limit period. |
| `errors` | integer | The number of failed push notifications the user has sent during the rate limit period. |
| `maximum` | integer | The maximum number of push notifications the user can send during the users rate limit period. |
| `resetsAt` | ISO8601 timestamp | The timestamp that the users rate limit period expires at. Must be provided in the UTC timezone. |
The rate limits will be output to the log at the warning log level after every notification is successfully sent. Home Assistant will also output the exact time remaining until the rate limit period resets.
Once the user hits their maximum amount of notifications sent in the rate limit period, you should start responding with a 429 status code until the rate limit period expires. The response object can optionally contain a key, `message` which will be output to the Home Assistant log instead of the standard error message.
The notify platform does not itself implement any kind of rate limit protections. Users will be able to keep sending you notifications, so you should reject them with a 429 status code as early in your logic as possible.
## Example server implementation
The below code is a Firebase Cloud Function that forwards notifications to Firebase Cloud Messaging. To deploy this, you should create a new Firestore database named `rateLimits`. Then, you can deploy the following code. Also, ensure that you have properly configured your project with the correct authentication keys for APNS and FCM.
```javascript
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
var db = admin.firestore();
const MAX_NOTIFICATIONS_PER_DAY = 150;
exports.sendPushNotification = functions.https.onRequest(async (req, res) => {
console.log('Received payload', req.body);
var today = getToday();
var token = req.body.push_token;
var ref = db.collection('rateLimits').doc(today).collection('tokens').doc(token);
var payload = {
notification: {
body: req.body.message,
},
token: token,
};
if(req.body.title) {
payload.notification.title = req.body.title;
}
if(req.body.data) {
if(req.body.data.android) {
payload.android = req.body.data.android;
}
if(req.body.data.apns) {
payload.apns = req.body.data.apns;
}
if(req.body.data.data) {
payload.data = req.body.data.data;
}
if(req.body.data.webpush) {
payload.webpush = req.body.data.webpush;
}
}
console.log('Notification payload', JSON.stringify(payload));
var docExists = false;
var docData = {
deliveredCount: 0,
errorCount: 0,
totalCount: 0,
};
try {
let currentDoc = await ref.get();
docExists = currentDoc.exists;
if(currentDoc.exists) {
docData = currentDoc.data();
}
} catch(err) {
console.error('Error getting document!', err);
return handleError(res, 'getDoc', err);
}
if(docData.deliveredCount > MAX_NOTIFICATIONS_PER_DAY) {
return res.status(429).send({
errorType: 'RateLimited',
message: 'The given target has reached the maximum number of notifications allowed per day. Please try again later.',
target: token,
rateLimits: getRateLimitsObject(docData),
});
}
docData.totalCount = docData.totalCount + 1;
var messageId;
try {
messageId = await admin.messaging().send(payload);
docData.deliveredCount = docData.deliveredCount + 1;
} catch(err) {
docData.errorCount = docData.errorCount + 1;
await setRateLimitDoc(ref, docExists, docData, res);
return handleError(res, 'sendNotification', err);
}
console.log('Successfully sent message:', messageId);
await setRateLimitDoc(ref, docExists, docData, res);
return res.status(201).send({
messageId: messageId,
sentPayload: payload,
target: token,
rateLimits: getRateLimitsObject(docData),
});
});
async function setRateLimitDoc(ref, docExists, docData, res) {
try {
if(docExists) {
console.log('Updating existing doc!');
await ref.update(docData);
} else {
console.log('Creating new doc!');
await ref.set(docData);
}
} catch(err) {
if(docExists) {
console.error('Error updating document!', err);
} else {
console.error('Error creating document!', err);
}
return handleError(res, 'setDocument', err);
}
return true;
}
function handleError(res, step, incomingError) {
if (!incomingError) return null;
console.error('InternalError during', step, incomingError);
return res.status(500).send({
errorType: 'InternalError',
errorStep: step,
message: incomingError.message,
});
}
function getToday() {
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0');
var yyyy = today.getFullYear();
return yyyy + mm + dd;
}
function getRateLimitsObject(doc) {
var d = new Date();
return {
successful: (doc.deliveredCount || 0),
errors: (doc.errorCount || 0),
total: (doc.totalCount || 0),
maximum: MAX_NOTIFICATIONS_PER_DAY,
remaining: (MAX_NOTIFICATIONS_PER_DAY - doc.deliveredCount),
resetsAt: new Date(d.getFullYear(), d.getMonth(), d.getDate()+1)
};
}
```

View File

@ -0,0 +1,228 @@
---
title: "Sending data home"
---
Once you have registered your app with the mobile app component, you can start interacting with Home Assistant via the provided webhook information.
The first step is to turn the returned webhook ID into a full URL: `<instance_url>/api/webhook/<webhook_id>`. This will be the only url that we will need for all our interactions. The webhook endpoint will not require authenticated requests.
If you were provided a Cloudhook URL during registration, you should use that by default and only fall back to a constructed URL as described above if that request fails.
If you were provided a remote UI URL during registration, you should use that as the `instance_url` when constructing a URL and only fallback to the user provided URL if the remote UI URL fails.
To summarize, here's how requests should be made:
1. If you have a Cloudhook URL, use that until a request fails. When a request fails, go to step 2.
2. If you have a remote UI URL, use that to construct a webhook URL: `<remote_ui_url>/api/webhook/<webhook_id>`. When a request fails, go to step 3.
3. Construct a webhook URL using the instance URL provided during setup: `<instance_url>/api/webhook/<webhook_id>`.
## Short note on instance URLs
Some users have configured Home Assistant to be available outside of their home network using a dynamic DNS service. There are some routers that don't support hairpinning / NAT loopback: a device sending data from inside the routers network, via the externally configured DNS service, to Home Asisstant, which also resides inside the local network.
To work around this, the app should record which WiFi SSID is the users home network, and use a direct connection when connected to the home WiFi network.
## Interaction basics
### Request
All interaction will be done by making HTTP POST requests to the webhook url. These requests do not need to contain authentication.
The payload format depends on the type of interaction, but it all shares a common base:
```json5
{
"type": "<type of message>",
"data": {}
}
```
If you received a `secret` during registration, you **MUST** encrypt your message and put it in the payload like this:
```json5
{
"type": "encrypted",
"encrypted": true,
"encrypted_data": "<encrypted message>"
}
```
### Response
As a general rule, expect to receive a 200 response for all your requests. There are a few cases in which you will receive another code:
- You will receive a 400 status code if your JSON is invalid. However, you will not receive this error if the encrypted JSON is invalid.
- You will receive a 201 when creating a sensor
- If you receive a 404, the `mobile_app` component most likely isn't loaded.
- Receiving a 410 means the integration has been deleted. You should notify the user and most likely register again.
## Implementing encryption
`mobile_app` supports two way encrypted communication via [Sodium](https://libsodium.gitbook.io/doc/).
> Sodium is a modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more.
### Choosing a library
Libraries that wrap Sodium exist for most modern programming languages and platforms. Sodium itself is written in C.
Here are the libraries we suggest using, although you should feel free to use whatever works well for you.
- Swift/Objective-C: [swift-sodium](https://github.com/jedisct1/swift-sodium) (official library maintained by Sodium developers.
For other languages, please see the list of [Bindings for other languages](https://download.libsodium.org/doc/bindings_for_other_languages). If more than one choice is available, we recommend using the choice most recently updated.
### Configuration
We use the [secret-key cryptography](https://download.libsodium.org/doc/secret-key_cryptography) features of Sodium to encrypt and decrypt payloads. All payloads are JSON encoded in Base64. For Base64 type, use `sodium_base64_VARIANT_ORIGINAL` (that is, "original", no padding, not URL safe).
### Signaling encryption support
During registration, you must set `supports_encryption` to `true` to enable encryption. The Home Assistant instance must be able to install `libsodium` to enable encryption. Confirm that you should make all future webhook requests encrypted by the presence of the key `secret` in the initial registration response. You must store this secret forever. There is no way to recover it via the Home Assistant UI and you should **not** ask users to investigate hidden storage files to re-enter the encryption key. You should create a new registration if encryption ever fails and alert the user.
## Update device location
This message will inform Home Assistant of new location information.
```json
{
"type": "update_location",
"data": {
"gps": [12.34, 56.78],
"gps_accuracy": 120,
"battery": 45
}
}
```
| Key | Type | Description |
| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |
| `location_name` | string | Name of the zone the device is in. |
| `gps` | latlong | Current location as latitude and longitude. |
| `gps_accuracy` | int | GPS accurracy in meters. Must be greater than 0. |
| `battery` | int | Percentage of battery the device has left. Must be greater than 0. |
| `speed` | int | Speed of the device in meters per second. Must be greater than 0. |
| `altitude` | int | Altitude of the device in meters. Must be greater than 0. |
| `course` | int | The direction in which the device is traveling, measured in degrees and relative to due north. Must be greater than 0. |
| `vertical_accuracy` | int | The accuracy of the altitude value, measured in meters. Must be greater than 0. |
## Call a service
Call a service in Home Assistant.
```json
{
"type": "call_service",
"data": {
"domain": "light",
"service": "turn_on",
"service_data": {
"entity_id": "light.kitchen"
}
}
}
```
| Key | Type | Description |
| -------------- | ------ | ------------------------------- |
| `domain` | string | The domain of the service |
| `service` | string | The service name |
| `service_data` | dict | The data to send to the service |
## Fire an event
Fire an event in Home Assistant.
```json
{
"type": "fire_event",
"data": {
"event_type": "my_custom_event",
"event_data": {
"something": 50
}
}
}
```
| Key | Type | Description |
| ------------ | ------ | ------------------------- |
| `event_type` | string | Type of the event to fire |
| `event_data` | string | Date of the event to fire |
## Render templates
Renders one or more templates and returns the result(s).
```json
{
"type": "render_template",
"data": {
"my_tpl": {
"template": "Hello {{ name }}, you are {{ states('person.paulus') }}.",
"variables": {
"name": "Paulus"
}
}
}
}
```
`data` must contain a map of `key`: `dictionary`. Results will be returned like `{"my_tpl": "Hello Paulus, you are home"}`. This allows for rendering multiple templates in a single call.
| Key | Type | Description |
| ----------- | ------ | ---------------------------------------- |
| `template` | string | The template to render |
| `variables` | Dict | The extra template variables to include. |
## Update registration
Update your app registration. Use this if the app version changed or any of the other values.
```json
{
"type": "update_registration",
"data": {
"app_data": {
"push_token": "abcd",
"push_url": "https://push.mycool.app/push"
},
"app_version": "2.0.0",
"device_name": "Robbies iPhone",
"manufacturer": "Apple, Inc.",
"model": "iPhone XR",
"os_version": "23.02"
}
}
```
All keys are optional.
| Key | Type | Description |
| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `app_data` | Dict | App data can be used if the app has a supporting component that extends mobile_app functionality or wishes to enable the notification platform. |
| `app_version` | string | Version of the mobile app. |
| `device_name` | string | Name of the device running the app. |
| `manufacturer` | string | The manufacturer of the device running the app. |
| `model` | string | The model of the device running the app. |
| `os_version` | string | The OS version of the device running the app. |
## Get zones
Get all enabled zones.
```json
{
"type": "get_zones"
}
```
## Get config
Returns a version of `/api/config` with values useful for configuring your app.
```json
{
"type": "get_config"
}
```

View File

@ -0,0 +1,77 @@
---
title: "Sensors"
---
The `mobile_app` component supports exposing custom sensors that can be managed entirely via your app.
## Registering a sensor
All sensors must be registered before they can get updated. You can only register one sensor at a time, unlike updating sensors.
To register a sensor, make a request to the webhook like this:
```json
{
"data": {
"attributes": {
"foo": "bar"
},
"device_class": "battery",
"icon": "mdi:battery",
"name": "Battery State",
"state": "12345",
"type": "sensor",
"unique_id": "battery_state",
"unit_of_measurement": "%"
},
"type": "register_sensor"
}
```
The valid keys are:
| Key | Type | Required | Description |
| --------------------- | ----------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| attributes | object | No | Attributes to attach to the sensor |
| device_class | string | No | One of the valid device classes. [Binary Sensor Classes](https://www.home-assistant.io/components/binary_sensor/#device-class), [Sensor Classes](https://www.home-assistant.io/components/sensor/#device-class) |
| icon | Material Design Icon (string) | No | Must be prefixed `mdi:`. If not provided, default value is `mdi:cellphone` |
| name | string | Yes | The name of the sensor |
| state | bool, float, int, string | Yes | The state of the sensor |
| type | string | Yes | The type of the sensor. Must be one of `binary_sensor` or `sensor` |
| unique_id | string | Yes | A identifier unique to this installation of your app. You'll need this later. Usually best when its a safe version of the sensor name |
| unit_of_measurement | string | No | The unit of measurement for the sensor |
Sensors will appear as soon as they are registered.
## Updating a sensor
Once a sensor has been registered, you need to update it. This is very similar to registering it, but you can update all your sensors at the same time.
For example, to update the sensor we registered above, you would send this:
```json
{
"data": [
{
"attributes": {
"hello": "world"
},
"icon": "mdi:battery",
"state": 123,
"type": "sensor",
"unique_id": "battery_state"
}
],
"type": "update_sensor_states"
}
```
Only some of the keys are allowed during updates:
| Key | Type | Required | Description |
| ---------- | ----------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| attributes | object | No | Attributes to attach to the sensor |
| icon | Material Design Icon (string) | No | Must be prefixed `mdi:` |
| state | bool, float, int, string | Yes | The state of the sensor |
| type | string | Yes | The type of the sensor. Must be one of `binary_sensor` or `sensor` |
| unique_id | string | Yes | A identifier unique to this installation of your app. You'll need this later. Usually best when its a safe version of the sensor name |

View File

@ -0,0 +1,80 @@
---
title: "Connecting to an instance"
---
When a user first opens the app, they will need to connect to their local instance to authenticate and register the device.
## Authenticating the user
The local instance can be discovered if Home Assistant has the [zeroconf component](https://www.home-assistant.io/components/zeroconf) configured by searching for `_home-assistant._tcp.local.`. If not configured, the user will need to be asked for the local address of their instance.
When the address of the instance is known, the app will ask the user to authenticate via [OAuth2 with Home Assistant](auth_api.md). Home Assistant uses IndieAuth, which means that to be able to redirect to a url that triggers your app, you need to take some extra steps. Make sure to read the last paragraph of the "Clients" section thoroughly.
## Registering the device
*This requires Home Assistant 0.90 or later.*
Home Assistant has a `mobile_app` component that allows applications to register themselves and interact with the instance. This is a generic component to handle most common mobile application tasks. This component is extendable with custom interactions if your app needs more types of interactions than are offered by this component.
Once you have tokens to authenticate as a user, it's time to register the app with the mobile app component in Home Assistant.
### Getting Ready
First, you must ensure that the `mobile_app` component is loaded. There are two ways to do this:
- You can publish a Zeroconf/Bonjour record `_hass-mobile-app._tcp.local.` to trigger the automatic load of the `mobile_app` component. You should wait at least 60 seconds after publishing the record before continuing.
- You can ask the user to add `mobile_app` to their configuration.yaml and restart Home Assistant. If the user already has `default_config` in their configuration, then `mobile_app` will have been already loaded.
You can confirm the `mobile_app` component has been loaded by checking the `components` array of the [`/api/config` REST API call](external_api_rest.md#get-api-config). If you continue to device registration and receive a 404 status code, then it most likely hasn't been loaded yet.
### Registering the device
To register the device, make an authenticated POST request to `/api/mobile_app/registrations`. [More info on making authenticated requests.](auth_api.md#making-authenticated-requests)
Example payload to send to the registration endpoint:
```json
{
"app_id": "awesome_home",
"app_name": "Awesome Home",
"app_version": "1.2.0",
"device_name": "Robbies iPhone",
"manufacturer": "Apple, Inc.",
"model": "iPhone X",
"os_version": "iOS 10.12",
"supports_encryption": true,
"app_data": {
"push_notification_key": "abcdef",
}
}
```
| Key | Required | Type | Description |
| --------------------- | -------- | ------ | --------------------------------------------------------------------------------------------------- |
| `app_id` | V | string | A unique identifier for this app. |
| `app_name` | V | string | Name of the mobile app. |
| `app_version` | V | string | Version of the mobile app. |
| `device_name` | V | string | Name of the device running the app. |
| `manufacturer` | V | string | The manufacturer of the device running the app. |
| `model` | V | string | The model of the device running the app. |
| `os_version` | V | string | The OS version of the device running the app. |
| `supports_encryption` | V | bool | If the app supports encryption. See also the [encryption section](#encryption). |
| `app_data` | | Dict | App data can be used if the app has a supporting component that extends `mobile_app` functionality. |
When you get a 200 response, the mobile app is registered with Home Assistant. The response is a JSON document and will contain the URLs on how to interact with the Home Assistant instance. You should permanently store this information.
```json
{
"cloudhook_url": "https://hooks.nabu.casa/randomlongstring123",
"remote_ui_url": "https://randomlongstring123.ui.nabu.casa",
"secret": "qwerty",
"webhook_id": "abcdefgh"
}
```
| Key | Type | Description |
| --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cloudhook_url` | string | The cloudhook URL provided by Home Assistant Cloud. Only will be provided if user is actively subscribed to Nabu Casa. |
| `remote_ui_url` | string | The remote UI URL provided by Home Assistant Cloud. Only will be provided if user is actively subscribed to Nabu Casa. |
| `secret` | string | The secret to use for encrypted communication. Will only be included if encryption is supported by both the app and the Home Assistant instance. [More info](app_integration_sending_data.md#implementing-encryption). |
| `webhook_id` | string | The webhook ID that can be used to send data back. |

View File

@ -0,0 +1,9 @@
---
title: "Authenticated Webview"
---
Your application already asked the user to authenticate. This means that your app should not ask the user to authenticate again when they open the Home Assistant UI.
To make this possible, the Home Assistant UI supports [external authentication](frontend_external_auth). This allows your app to provide hooks so that the frontend will ask your app for access tokens.
Note that this feature requires a direct connection to the instance.

View File

@ -0,0 +1,50 @@
---
title: "Components Architecture"
sidebar_label: "Components"
---
Home Assistant can be extended with **components**. Each component is responsible for a specific domain within Home Assistant. Components can listen for or trigger events, offer services, and maintain states. Components are written in Python and can do all the goodness that Python has to offer. Out of the box, Home Assistant offers a bunch of [built-in components](https://www.home-assistant.io/components/).
<img src='/img/en/architecture/component_interaction.png' alt='Diagram showing interaction between components and the Home Assistant core.' />
There are two types of components within Home Assistant: components that interact with an Internet of Things domain, and components that respond to events that happen within Home Assistant. Read on to learn about each type!
## Components that interact with an Internet-of-Things domain
These components track devices within a specific domain and consist of a core part and platform-specific logic. These components make their information available via the State Machine and the Event Bus. The components also register services in the Service Registry to expose control of the devices.
For example, the built-in [`switch` component](https://www.home-assistant.io/components/switch/) is responsible for interaction with different types of switches. A platform provides support for a particular kind or brand of device. For example, a switch could use a WeMo or Orvibo platform and a light component might interact with the Hue or LIFX platform.
If you want to add support for a new platform, check out the [add new platform section](creating_platform_index.md).
## Components that respond to events that happen within Home Assistant
These components provide small pieces of home automation logic or involve services that do common tasks within your house.
For example, the [`device_sun_light_trigger` component](https://www.home-assistant.io/components/device_sun_light_trigger/) tracks the state of devices and the sun to make sure that the lights are turned on when it gets dark and people are home. The component uses logic like this:
```text
In the event that device 'Paulus Nexus 5' changes to the 'Home' state:
If the sun has set and the lights are not on:
Turn on the lights
```
```text
In the event that the combined state of all tracked devices changes to 'Not Home':
If the lights are on:
Turn off the lights
```
```text
In the event of the sun setting:
If the lights are off and the combined state of all tracked device equals 'Home':
Turn on the lights
```
## The full picture
When we put all the different pieces of Home Assistant together, it's a close match for the initial home automation overview sketch. The smart home AI has not been implemented yet, so it's not included in this picture.
![Overview of the full Home Assistant architecture with a couple of loaded components and platforms](/img/en/architecture/ha_full_architecture.png)
The platform logic for components uses third-party Python libraries to communicate with the devices. Through this, we can leverage some of the best libraries in the Python community.

View File

@ -0,0 +1,41 @@
---
title: "Entity Architecture"
sidebar_label: Entity
---
![Architecture overview of Hass.io](/img/en/architecture/entities_architecture.png)
## Configuration
Configuration is provided by the [configuration.yaml file](configuration_yaml_index.md) or by a [Config Entry](config_entries_index.md).
## Component
Examples of components: `light`, `switch`.
The component is responsible for defining the Abstract Entity Class and services to control the entities.
## Entity Component
The Entity Component is responsible for:
- Distributing the configuration to the platforms
- Forward config entries and discoveries
- Collect entities for service calls
- Optionally maintain a group of all entities
## Entity Platform
The Entity Platform manages all entities for the platform and polls them for updates if necessary.
When adding entities, the Entity Platform will query the Entity Registry to make sure that the entities to be added have the correct entity IDs.
## Entity Registry
The [Entity Registry](entity_registry_index.md) will track entities and allows users to store extra settings for an entity.
## Platform
Examples of platforms: `light.hue`, `switch.wemo`.
Platform uses configuration to query the external device/service and add entities to the entity platform.

View File

@ -0,0 +1,26 @@
---
title: "Hass.io Architecture"
sidebar_label: Hass.io
---
![Architecture overview of Hass.io](/img/en/architecture/hassio.png)
## Host Control (HC)
This is a daemon running on the host machine that allows the supervisor to control certain aspects of the host OS:
- Power cycle (restart, turn off)
- Manage network settings
- Local updates
## Host
Our pre-build images are based on [HassOS](https://github.com/home-assistant/hassos) which is based on [BuildRoot](https://buildroot.org/). Any Linux machine can be turned into a Hass.io host by running [the installer](https://www.home-assistant.io/hassio/installation/#alternative-install-on-generic-linux-server).
## Supervisor
The supervisor offers an API to manage the host and running the Docker containers.
## Configuration panel
The configuration panel lives inside the supervisor but is accessible via the Home Assistant user interface. The configuration panel allows the user to manage the installation.

View File

@ -0,0 +1,23 @@
---
title: "Architecture"
sidebar_label: "Introduction"
---
Before we dive into the Home Assistant architecture, let's get a clear overview of the home automation landscape as a whole. This way, we can show how the different parts of Home Assistant fit into the picture.
For more information about each part in this overview, [check out our blog](https://www.home-assistant.io/blog/2014/12/26/home-control-home-automation-and-the-smart-home/). Here's the tl;dr version of the blog:
- Home Control is responsible for collecting information and controlling devices.
- Home Automation triggers commands based on user configurations.
- Smart Home triggers commands based on previous behavior.
![Home Automation landscape](/img/en/architecture/home_automation_landscape.svg)
The Home Assistant core is responsible for Home Control. Home Assistant contains four parts which make this possible:
- **Event Bus**: facilitates the firing and listening of events -- the beating heart of Home Assistant.
- **State Machine**: keeps track of the states of things and fires a `state_changed` event when a state has been changed.
- **Service Registry**: listens on the event bus for `call_service` events and allows other code to register services.
- **Timer**: sends a `time_changed` event every 1 second on the event bus.
![Overview of the Home Assistant core architecture](/img/en/architecture/ha_architecture.svg)

View File

@ -0,0 +1,11 @@
---
title: Area Registry
sidebar_label: Introduction
---
The area registry is a registry where Home Assistant keeps track of areas. An area represents a physical location for Home Assistant. It can be used to place devices in different areas.
| Attribute | Description |
| --------- | ----------------------------------------------- |
| id | Unique ID of area (generated by Home Assistant) |
| name | Name of this area |

View File

@ -0,0 +1,9 @@
---
title: "Asyncio 101"
---
If you are not familiar yet with asyncio, please watch the below video. It's a great introduction by [Robert Smallshire](https://github.com/rob-smallshire) in how and why asyncio works the way it does.
<div class='videoWrapper'>
<iframe width="560" height="315" src="https://www.youtube.com/embed/M-UcUs7IMIM" frameborder="0" allowfullscreen mark="crwd-mark"></iframe>
</div>

View File

@ -0,0 +1,67 @@
---
title: "Categorizing Functions"
---
A piece of work within Home Assistant is represented by a function that will be invoked. It will either run inside our event loop or inside our thread pool, depending on if it is async safe.
Home Assistant uses the convention that all functions that must be run from within the event loop are prefixed with `async_`.
## The coroutine function
Coroutines are special functions based on Pythons generators syntax which allows them to suspend execution while waiting on a result.
Invoking a coroutine function will return a Generator object back, but will not actually begin execution. This object will execute the task when it is either yielded from (from within another coroutine) or it is scheduled on the event loop.
To declare a function a coroutine, import the coroutine annotation from the asyncio package and annotate your function.
```python
async def async_look_my_coroutine(target):
result = await entity.async_turn_on()
if result:
print("hello {}".format(target))
hass.loop.create_task(async_look_my_coroutine("world"))
```
In this example, we schedule the coroutine by calling `hass.loop.create_task`. This will add the coroutine to the queue of tasks to be run. When the event loop is running `async_look_my_coroutine` it will suspend the task when `await entity.async_turn_on()` is called. At that point a new task will be scheduled to execute `entity.async_turn_on()`. When that job has been executed, `async_look_my_coroutine` will resume.
## The callback function
This is a normal function that is considered safe to be run from within the event loop. A callback is unable to suspend itself and thus cannot do any I/O or call a coroutine. A callback is capable of scheduling a new task but it will not be able to wait for the results.
To declare a function as a callback, import the callback annotation from the core package and annotate your function.
A common use case for a callback in Home Assistant is as a listener for an event or a service call. It can process the incoming information and then schedule the right calls to be made. Example from the automation component.
```python
from homeassistant.core import callback
@callback
def async_trigger_service_handler(service_call):
"""Handle automation trigger service calls."""
vars = service_call.data.get(ATTR_VARIABLES)
for entity in component.async_extract_from_service(service_call):
hass.loop.create_task(entity.async_trigger(vars, True))
```
In this example, `entity.async_trigger` is a coroutine function. Invoking the coroutine function will return a coroutine task. The passed in parameters will be used when the task gets executed.
To execute the task we have to schedule it for execution on the event loop. This is done by calling `hass.loop.create_task`.
### Why even have callbacks?
You might wonder, if a coroutine can do everything a callback can do, why even have a callback. The reason is performance and better state consistency of the core API objects.
When coroutine A waits for coroutine B, it will suspend itself and schedule a new task to run B. This means that the event loop is now running A, B and then A again. If B is a callback, A will never have to suspend itself and thus the event loop is just running A. The consistency implication is that other events queued to run on the event loop continue to wait until callbacks complete, but will be interleaved when yielding to another coroutine.
## Event loop and thread safe
These are functions that are safe to run both in a thread and inside the event loop. These functions are usually performing a computation or transform data in memory. Anything that does I/O does not fall under this category. Many standard library functions fall in this category. For example generating the sum of a set of numbers using sum or merging two dictionaries.
There is no special annotation to mark functions as part of this category and care should be taken when using these functions from inside the event loop. When in doubt, look at their implementation.
## Other functions
These are all the functions that did not fit in the previous categories. These functions are either thread-safe or not considered safe to be run within the event loop. These are functions that use sleep, or perform I/O.
There is no special annotation necessary to be considered part of this category.

View File

@ -0,0 +1,16 @@
---
title: "Asynchronous Programming"
sidebar_label: Introduction
---
On September 29, 2016 we released [Home Assistant 0.29](https://www.home-assistant.io/blog/2016/09/29/async-sleepiq-emoncms-stocks/) as part of our bi-weekly release schedule. This release introduced a complete overhaul of the core spearheaded by [Ben Bangert](https://github.com/bbangert/).
The old core was set up like a “traditional” threaded application. Each resource that was not thread safe (ie. the state of entities) would be protected by a lock. This caused a lot of waiting and potential inconsistency because a task could now end up waiting halfway through its job until some resource got freed.
Our new core is based on Pythons built-in **asyncio** module. Instead of having all threads have access to the core API objects, access is now limited to a special thread called the *event loop*. All components will now schedule themselves as a task to be executed by the event loop. This gives us the guarantee that only a single task is executed at the same time, meaning we no longer need any locks.
The only problem with running everything inside the event loop is when a task does blocking I/O; something most third-party Python libraries do. For example, while requesting new information from a device, the core will stop running until we get a response from the device. To handle this, a task is able to suspend itself until the response is available, after which it will be enqueued in the event loop to process the result.
For a task to be able to suspend itself, all code that it calls must support this capability. In practice, this would mean that each device integration will need a full rewrite of the library that offers the integration! As this is something that cannot be achieved, ever, a 100% backwards compatible API has been added so that no platform will require updating.
The backwards compatible API schedules a task in a different thread and blocks that thread until the task has been processed by the event loop.

View File

@ -0,0 +1,102 @@
---
title: "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](https://dev-docs.home-assistant.io/en/master/api/core.html) 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
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))
```

View File

@ -0,0 +1,245 @@
---
title: "Authentication API"
sidebar_label: API
---
This page will describe the steps required for your application to authorize against and integrate with Home Assistant instances. [See a demo](https://hass-auth-demo.glitch.me) powered by our helper lib [home-assistant-js-websocket](https://github.com/home-assistant/home-assistant-js-websocket).
Each user has their own instance of Home Assistant which gives each user control over their own data. However, we also wanted to make it easy for third party developers to create applications that allow users to integrate with Home Assistant. To achieve this, we have adopted the [OAuth 2 specification](https://tools.ietf.org/html/rfc6749) combined with the [OAuth 2 IndieAuth extension](https://indieauth.spec.indieweb.org/) for generating clients.
## Clients
Before you can ask the user to authorize their instance with your application, you will need a client. In traditional OAuth2, the server needs to generate a client before a user can authorize. However, as each server belongs to a user, we've adopted a slightly different approach from [IndieAuth](https://indieauth.spec.indieweb.org/#client-identifier).
The client ID you need to use is the website of your application. The redirect url has to be of the same host and port as the client ID. For example:
- client id: `https://www.my-application.io`
- redirect uri: `https://www.my-application.io/hass/auth_callback`
If you require a different redirect url (ie, if building a native app), you can add an HTML tag to the content of the website of your application (the client ID) with an approved redirect url. For example, add this to your site to whitelist redirect uri `hass://auth`:
```html
<link rel='redirect_uri' href='hass://auth'>
```
Home Assistant will scan the first 10kB of a website for link tags.
## Authorize
[![Authorization flow sequence diagram](/img/en/auth/authorize_flow.png)](https://www.websequencediagrams.com/?lz=dGl0bGUgQXV0aG9yaXphdGlvbiBGbG93CgpVc2VyIC0-IENsaWVudDogTG9nIGludG8gSG9tZSBBc3Npc3RhbnQKABoGIC0-IFVzZXI6AEMJZSB1cmwgAD4JACgOOiBHbyB0bwAeBWFuZCBhAC0ICgBQDgB1DACBFw5jb2RlAHELAE4RZXQgdG9rZW5zIGZvcgAoBgBBGlQAJQUK&s=qsd)
> All example URLs here are shown with extra spaces and new lines for display purposes only.
The authorize url should contain `client_id` and `redirect_uri` as query parameters.
http://your-instance.com/auth/authorize?
client_id=https%3A%2F%2Fhass-auth-demo.glitch.me&
redirect_uri=https%3A%2F%2Fhass-auth-demo.glitch.me%2F%3Fauth_callback%3D1
Optionally you can also include a `state` parameter, this will be added to the redirect uri. The state is perfect to store the instance url that you are authenticating with. Example:
http://your-instance.com/auth/authorize?
client_id=https%3A%2F%2Fhass-auth-demo.glitch.me&
redirect_uri=https%3A%2F%2Fhass-auth-demo.glitch.me%2Fauth_callback&
state=http%3A%2F%2Fhassio.local%3A8123
The user will navigate to this link and be presented with instructions to log in and authorize your application. Once authorized, the user will be redirected back to the passed in redirect uri with the authorization code and state as part of the query parameters. Example:
https://hass-auth-demo.glitch.me/auth_callback
code=12345&
state=http%3A%2F%2Fhassio.local%3A8123
This authorization code can be exchanged for tokens by sending it to the token endpoint (see next section).
## 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. In thee case of refresh token, the token endpoint is also capable of revoking a 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
> All requests to the token endpoint need to contain the exact same client ID as was used to redirect the user to the authorize endpoint.
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&
client_id=https%3A%2F%2Fhass-auth-demo.glitch.me
The return response will be an access and refresh token:
```json
{
"access_token": "ABCDEFGH",
"expires_in": 1800,
"refresh_token": "IJKLMNOPQRST",
"token_type": "Bearer"
}
```
The access token is a short lived token that can be used to access the API. The refresh token can be used to fetch new access tokens. The `expires_in` value is seconds that the access token is valid.
An HTTP status code of 400 will be returned if an invalid request has been issued. The HTTP status code will be 403 if a token is requested for an inactive user.
```json
{
"error": "invalid_request",
"error_description": "Invalid client id",
}
```
### Refresh token
Once you have retrieved a refresh token via the grant type `authorization_code`, you can use it to fetch new access tokens. The request body is:
grant_type=refresh_token&
refresh_token=IJKLMNOPQRST&
client_id=https%3A%2F%2Fhass-auth-demo.glitch.me
The return response will be an access token:
```json
{
"access_token": "ABCDEFGH",
"expires_in": 1800,
"token_type": "Bearer"
}
```
An HTTP status code of 400 will be returned if an invalid request has been issued.
```json
{
"error": "invalid_request",
"error_description": "Invalid client id",
}
```
### Revoking a refresh token
> client_id is not need for revoke refresh token
The token endpoint is also capable of revoking a refresh token. Revoking a refresh token will immediately revoke the refresh token and all access tokens that it has ever granted. To revoke a refresh token, make the following request:
token=IJKLMNOPQRST&
action=revoke
The request will always respond with an empty body and HTTP status 200, regardless if the request was successful.
## Long-lived access token
A long-lived access token is usually used for 3rd party API calls and webhook-ish integrations. To generate a long-lived access token, an active websocket connection has to be established.
Send websocket command `auth/long_lived_access_token` will create a long-lived access token for current user. Access token will not be saved in Home Assistant. User need to record the token in secure place.
```json
{
"id": 11,
"type": "auth/long_lived_access_token",
"client_name": "GPS Logger",
"client_icon": null,
"lifespan": 365
}
```
Result will be a long-lived access token:
```json
{
"id": 11,
"type": "result",
"success": true,
"result": "ABCDEFGH"
}
```
Additionally, a long-lived access token can be created using the UI tool located at the bottom of the user's Home Assistant profile page.
## 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
### Example: cURL
```shell
curl -X GET \
https://your.awesome.home/api/error/all \
-H 'Authorization: Bearer ABCDEFGH'
```
### Example: Python
```python
import requests
url = "https://your.awesome.home/api/error/all"
headers = {
'Authorization': "Bearer ABCDEFGH",
}
response = requests.request('GET', url, headers=headers)
print(response.text)
```
### Example: NodeJS
```JavaScript
fetch('https://your.awesome.home/api/error/all', {
headers: { Authorization: 'Bearer ABCDEFGH' }
}).then(function (response) {
if (!response.ok) {
return Promise.reject(response);
}
return response.text();
}).then(function (body ) {
console.log(body);
});
```
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 so the user is no longer logged in. You should clear the user's data and ask the user to authorize again.
## Signed paths
Sometimes you want a user to make a GET request to Home Assistant to download data. In this case the normal auth system won't do, as we can't link the user to an API with the auth header attached to it. In that case, a signed path can help.
A signed path is a normal path on our server, like `/api/states`, but with an attached secure authentication signature. The user is able to navigate to this path and will be authorised as the access token that created the signed path. Signed paths can be created via the websocket connection and are meant to be shortlived. The default expiration is 30 seconds.
To get a signed path, send the following command:
```js
{
"type": "auth/sign_path",
"path": "/api/states",
// optional, expiration time in seconds. Defaults to 30 seconds
"expires": 20
}
```
The response will contain the signed path:
```js
{
"path": "/api/states?authSig=ABCDEFGH"
}
```
Some things to note about a signed path:
- If the refresh token is deleted, the signed url is no longer valid.
- If the user is deleted, the signed url is no longer valid (because the refresh token will be deleted).
- If Home Assistant is restarted, the signed url is no longer valid.
- Access is only validated when the request is received. If a response takes longer than the expiration time (ie, downloading a large file), the download will continue after the expiration date has passed.

View File

@ -0,0 +1,66 @@
---
title: "Multi-factor Authentication Modules"
---
Multi-factor Authentication Modules are used in conjunction with [Authentication Provider](auth_auth_provider.html) to provide a fully configurable authentication framework. Each MFA module may provide one multi-factor authentication function. User can enable multiple mfa modules, but can only select one module in login process.
## Defining an mfa auth module
> We currently only support built-in mfa auth modules. Support for custom auth modules might arrive in the future.
Multi-factor Auth modules are defined in `homeassistant/auth/mfa_modules/<name of module>.py`. The auth module will need to provide an implementation of the `MultiFactorAuthModule` class.
For an example of a fully implemented auth module, please see [insecure_example.py](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/auth/mfa_modules/insecure_example.py).
Multi-factor Auth modules shall extend the following methods of `MultiFactorAuthModule` class.
| method | Required | Description |
| ---------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `@property def input_schema(self)` | Yes | Return a schema defined the user input form. |
| `async def async_setup_flow(self, user_id)` | Yes | Return a SetupFlow to handle the setup workflow. |
| `async def async_setup_user(self, user_id, setup_data)` | Yes | Set up user for use this auth module. |
| `async def async_depose_user(self, user_id)` | Yes | Remove user information from this auth module. |
| `async def async_is_user_setup(self, user_id)` | Yes | Return whether user is set up. |
| `async def async_validate(self, user_id, user_input)` | Yes | Given a user_id and user input, return validation result. |
| `async def async_initialize_login_mfa_step(self, user_id)` | No | Will be called once before display the mfa step of login flow. This is not initialization for the MFA module but the mfa step in login flow. |
## Setup Flow
Before user can use a multi-factor auth module, it has to be enabled or set up. All available modules will be listed in user profile page, user can enable the module he/she wants to use. A setup data entry flow will guide user finish the necessary steps.
Each MFA module need to implement a setup flow handler extends from `mfa_modules.SetupFlow` (if only one simple setup step need, `SetupFlow` can be used as well). For example for Google Authenticator (TOTP, Time-based One Time Password) module, the flow will need to be:
- Generate a secret and store it on instance of setup flow
- Return `async_show_form` with a QR code in the description (injected as base64 via `description_placeholders`)
- User scans code and enters a code to verify it scanned correctly and clock in synced
- TOTP module saved the secret along with user_id, module is enabled for user
## Workflow
![Multi Factor Authentication Workflow](/img/en/auth/mfa_workflow.png)
<!--
Source: https://drive.google.com/file/d/12_nANmOYnOdqM56BND01nPjJmGXe-M9a/view
-->
## Configuration example
```yaml
# configuration.xml
homeassistant:
auth_providers:
- type: homeassistant
- type: legacy_api_password
auth_mfa_modules:
- type: totp
- type: insecure_example
users: [{'user_id': 'a_32_bytes_length_user_id', 'pin': '123456'}]
```
In this example, user will first select from `homeassistant` or `legacy_api_password` auth provider. For `homeassistant` auth provider, user will first input username/password, if that user enabled both `totp` and `insecure_example`, then user need select one auth module, then input Google Authenticator code or input pin code base on the selection.
> insecure_example is only for demo purpose, please do not use it in production.
## Validation session
Not like auth provider, auth module use session to manage the validation. After auth provider validated, mfa module will create a validation session, include an experiation time and user_id from auth provider validate result. Mutli-factor auth module will not only verify the user input, but also verify the session is not expired. The validation session data is stored in your configuration directory.

View File

@ -0,0 +1,42 @@
---
title: "Authentication Providers"
---
Authentication providers confirm the identity of users. The user proofs their identity by going through the login flow for an auth provider. The auth provider defines the login flow and can ask the user all information this needs. This will commonly be username and password but could also include a 2FA token or other challenges.
Once an authentication provider has confirmed the identity of a user, it will pass that on to Home Assistant in the form of a Credentials object.
## Defining an auth provider
> We currently only support built-in auth providers. Support for custom auth providers might arrive in the future.
Auth providers are defined in `homeassistant/auth/providers/<name of provider>.py`. The auth provider module will need to provide an implementation of the `AuthProvider` class and `LoginFlow` class, it is what asks user for information and validates it base on `data_entry_flow`.
For an example of a fully implemented auth provider, please see [insecure_example.py](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/auth/providers/insecure_example.py).
Auth providers shall extend the following methods of `AuthProvider` class.
| method | Required | Description |
| ---------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| async def async_login_flow(self) | Yes | Return an instance of the login flow for a user to identify itself. |
| async def async_get_or_create_credentials(self, flow_result) | Yes | Given the result of a login flow, return a credentials object. This can either be an existing one or a new one. |
| async def async_user_meta_for_credentials(credentials) | No | Callback called Home Assistant is going to create a user from a Credentials object. Can be used to populate extra fields for the user. |
Auth providers shall extend the following methods of `LoginFlow` class.
| method | Required | Description |
| -------------------------------------------------- | -------- | ------------------------------------------------ |
| async def async_step_init(self, user_input=None) | Yes | Handle the login form, see more detail in below. |
## async_step_init of LoginFlow
> We may change this inteface in near future.
`LoginFlow` extends `data_entry_flow.FlowHandler`. The first step of data entry flow is hard coded as `init`, so each flow has to implement `async_step_init` method. The pattern of `async_step_init` likes following pseudo-code:
```python
async def async_step_init(self, user_input=None):
return self.async_show_form(step_id='init', data_schema='some schema to construct ui form') if user_input is None
return self.async_show_form(step_id='init', errors) if user_input is invalid
return await self.async_finish(username) if user_input is valid
```

View File

@ -0,0 +1,50 @@
---
title: "Authentication"
sidebar_label: Introduction
---
Home Assistant has a built-in authentication system allowing different users to interact with Home Assistant. The authentication system consist of various parts.
![Overview of how the different parts interact](/img/en/auth/architecture.png)
## Authentication providers
An authentication provider is used for users to authenticate themselves. It's up to the authentication provider to choose the method of authentication and the backend to use. By default we enable the built-in Home Assistant authentication provider which stores the users securely inside your configuration directory.
The authentication providers that Home Assistant will use are specified inside `configuration.yaml`. It is possible to have multiple instances of the same authentication provider active. In that case, each will be identified by a unique identifier. Authentication providers of the same type will not share credentials.
## Credentials
Credentials store the authentication of a user with a specific authentication provider. It is produced when a user successfully authenticates. It will allow the system to find the user in our system. If the user does not exist, a new user will be created. This user will not be activated but will require approval by the owner.
It is possible for a user to have multiple credentials linked to it. However, it can only have a single credential per specific authentication provider.
## Users
Each person is a user in the system. To log in as a specific user, authenticate with any of the authentication providers that are linked to this user. When a user logs in, it will get a refresh and an access token to make requests to Home Assistant.
### Owner
The user that is created during onboarding will be marked as "owner". The owner is able to manage other users and will always have access to all permissions.
## Groups
Users are a member of one or more groups. Group membership is how a user is granted permissions.
## Permission Policy
This is the permission policy that describes to which resources a group has access. For more information about permissions and policies, see [Permissions](auth_permissions.md).
## Access and refresh tokens
Applications that want to access Home Assistant will ask the user to start an authorization flow. The flow results in an authorization code when a user successfully authorizes the application with Home Assistant. This code can be used to retrieve an access and a refresh token. The access token will have a limited lifetime while refresh tokens will remain valid until a user deletes it.
The access token is used to access the Home Assistant APIs. The refresh token is used to retrieve a new valid access token.
### Refresh token types
There are three different types of refresh tokens:
- *Normal*: These are the tokens that are generated when a user authorizes an application. The application will hold on to these tokens on behalf of the user.
- *Long-lived Access Token*: These are refresh tokens that back a long lived access token. They are created internally and never exposed to the user.
- *System*: These tokens are limited to be generated and used by system users like Hass.io. They are never exposed to the user.

View File

@ -0,0 +1,266 @@
---
title: "Permissions"
---
> This is an experimental feature that is not enabled or enforced yet
Permissions limit the things a user has access to or can control. Permissions are attached to groups, of which a user can be a member. The combined permissions of all groups a user is a member of decides what a user can and cannot see or control.
Permissions do not apply to the user that is flagged as "owner". This user will always have access to everything.
## General permission structure
Policies are dictionaries that at the root level consist of different categories of permissions. In the current implementation this is limited to just entities.
```python
{
"entities": …
}
```
Each category can further split into subcategories that describe parts of that category.
```python
{
"entities": {
"domains": …,
"entity_ids": …
}
}
```
If a category is omitted, the user will not have permission to that category.
When defining a policy, any dictionary value at any place can be replaced with `True` or `None`. `True` means that permission is granted and `None` means use default, which is deny access.
## Entities
Entity permissions can be set on a per entity and per domain basis using the subcategories `entity_ids`, `device_ids`, `area_ids` and `domains`. You can either grant all access by setting the value to `True`, or you can specify each entity individually using the "read", "control", "edit" permissions.
The system will return the first matching result, based on the order: `entity_ids`, `device_ids`, `area_ids`, `domains`, `all`.
```json
{
"entities": {
"domains": {
"switch": true
},
"entity_ids": {
"light.kitchen": {
"read": true,
"control": true
}
}
}
}
```
## Merging policies
If a user is a member of multiple groups, the groups permission policies will be combined into a single policy at runtime. When merging policies, we will look at each level of the dictionary and compare the values for each source using the following methodology:
1. If any of the values is `True`, the merged value becomes `True`.
2. If any value is a dictionary, the merged value becomes a dictionary created by recursively checking each value using this methodology.
3. If all values are `None`, the merged value becomes `None`.
Let's look at an example:
```python
{
"entities": {
"entity_ids": {
"light.kitchen": True
}
}
}
```
```python
{
"entities": {
"entity_ids": True
}
}
```
Once merged becomes
```python
{
"entities": {
"entity_ids": True
}
}
```
## Checking permissions
We currently have two different permission checks: can the user do the read/control/edit operation on an entity, and is the user an admin and thus allowed to change this configuration setting.
Certain APIs will always be accessible to all users, but might offer a limited scope based on the permissions, like rendering a template.
### Checking permissions
To check a permission, you will need to have access to the user object. Once you have the user object, checking the permission is easy.
```python
from homeassistant.exceptions import Unauthorized
from homeasistant.permissions.const import (
POLICY_READ, POLICY_CONTROL, POLICY_EDIT
)
# Raise error if user is not an admin
if not user.is_admin:
raise Unauthorized()
# Raise error if user does not have access to control an entity
# Available policies: POLICY_READ, POLICY_CONTROL, POLICY_EDIT
if not user.permissions.check_entity(entity_id, POLICY_CONTROL):
raise Unauthorized()
```
### The context object
All service calls, fired events and states in Home Assistant have a context object. This object allows us to attribute changes to events and services. These context objects also contain a user id, which is used for checking the permissions.
It's crucial for permission checking that actions taken on behalf of the user are done with a context containing the user ID. If you are in a service handler, you should re-use the incoming context `call.context`. If you are inside a WebSocket API or Rest API endpoint, you should create a context with the correct user:
```python
from homeassistant.core import Context
await hass.services.async_call('homeassistant', 'stop', context=Context(
user_id=user.id
), blocking=True)
```
### If a permission check fails
When you detect an anauthorized action, you should raise the `homeassistant.exceptions.Unauthorized` exception. This exception will cancel the current action and notifies the user that their action is unauthorized.
The `Unauthorized` exception has various parameters, to identify the permission check that failed. All fields are optional.
| # Not all actions have an ID (like adding config entry) | # We then use this fallback to know what category was unauth
| Parameter | Description |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| context | The context of the current call. |
| user_id | The user ID that we tried to operate on. |
| entity_id | The entity ID that we tried to operate on. |
| config_entry_id | The config entry ID that we tried to operate on. |
| perm_category | The permission category that we tested. Only necessary if we don't have an object ID that the user tried to operate on (like when we create a config entry). |
| permission | The permission that we tested, ie `POLICY_READ`. |
### Securing a service call handler
Service calls allow a user to control entities or with the integration as a whole. A service call uses the attached context to see which user invoked the command. Because context is used, it is important that you also pass the call context to all service calls.
All services that are registered via the entity component (`component.async_register_entity_service()`) will automatically have their permissions checked.
#### Checking entity permissions
Your service call handler will need to check the permissions for each entity that it will act on.
```python
from homeassistant.exceptions import Unauthorized, UnknownUser
from homeassistant.auth.permissions.const import POLICY_CONTROL
async def handle_entity_service(call):
"""Handle a service call."""
entity_ids = call.data['entity_id']
for entity_id in entity_ids:
if call.context.user_id:
user = await hass.auth.async_get_user(call.context.user_id)
if user is None:
raise UnknownUser(
context=call.context,
entity_id=entity_id,
permission=POLICY_CONTROL,
)
if not user.permissions.check_entity(entity_id, POLICY_CONTROL):
raise Unauthorized(
context=call.context,
entity_id=entity_id,
permission=POLICY_CONTROL,
)
# Do action on entity
async def async_setup(hass, config):
hass.services.async_register(DOMAIN, 'my_service', handle_entity_service)
return True
```
#### Checking admin permission
Starting Home Assistant 0.90, there is a special decorator to help protect services that require admin access.
```python
# New in Home Assistant 0.90
async def handle_admin_service(call):
"""Handle a service call."""
# Do admin action
async def async_setup(hass, config):
hass.helpers.service.async_register_admin_service(
DOMAIN, 'my_service', handle_admin_service, vol.Schema({})
)
return True
```
### Securing a REST API endpoint
```python
from homeassistant.core import Context
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.exceptions import Unauthorized
class MyView(HomeAssistantView):
"""View to handle Status requests."""
url = '/api/my-component/my-api'
name = 'api:my-component:my-api'
async def post(self, request):
"""Notify that the API is running."""
hass = request.app['hass']
user = request['hass_user']
if not user.is_admin:
raise Unauthorized()
hass.bus.async_fire('my-component-api-running', context=Context(
user_id=user.id
))
return self.json_message("Done.")
```
### Securing a Websocket API endpoint
Verifying permissions in a Websocket API endpoint can be done by accessing the user via `connection.user`. If you need to check admin access, you can use the built-in `@require_admin` decorator.
```python
from homeassistant.compnents import websocket_api
async def async_setup(hass, config):
hass.components.websocket_api.async_register_command(websocket_create)
return True
@websocket_api.require_admin
@websocket_api.async_response
@websocket_api.websocket_command({
vol.Required('type'): 'my-component/my-action',
})
async def websocket_create(hass, connection, msg):
"""Create a user."""
# Do action
```

View File

@ -0,0 +1,91 @@
---
title: Integration Configuration
sidebar_label: Configuration
---
> This option is currently only available for built-in components.
Integrations can be set up via the user interface by adding support for config entries. Config entries uses the [data flow entry framework](data_entry_flow_index.md) to allow users to create entries. Components that want to support config entries will need to define a Config Flow Handler. This handler will manage the creation of entries from user input, discovery or other sources (like Hass.io).
Config Flow Handlers control the data that is stored in a config entry. This means that there is no need to validate that the config is correct when Home Assistant starts up. It will also prevent breaking changes, because we will be able to migrate configuration entries to new formats if the version changes.
When instantiating the handler, Home Assistant will make sure to load all dependencies and install the requirements of the component.
To register your config flow handler with Home Assistant, register it with the config entries `HANDLERS` registry:
```python
from homeassistant import config_entries
@config_entries.HANDLERS.register(DOMAIN)
class ExampleConfigFlow(config_entries.ConfigFlow):
```
All config flow handlers will also need to add their domain name to the `FLOWS` constant in `homeassistant/config_entries.py`.
## Discovering your config flow
Home Assistant has a discovery integration that scans the network for available devices and services and will trigger the config flow of the appropriate integration. Discovery is limited to UPnP and zeroconf/mDNS.
To have your integration be discovered, you will have to extend the [NetDisco library](https://github.com/home-assistant/netdisco) to be able to find your device. This is done by adding a new discoverable. [See the repository for examples of existing discoverable.](https://github.com/home-assistant/netdisco/tree/master/netdisco/discoverables)
Once done, you will have to update the discovery integration to make it aware which discovery maps to which integration, by updating [this list](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/discovery/__init__.py#L55).
Finally, you will have to add support to your config flow to be triggered from discovery. This is done by adding a new discovery step. Make sure that your discovery step does not automatically create an entry. All discovered config flows are required to have a confirmation from the user.
Once discovered, the user will be notified that they can continue the flow from the config panel.
```python
@config_entries.HANDLERS.register(DOMAIN)
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_discovery(self, info):
# Handle discovery info
```
## Translations
Translations for the config flow handlers are defined under the `config` key in the component translation file `strings.json`. Example of the Hue component:
```json
{
"config": {
"title": "Philips Hue Bridge",
"step": {
"init": {
"title": "Pick Hue bridge",
"data": {
"host": "Host"
}
},
"link": {
"title": "Link Hub",
"description": "Press the button on the bridge to register Philips Hue with Home Assistant.\n\n![Location of button on bridge](/static/images/config_philips_hue.jpg)"
}
},
"error": {
"register_failed": "Failed to register, please try again",
"linking": "Unknown linking error occurred."
},
"abort": {
"discover_timeout": "Unable to discover Hue bridges",
"no_bridges": "No Philips Hue bridges discovered",
"all_configured": "All Philips Hue bridges are already configured",
"unknown": "Unknown error occurred",
"cannot_connect": "Unable to connect to the bridge",
"already_configured": "Bridge is already configured"
}
}
}
```
When the translations are merged into Home Assistant, they will be automatically uploaded to [Lokalise](https://lokalise.co/) where the translation team will help to translate them in other languages. [More info on translating Home Assistant.](internationalization_translation.md)
## Triggering other config flows
If you are writing an integration that discovers other integrations, you will want to trigger their config flows so the user can set them up. Do this by passing a source parameter and optional user input when initializing the config entry:
```python
await hass.config_entries.flow.async_init(
'hue', data=discovery_info,
context={'source': config_entries.SOURCE_DISCOVERY})
```

View File

@ -0,0 +1,166 @@
---
title: Config Entries
sidebar_label: Introduction
---
Config Entries are configuration data that are persistently stored by Home Assistant. A config entry is created by a user via the UI. The UI flow is powered by a [config flow handler](config_entries_config_flow_handler.md) as defined by the component. Config entries can also have an extra [options flow handler](config_entries_options_flow_handler.md), also defined by the component.
## Lifecycle
| State | Description |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| not loaded | The config entry has not been loaded. This is the initial state when a config entry is created or when Home Assistant is restarted. |
| loaded | The config entry has been loaded. |
| setup error | An error occurred when trying to set up the config entry. |
| setup retry | A dependency of the config entry was not ready yet. Home Assistant will automatically retry loading this config entry in the future. Time between attempts will automatically increase. |
| migration error | The config entry had to be migrated to a newer version, but the migration failed. |
| failed unload | The config entry was attempted to be unloaded, but this was either not supported or it raised an exception. |<svg width="508pt" height="188pt" viewbox="0.00 0.00 508.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
<title>G</title>
<polygon fill="white" stroke="white" points="-4,5 -4,-184 505,-184 505,5 -4,5"></polygon>
<g id="node1" class="node">
<title>
not loaded
</title>
<ellipse fill="none" stroke="black" cx="168" cy="-162" rx="51.3007" ry="18"></ellipse>
<text text-anchor="middle" x="168" y="-157.8" font-family="Times,serif" font-size="14.00">not loaded</text> </g> <g id="node3" class="node">
<title>
loaded
</title>
<ellipse fill="none" stroke="black" cx="61" cy="-90" rx="36.1722" ry="18"></ellipse>
<text text-anchor="middle" x="61" y="-85.8" font-family="Times,serif" font-size="14.00">loaded</text> </g> <g id="edge2" class="edge">
<title>
not loaded-&gt;loaded
</title>
<path fill="none" stroke="black" d="M140.518,-146.666C123.947,-136.676 103.104,-123.187 86.8392,-111.989"></path>
<polygon fill="black" stroke="black" points="88.532,-108.902 78.3309,-106.041 84.5212,-114.639 88.532,-108.902"></polygon>
</g> <g id="node5" class="node">
<title>
setup error
</title>
<ellipse fill="none" stroke="black" cx="168" cy="-90" rx="52.3895" ry="18"></ellipse>
<text text-anchor="middle" x="168" y="-85.8" font-family="Times,serif" font-size="14.00">setup error</text> </g> <g id="edge4" class="edge">
<title>
not loaded-&gt;setup error
</title>
<path fill="none" stroke="black" d="M162.122,-144.055C161.304,-136.346 161.061,-127.027 161.395,-118.364"></path>
<polygon fill="black" stroke="black" points="164.894,-118.491 162.087,-108.275 157.911,-118.012 164.894,-118.491"></polygon>
</g> <g id="node7" class="node">
<title>
setup retry
</title>
<ellipse fill="none" stroke="black" cx="291" cy="-90" rx="52.0932" ry="18"></ellipse>
<text text-anchor="middle" x="291" y="-85.8" font-family="Times,serif" font-size="14.00">setup retry</text> </g> <g id="edge6" class="edge">
<title>
not loaded-&gt;setup retry
</title>
<path fill="none" stroke="black" d="M189.578,-145.465C206.94,-134.869 231.584,-120.783 252.292,-109.59"></path>
<polygon fill="black" stroke="black" points="254.022,-112.634 261.19,-104.832 250.722,-106.461 254.022,-112.634"></polygon>
</g> <g id="node9" class="node">
<title>
migration error
</title>
<ellipse fill="none" stroke="black" cx="431" cy="-90" rx="69.1427" ry="18"></ellipse>
<text text-anchor="middle" x="431" y="-85.8" font-family="Times,serif" font-size="14.00">migration error</text> </g> <g id="edge8" class="edge">
<title>
not loaded-&gt;migration error
</title>
<path fill="none" stroke="black" d="M207.659,-150.445C252.053,-138.628 324.343,-119.388 374.607,-106.01"></path>
<polygon fill="black" stroke="black" points="375.588,-109.37 384.351,-103.416 373.787,-102.606 375.588,-109.37"></polygon>
</g> <g id="edge10" class="edge">
<title>
loaded-&gt;not loaded
</title>
<path fill="none" stroke="black" d="M85.5216,-103.56C102.143,-113.462 123.939,-127.508 141.027,-139.231"></path>
<polygon fill="black" stroke="black" points="139.274,-142.276 149.481,-145.116 143.273,-136.53 139.274,-142.276"></polygon>
</g> <g id="node12" class="node">
<title>
failed unload
</title>
<ellipse fill="none" stroke="black" cx="61" cy="-18" rx="61.5781" ry="18"></ellipse>
<text text-anchor="middle" x="61" y="-13.8" font-family="Times,serif" font-size="14.00">failed unload</text> </g> <g id="edge12" class="edge">
<title>
loaded-&gt;failed unload
</title>
<path fill="none" stroke="black" d="M61,-71.6966C61,-63.9827 61,-54.7125 61,-46.1124"></path>
<polygon fill="black" stroke="black" points="64.5001,-46.1043 61,-36.1043 57.5001,-46.1044 64.5001,-46.1043"></polygon>
</g> <g id="edge16" class="edge">
<title>
setup error-&gt;not loaded
</title>
<path fill="none" stroke="black" d="M173.913,-108.275C174.715,-116.03 174.94,-125.362 174.591,-134.005"></path>
<polygon fill="black" stroke="black" points="171.094,-133.832 173.878,-144.055 178.077,-134.327 171.094,-133.832"></polygon>
</g> <g id="edge14" class="edge">
<title>
setup retry-&gt;not loaded
</title>
<path fill="none" stroke="black" d="M269.469,-106.507C252.104,-117.106 227.436,-131.206 206.71,-142.408"></path>
<polygon fill="black" stroke="black" points="204.973,-139.368 197.805,-147.17 208.273,-145.541 204.973,-139.368"></polygon>
</g> </g> </svg>
<!--
Graphviz:
digraph G {
"not loaded" -> "loaded"
"not loaded" -> "setup error"
"not loaded" -> "setup retry"
"not loaded" -> "migration error"
"loaded" -> "not loaded"
"loaded" -> "failed unload"
"setup retry" -> "not loaded"
"setup error" -> "not loaded"
}
-->
## Setting up an entry
During startup, Home Assistant first calls the [normal component setup](https://developers.home-assistant.io/docs/en/creating_component_index.html), and then call the method `async_setup_entry(hass, entry)` for each entry. If a new Config Entry is created at runtime, Home Assistant will also call `async_setup_entry(hass, entry)` ([example](https://github.com/home-assistant/home-assistant/blob/0.68.0/homeassistant/components/hue/__init__.py#L119)).
#### For platforms
If a component includes platforms, it will need to forward the Config Entry to the platform. This can be done by calling the forward function on the config entry manager ([example](https://github.com/home-assistant/home-assistant/blob/0.68.0/homeassistant/components/hue/bridge.py#L81)):
```python
# Use `hass.async_add_job` to avoid a circular dependency between the platform and the component
hass.async_add_job(hass.config_entries.async_forward_entry_setup(config_entry, 'light'))
```
For a platform to support config entries, it will need to add a setup entry method ([example](https://github.com/home-assistant/home-assistant/blob/0.68.0/homeassistant/components/light/hue.py#L60)):
```python
async def async_setup_entry(hass, config_entry, async_add_devices):
```
## Unloading entries
Components can optionally support unloading a config entry. When unloading an entry, the component needs to clean up all entities, unsubscribe any event listener and close all connections. To implement this, add `async_unload_entry(hass, entry)` to your component ([example](https://github.com/home-assistant/home-assistant/blob/0.68.0/homeassistant/components/hue/__init__.py#L136)).
For each platform that you forwarded the config entry to, you will need to forward the unloading too.
```python
await self.hass.config_entries.async_forward_entry_unload(self.config_entry, 'light')
```
If you need to clean up resources used by an entity in a platform, have the entity implement the [`async_will_remove_from_hass`](entity_index.md#async_will_remove_from_hass) method.
## Removal of entries
If a component needs to clean up code when an entry is removed, it can define a removal method:
```python
async def async_remove_entry(hass, entry) -> None:
"""Handle removal of an entry."""
```

View File

@ -0,0 +1,44 @@
---
title: Integration Configuration Options
sidebar_label: Configuration Options
---
> This option is currently only available for built-in components.
An integration that is configured via a config entry can expose options to the user to allow tweaking behavior of the integration, like which devices or locations should be integrated.
Config Entry Options uses the [Data Flow Entry framework](data_entry_flow_index.md) to allow users to update a config entries options. Components that want to support config entry options will need to define a Options Flow Handler.
## Options support
For an integration to support options it needs to have an `async_get_options_flow` method in its config flow handler. Calling it will return an instance of the components options flow handler.
```python
@staticmethod
@callback
def async_get_options_flow(config, options):
return OptionsFlowHandler(config, options)
```
## Flow handler
The Flow handler works just like the config flow handler, except that the first step in the flow will always be `async_step_init`.
```python
class OptionsFlowHandler(data_entry_flow.FlowHandler):
def __init__(self, config, options):
```
## Signal updates
If the component should act on updated options, you can register an update listener to the config entry that will be called when the entry is updated.
```python
entry.add_update_listener(update_listener)
```
The Listener shall be an async function that takes the same input as async_setup_entry. Options can then be accessed from `entry.options`.
```python
async def update_listener(hass, entry):
```

View File

@ -0,0 +1,57 @@
---
title: "Integration Configuration via YAML"
sidebar_label: Configuration via YAML
---
`configuration.yaml` is a configuration file defined by the user. It is automatically created by Home Assistant on first launch. It defines which components to load.
## Pre-processing
Home Assistant will do some pre-processing on the config based on the components that are specified to load.
### CONFIG_SCHEMA
If a component defines a variable `CONFIG_SCHEMA`, the config object that is passed in will be the result of running the config through `CONFIG_SCHEMA`. `CONFIG_SCHEMA` should be a voluptuous schema.
### PLATFORM_SCHEMA
If a component defines a variable `PLATFORM_SCHEMA`, the component will be treated as an entity component. The configuration of entity components is a list of platform configurations.
Home Assistant will gather all platform configurations for this component. It will do so by looking for configuration entries under the domain of the component (ie `light`) but also under any entry of domain + extra text.
While gathering the platform configs, Home Assistant will validate them. It will see if the platform exists and if the platform defines a PLATFORM_SCHEMA, validate against that schema. If not defined, it will validate the config against the PLATFORM_SCHEMA defined in the component. Any configuration that references non existing platforms or contains invalid config will be removed.
The following `configuration.yaml`:
```yaml
unrelated_component:
some_key: some_value
switch:
platform: example1
switch living room:
- platform: example2
some_config: true
- platform: invalid_platform
```
will be passed to the component as
```python
{
"unrelated_component": {
"some_key": "some_value"
},
"switch": [
{
"platform": "example1"
},
{
"platform": "example2,
"some_config": True
}
]
}
```

View File

@ -0,0 +1,69 @@
---
title: "Checklist for creating a component"
sidebar_label: Component Checklist
---
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. Requirements have been added to [`manifest.json`](creating_integration_manifest.md). The `REQUIREMENTS` constant is deprecated.
2. Requirement version should be pinned: `"requirements": ['phue==0.8.1']`
3. We no longer want requirements hosted on GitHub. Please upload to PyPi.
4. Requirements should only be imported inside functions. 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. You can share data with your platforms by leveraging `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()
```
[Tutorial on publishing your own PyPI package](https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/)
### 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 domain name. 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.

View File

@ -0,0 +1,7 @@
---
title: ""
---
[This page has moved.](creating_integration_manifest.md)
<script>document.location = 'creating_integration_manifest.html';</script>

View File

@ -0,0 +1,20 @@
---
title: "Integration with Multiple Platforms"
sidebar_label: Multiple platforms
---
Most integrations consist of a single platform. And in that case, it's fine to just define that one platform. However, if you are going to add a second platform, you will want to centralize your connection logic. This is done inside the component (`__init__.py`).
If your integration is configurable via `configuration.yaml`, it will cause the entry point of your configuration to change, as now users will need to set up your integration directly, and it is up to your integration to set up the platforms.
## Loading platforms when configured via a config entry
If your integration is set up via a config entry, you will need to forward the config entry to the appropriate integration to set up your platform. For more info, see the [config entry documentation](config_entries_index.md#for-platforms).
## Loading platforms when configured via configuration.yaml
If your integration is not using config entries, it will have to use our discovery helpers to set up its platforms. Note, this approach does not support unloading.
To do this, you will need to use the `load_platform` and `async_load_platform` methods from the discovery helper.
- See also a [full example that implementing this logic](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_load_platform/)

View File

@ -0,0 +1,38 @@
---
title: "Creating a Minimal Component"
sidebar_label: "Minimal Component"
---
Alright, you learned about the [manifest](creating_integration_manifest.md), so it's time to write your first code for your integration. AWESOME. Don't worry, we've tried hard to keep it as easy as possible.
More extensive examples of integrations are available from [our example repository](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/).
## The code
Each component needs to have 2 basic parts: it needs to define a `DOMAIN` constant that contains the domain of the integration. The second part is that it needs to define a setup method that returns a boolean if the set up was successful. So let's take a look at how this looks:
```python
DOMAIN = 'hello_state'
def setup(hass, config):
hass.states.set('hello_state.world', 'Paulus')
# Return boolean to indicate that initialization was successful.
return True
```
And if you prefer an async component:
```python
DOMAIN = 'hello_state'
async def async_setup(hass, config):
hass.states.async_set('hello_state.world', 'Paulus')
# Return boolean to indicate that initialization was successful.
return True
```
That's it! If you load this, you will see a new state in the state machine.
To load this, add `hello_state:` to your `configuration.yaml` file and create a file `<config_dir>/custom_components/hello_state/__init__.py` with one of the two codeblocks above to test it locally.

View File

@ -0,0 +1,31 @@
---
title: "Integration File Structure"
sidebar_label: "File Structure"
---
Each integration is stored inside a directory named after the integration domain. The domain is a short name consisting of characters and underscores. This domain has to be unique and cannot be changed. Example of the domain for the mobile app integration: `mobile_app`. So all files for this integration are in the folder `mobile_app/`.
The bare minimum content of this folder looks like this:
- `manifest.json`: The manifest file describes the integration and its dependencies. [More info](creating_integration_manifest.md)
- `__init__.py`: The component file. If the integration only offers a platform, you can keep this file limited to a docstring introducing the integration `"""The Mobile App integration."""`.
## Integrating devices - `light.py`, `switch.py` etc
If your integration is going to integrate one or more devices, you will need to do this by creating a platform that interacts with an entity integration. For example, if you want to represent a light device inside Home Assistant, you will create `light.py`, which will contain a light platform for the light integration.
- More info on [available entity integrations](entity_index.md).
- More info on [creating platforms](creating_platform_index.md).
## Integrating services - `services.yaml`
If your integration is going to register services, it will need to provide a description of the available services. The description is stored in `services.yaml`. [More information about `services.yaml`.](dev_101_services.md)
## Where Home Assistant looks for integrations
Home Assistant will look for an integration when it sees the domain referenced in the config file (i.e. `mobile_app:`) or if it is a dependency of another integration. Home Assistant will look at the following locations:
- `<config directory>/custom_components/<domain>`
- `homeassistant/components/<domain>` (built-in integrations)
You can override a built-in integration by having an integration with the same domain in your `config/custom_components` folder. Note that overriding built-in components is not recommended as you will no longer get updates. It is recommended to pick a unique name.

View File

@ -0,0 +1,77 @@
---
title: "Integration Manifest"
sidebar_label: "Manifest"
---
Since 0.92.0, every integration has a manifest file to specify basic information about an integration. This file is stored as `manifest.json` in your integration directory. It is required to add such a file, except for custom components.
```json
{
"domain": "hue",
"name": "Philips Hue",
"documentation": "https://www.home-assistant.io/components/hue",
"dependencies": ["mqtt"],
"codeowners": ["@balloob"],
"requirements": ["aiohue==1.9.1"]
}
```
Or a minimal example that you can copy into your project:
```json
{
"domain": "your_domain_name",
"name": "Your Integration",
"documentation": "https://www.example.com",
"dependencies": [],
"codeowners": [],
"requirements": []
}
```
## Domain
The domain is a short name consisting of characters and underscores. This domain has to be unique and cannot be changed. Example of the domain for the mobile app integration: `mobile_app`.
## Name
The name of the integration.
## Documentation
The website containing documentation on how to use your integration. If this integration is being submitted for inclusion in Home Assistant, it should be `https://www.home-assistant.io/components/<domain>`
## Dependencies
Dependencies are other Home Assistant integrations that you want Home Assistant to set up successfully prior to the integration being loaded. This can be necessary in case you want to offer functionality from that other integration, like using webhooks or an MQTT connection.
## Code Owners
GitHub usernames or team names of people that are responsible for this integration. You should add at least your GitHub username here, as well as anyone who helped you to write code that is being included.
## Requirements
Requirements are Python libraries or modules that you would normally install using `pip` for your component. Home Assistant will try to install the requirements into the `deps` subdirectory of the Home Assistant [configuration directory](https://www.home-assistant.io/docs/configuration/) if you are not using a `venv` or in something like `path/to/venv/lib/python3.6/site-packages` if you running in a virtual environment. This will make sure that all requirements are present at startup. If steps fail, like missing packages for the compilation of a module or other install errors, the component will fail to load.
Requirements is an array of strings. Each entry is a `pip` compatible string. For example, the media player Cast platform depends on the Python package PyChromecast v3.2.0: `["pychromecast==3.2.0"]`.
> Because of how Home Assistant installs requirements on demand, actual Python imports of your requirements should be done inside functions instead of at the root level of your Python files.
### Custom requirements during development & testing
During the development of a component, it can be useful to test against different versions of a requirement. This can be done in two steps, using `pychromecast` as an example:
```bash
pip install pychromecast==3.2.0 --target ~/.homeassistant/deps
hass --skip-pip
```
This will use the specified version, and prevent Home Assistant from trying to override it with what is specified in `requirements`.
If you need to make changes to a requirement to support your component, it's also possible to install a development version of the requirement using `pip install -e`:
```bash
git clone https://github.com/balloob/pychromecast.git
pip install -e ./pychromecast
hass --skip-pip
```

View File

@ -0,0 +1,93 @@
---
title: "Checklist for creating a platform"
sidebar_label: Platform Checklist
---
A checklist of things to do when you're adding a new platform.
> 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 platform level
- Use `CONF_MONITORED_CONDITIONS` instead of `CONF_MONITORED_VARIABLES`
### 1. Requirements
1. Requirements have been added to [`manifest.json`](creating_integration_manifest.md). The `REQUIREMENTS` constant is deprecated.
2. Requirement version should be pinned: `"requirements": ['phue==0.8.1']`
3. We no longer want requirements hosted on GitHub. Please upload to PyPi.
4. Requirements should only be imported inside functions. This is necessary because requirements are installed on the fly.
### 2. Dependencies
1. If you depend on a component for the connection, add it to your dependencies in [`manifest.json`](creating_integration_manifest.md): `"dependencies": ['nest']`. The `DEPENDENCIES` constant is deprecated.
### 3. Configuration
1. Voluptuous schema present for [configuration validation](development_validation.md)
2. Voluptuous schema extends schema from component
(e.g., `hue.light.PLATFORM_SCHEMA` extends `light.PLATFORM_SCHEMA`)
3. Default parameters specified in voluptuous schema, not in `setup_platform(...)`
4. Your `PLATFORM_SCHEMA` should use as many generic config keys as possible from `homeassistant.const`
5. Never depend on users adding things to `customize` to configure behavior inside your platform.
```python
import voluptuous as vol
from homeassistant.const import CONF_FILENAME, CONF_HOST
from homeassistant.components.light import PLATFORM_SCHEMA
import homeassistant.helpers.config_validation as cv
CONF_ALLOW_UNREACHABLE = 'allow_unreachable'
DEFAULT_UNREACHABLE = False
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_ALLOW_UNREACHABLE,
default=DEFAULT_UNREACHABLE): cv.boolean,
vol.Optional(CONF_FILENAME): cv.string,
})
```
### 4. Setup Platform
1. Verify that the passed in configuration (user/pass/host etc.) works.
2. Group your calls to `add_devices` if possible.
3. If the platform adds extra services, the format should be `<domain of your integration>.<service name>`. So if your integration's domain is "awesome_sauce" and you are making a light platform, you would register services under the `awesome_sauce` domain. Make sure that your services [verify permissions](auth_permissions.md#checking-permissions).
### 5. Entity
1. Extend the entity from the integration you're building a platform for.
```python
from homeassistant.components.light import Light
class HueLight(Light):
...
```
2. Avoid passing in `hass` as a parameter to the entity. When the entity has been added to Home Assistant, `hass` will be set on the entity when the entity is added to Home Assistant. This means you can access `hass` as `self.hass` inside the entity.
3. Do not call `update()` in constructor, use `add_entities(devices, True)` instead.
4. Do not do any I/O inside properties. Cache values inside `update()` instead.
5. When dealing with time, state and/or attributes should not contain relative time since something happened. Instead, it should store UTC timestamps.
6. Leverage the [entity lifecycle callbacks](entity_index.md#lifecycle-hooks) to attach event listeners or clean up connections.
### 6. 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()
```
[Tutorial on publishing your own PyPI package](https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/)

View File

@ -0,0 +1,7 @@
---
title: ""
---
[This page has moved.](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light)
<script>document.location = 'https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light';</script>

View File

@ -0,0 +1,7 @@
---
title: ""
---
[This page has moved.](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor)
<script>document.location = 'https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor';</script>

View File

@ -0,0 +1,21 @@
---
title: "Integration Platforms"
sidebar_label: "Platforms"
---
Home Assistant has various built-in integrations that abstract device types. There are [lights](entity_light.md), [switches](entity_switch.md), [covers](entity_cover.md), [climate devices](entity_climate.md), and [many more](entity_index.md). Your integration can hook into these integrations by creating a platform. You will need a platform for each integration that you are integrating with.
To create a platform, you will need to create a file with the domain name of the integration that you are building a platform for. So if you are building a light, you will add a new file `light.py` to your integration folder.
We have created two example integrations that should give you a look at how this works:
- [Example sensor platform](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor/): hello world of platforms.
- [Example light platform](https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light/): showing best practices.
### Interfacing with devices
One Home Assistant rule is that the integration should never interface directly with devices. Instead, it should interact with a third-party Python 3 library. This way, Home Assistant can share code with the Python community and keep the project maintainable.
Once you have your Python library ready and published to PyPI, add it to the [manifest](creating_integration_manifest.md). It will now be time to implement the Entity base class that is provided by the integration that you are creating a platform for.
Find your integration at the [entity index](entity_index.md) to see what methods and properties are available to implement.

View File

@ -0,0 +1,223 @@
---
title: Data Entry Flow
sidebar_label: Introduction
---
Data Entry Flow is a data entry framework that is part of Home Assistant. Data entry is done via data entry flows. A flow can represent a simple login form or a multi-step setup wizard for a component. A Flow Manager is managing all flows that are in progress and handles creation of new flows.
Data Entry Flow is being used in Home Assistant to create config entries.
## Flow Manager
This is the class that manages the flows that are in progress. When instantiating one, you pass in two async callbacks:
```python
async def async_create_flow(handler, context=context, data=data)
```
The manager delegates instantiating of config flow handlers to this async callback. This allows the parent of the manager to define their own way of finding handlers and preparing a handler for instantiation. For example, in the case of the config entry manager, it will make sure that the dependencies and requirements are setup.
```python
async def async_finish_flow(flow, result)
```
This async callback is called when a flow is finished or aborted. i.e. `result['type'] in [RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_ABORT]`. The callback function can modify result and return it back, if the result type changed to `RESULT_TYPE_FORM`, the flow will continue running, display another form.
If the result type is `RESULT_TYPE_FORM`, the result should like:
```python
{
# The result type of the flow
'type': RESULT_TYPE_FORM,
# the id of the flow
'flow_id': 'abcdfgh1234,
# handler name
'handler': 'hue',
# name of the step, flow.async_step_[step_id] will be called when form submitted
'step_id': 'init',
# a voluptuous schema to build and validate user input
'data_schema': vol.Schema(),
# an errors dict, None if no errors
'errors': errors,
# a detail information about the step
'description_placeholders': description_placeholders,
}
```
If the result type is `RESULT_TYPE_CREATE_ENTRY`, the result should like:
```python
{
# Data schema version of the entry
'version': 2,
# The result type of the flow
'type': RESULT_TYPE_CREATE_ENTRY,
# the id of the flow
'flow_id': 'abcdfgh1234,
# handler name
'handler': 'hue',
# title and data as created by the handler
'title': 'Some title',
'result': {
'some': 'data'
},
}
```
If the result type is `RESULT_TYPE_ABORT`, the result should like:
```python
{
# The result type of the flow
'type': RESULT_TYPE_ABORT,
# the id of the flow
'flow_id': 'abcdfgh1234,
# handler name
'handler': 'hue',
# the abort reason
'reason': 'already_configured',
}
```
## Flow Handler
Flow handlers will handle a single flow. A flow contains one or more steps. When a flow is instantiated, the `FlowHandler.init_step` step will be called. Each step has three different possible results: "Show Form", "Abort" and "Create Entry".
At a minimum, each flow handler will have to define a version number and a step. This doens't have to be `init`, as `async_create_flow` can assign `init_step` depends on diffreent workflow, for example in configuration, `context.source` will be use as `init_step`.
The bare minimum config flow:
```python
from homeassistant import data_entry_flow
@config_entries.HANDLERS.register(DOMAIN)
class ExampleConfigFlow(data_entry_flow.FlowHandler):
# The schema version of the entries that it creates
# Home Assistant will call your migrate method if the version changes
# (this is not implemented yet)
VERSION = 1
async def async_step_user(self, user_input=None):
# Do something
```
### Show Form
This result type will show a form to the user to fill in. You define the current step, the schema of the data (using voluptuous) and optionally a dictionary of errors. Title and description of the step will be provided via the translation file. Where this is defined depends on the context of the data entry flow.
```python
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_user(self, user_input=None):
# Use OrderedDict to guarantee order of the form shown to the user
data_schema = OrderedDict()
data_schema[vol.Required('username')] = str
data_schema[vol.Required('password')] = str
return self.async_show_form(
step_id='init',
data_schema=vol.Schema(data_schema)
)
```
After the user has filled in the form, the step method will be called again and the user input is passed in. Your step will only be called if the user input passes your data schema. When the user passes in data, you will have to do extra validation of the data. For example, you can verify that the passed in username and password are valid.
If something is wrong, you can return a dictionary with errors. Each key in the error dictionary refers to a field name that contains the error. Use the key `base` if you want to show an error unrelated to a specific field. The specified errors need to refer to a key in a translation file.
```python
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_user(self, user_input=None):
errors = {}
if user_input is not None:
# Validate user input
valid = await is_valid(user_input)
if valid:
# See next section on create entry usage
return self.create_entry(...)
errors['base'] = 'auth_error'
# Use OrderedDict to guarantee order of the form shown to the user
data_schema = OrderedDict()
data_schema[vol.Required('username')] = str
data_schema[vol.Required('password')] = str
return self.async_show_form(
step_id='init',
data_schema=vol.Schema(data_schema),
errors=errors
)
```
#### Multi-step flows
If the user input passes validation, you can again return one of the three return values. If you want to navigate the user to the next step, return the return value of that step:
```python
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_init(self, user_input=None):
errors = {}
if user_input is not None:
# Validate user input
valid = await is_valid(user_input)
if valid:
# Store info to use in next step
self.init_info = user_input
# Return the form of the next step
return await self.async_step_account()
...
```
### Create Entry
When the result is "Create Entry", an entry will be created and passed to the parent of the flow manager. A success message is shown to the user and the flow is finished. You create an entry by passing a title and data. The title can be used in the UI to indicate to the user which entry it is. Data can be any data type, as long as it is JSON serializable.
```python
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_user(self, user_input=None):
return self.create_entry(
title='Title of the entry',
data={
'something_special': user_input['username']
}
)
```
### Abort
When a flow cannot be finished, you need to abort it. This will finish the flow and inform the user that the flow has finished. Reasons for a flow to not be able to finish can be that a device is already configured or not compatible with Home Assistant.
```python
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_user(self, user_input=None):
return self.async_abort(
reason='not_supported'
)
```
## Translations
Data entry flows depend on translations for showing the text in the forms. It depends on the parent of a data entry flow manager where this is stored.
## Initializing a config flow from an external source
You might want to initialize a config flow programmatically. For example, if we discover a device on the network that requires user interaction to finish setup. To do so, pass a source parameter and optional user input when initializing a flow:
```python
await flow_mgr.async_init('hue', context={'source': data_entry_flow.SOURCE_DISCOVERY}, data=discovery_info)
```
The config flow handler will not start with the `init` step. Instead, it will be instantiated with a step name equal to the source. The step should follow the same return values as a normal step.
```python
class ExampleConfigFlow(data_entry_flow.FlowHandler):
async def async_step_discovery(self, info):
# Handle discovery info
```

View File

@ -0,0 +1,28 @@
---
title: "Using Config"
---
Based on where you are in the code, `config` can mean various things.
### On the hass object
On the hass object is an instance of the Config class. The Config class contains the users preferred units, the path to the config directory and which components are loaded. [See available methods.](https://dev-docs.home-assistant.io/en/master/api/core.html#homeassistant.core.Config)
### Config passed into component setup
The `config` parameter passed to a component setup is a dictionary containing all of the user supplied configuration. The keys of the dictionary are the component names and the value is another dictionary with the component configuration.
The object will have already been validated using your `CONFIG_SCHEMA` or `PLATFORM_SCHEMA` if available. If you have defined a `PLATFORM_SCHEMA`, all references to your component (ie `light 2:` etc) will have been changed to be accessible as a list under `config[DOMAIN]`.
If your configuration file contains the following lines:
```yaml
example:
host: paulusschoutsen.nl
```
Then in the setup method of your component you will be able to refer to `config['example']['host']` to get the value `paulusschoutsen.nl`.
### Passed into platform setup
The `config` parameter passed to a platform setup function is only the config for that specific platform.

View File

@ -0,0 +1,58 @@
---
title: "Using 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](https://dev-docs.home-assistant.io/en/master/api/helpers.html#module-homeassistant.helpers.event).
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.](https://www.home-assistant.io/docs/configuration/events/)
## 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.](https://dev-docs.home-assistant.io/en/master/api/helpers.html#module-homeassistant.helpers.event)

View File

@ -0,0 +1,30 @@
---
title: "Hass object"
---
While developing Home Assistant you will see a variable that is everywhere: `hass`. This is the Home Assistant instance that will give you access to all the various parts of the system.
### The `hass` object
The Home Assistant instance contains four objects to help you interact with the system.
| Object | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hass` | This is the instance of Home Assistant. Allows starting, stopping and enqueing new jobs. [See available methods.](https://dev-docs.home-assistant.io/en/master/api/core.html#homeassistant.core.HomeAssistant) |
| `hass.config` | This is the core configuration of Home Assistant exposing location, temperature preferences and config directory path. [See available methods.](https://dev-docs.home-assistant.io/en/master/api/core.html#homeassistant.core.Config) |
| `hass.states` | This is the StateMachine. It allows you to set states and track when they are changed. [See available methods.](https://dev-docs.home-assistant.io/en/master/api/core.html#homeassistant.core.StateMachine) |
| `hass.bus` | This is the EventBus. It allows you to trigger and listen for events. [See available methods.](https://dev-docs.home-assistant.io/en/master/api/core.html#homeassistant.core.EventBus) |
| `hass.services` | This is the ServiceRegistry. It allows you to register services. [See available methods.](https://dev-docs.home-assistant.io/en/master/api/core.html#homeassistant.core.ServiceRegistry) |
### Where to find `hass`
Depending on what you're writing, there are different ways the `hass` object is made available.
**Component**
Passed into `setup(hass, config)` or `async_setup(hass, config)`.
**Platform**
Passed into `setup_platform(hass, config, add_devices, discovery_info=None)` or `async_setup_platform(hass, config, async_add_devices, discovery_info=None)`.
**Entity**
Available as `self.hass` once the entity has been added via the `add_devices` callback inside a platform.

View File

@ -0,0 +1,44 @@
---
title: "Development 101"
sidebar_label: Introduction
---
The goal of development 101 is to get you familiar with the basics of developing for Home Assistant. Before we start, please make sure you familiarize yourself with the [architecture](architecture_index.md).
To get our code running inside Home Assistant we're going to create a custom component. The first step is to locate your config folder. You can find the path to your config folder by opening the Home Assistant frontend, click on the <img src='/img/dev-tools/about-icon.png' alt='service developer tool icon' class="inline" width="38" />. It's the path after the text "Path to configuration.yaml".
Inside your configuration directory create a new folder called `custom_components`. It might be that one already exists, that's fine too. This is the folder that Home Assistant will look at when looking for custom code.
> The Home Assistant API has two variants: a synchronous and an asynchronous version (asyncio). This development course will focus on the synchronous version.
To verify that everything is working correctly, let's create a small Hello World component. To do so, create a file called `hello_world.py` in your custom components folder. Copy paste the following content to it:
```python
# The domain of your component. Equal to the filename of your component.
DOMAIN = "hello_world"
def setup(hass, config):
"""Setup the hello_world component."""
# States are in the format DOMAIN.OBJECT_ID.
hass.states.set('hello_world.Hello_World', 'Works!')
# Return boolean to indicate that initialization was successfully.
return True
```
Last step is to add `hello_world:` entry to your `configuration.yaml` file.
```yaml
# Hello World component
hello_world:
```
After running `hass`, we should see log entries stating that `hello_world` component was loaded. What is more, additional state card shall appear within main panel.
```log
2018-04-03 21:44:20 INFO (MainThread) [homeassistant.loader] Loaded hello_world from custom_components.hello_world
2018-04-03 21:44:20 INFO (MainThread) [homeassistant.setup] Setting up hello_world
```
![State card showing that Hello World component is working as intended.](/img/en/frontend/hello-world-state-card.png)

View File

@ -0,0 +1,76 @@
---
title: "Integration Services"
sidebar_label: "Custom Services"
---
Home Assistant provides ready-made services for a lot of things, but it doesn't always cover everything. Instead of trying to change Home Assistant, it is preferred to add it as a service under your own integration first. Once we see a pattern in these services, we can talk about generalizing them.
This is a simple "hello world" example to show the basics of registering a service. To use this example, create the file `<config dir>/custom_components/hello_service/__init__.py` and copy the below example code.
Services can be called from automations and from the service "Developer tools" in the frontend.
```python
DOMAIN = 'hello_service'
ATTR_NAME = 'name'
DEFAULT_NAME = 'World'
def setup(hass, config):
"""Set up is called when Home Assistant is loading our component."""
def handle_hello(call):
"""Handle the service call."""
name = call.data.get(ATTR_NAME, DEFAULT_NAME)
hass.states.set('hello_service.hello', name)
hass.services.register(DOMAIN, 'hello', handle_hello)
# Return boolean to indicate that initialization was successfully.
return True
```
Load the integration by adding the following to your `configuration.yaml`. When your component is loaded, a new service should be available to call.
```yaml
# configuration.yaml entry
hello_service:
```
Open the frontend and in the sidebar, click the first icon in the developer tool section. This will open the Call Service developer tool. On the right, find your service and click on it. This will automatically fill in the correct values.
Pressing "Call Service" will now call your service without any parameters. This will cause your service to create a state with the default name 'World'. If you want to specify the name, you have to specify parameters. Add the following JSON as Service Data and press "Call Service again".
```json
{
"name": "Planet"
}
```
The service will now overwrite the previous state with "Planet".
## Service descriptions
Adding services is only useful if users know about them. In Home Assistant we use a `services.yaml` as part of your integration to describe the services.
Services are published under the domain name of your integration, so in `services.yaml` we only use the service name as the base key.
```yaml
# Example services.yaml entry
set_speed:
# Description of the service
description: Sets fan speed.
# Different fields that your service accepts
fields:
# Key of the field
entity_id:
# Description of the field
description: Name(s) of the entities to set
# Example value that can be passed for this field
example: 'fan.living_room'
speed:
description: Speed setting
example: 'low'
```

View File

@ -0,0 +1,126 @@
---
title: "Using States"
---
Home Assistant keeps track of the states of entities in a state machine. The state machine has very few requirements:
- Each state is related to an entity identified by an entity id. This id is made up of a domain and an object id. For example `light.kitchen_ceiling`. You can make up any combination of domain and object id, even overwriting existing states.
- Each state has a primary attribute that describes the state of the entity. In the case of a light this could be for example "on" and "off". You can store anything you want in the state, as long as it's a string (will be converted if it's not).
- You can store more information about an entity by setting attributes. Attributes is a dictionary that can contain any data that you want. The only requirement is that it's JSON serializable, so you're limited to numbers, strings, dictionaries and lists.
[Description of the state object.](https://www.home-assistant.io/docs/configuration/state_object/)
## Using states in your component
This is a simple tutorial/example on how to create and set states. We will do our work in a component called "hello_state". The purpose of this component is to display a given text in the frontend.
To get started, create the file `<config dir>/custom_components/hello_state.py` and copy the below example code.
```python
"""
Support for showing text in the frontend.
For more details about this component, please refer to the documentation at
https://home-assistant.io/cookbook/python_component_basic_state/
"""
import logging
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'hello_state'
def setup(hass, config):
"""Setup the Hello State component. """
_LOGGER.info("The 'hello state' component is ready!")
return True
```
1. In the file header we decided to add some details: A short description and the link to the documentation.
2. We want to do some logging. This means that we import the Python logging module and create an alias.
3. The component name is equal to the domain name.
4. The `setup` function will take care of the initialization of our component. The component will only write a log message. Keep in mind for later that you have several options for the severity:
- `_LOGGER.info(msg)`
- `_LOGGER.warning(msg)`
- `_LOGGER.error(msg)`
- `_LOGGER.critical(msg)`
- `_LOGGER.exception(msg)`
5. We return `True` if everything is ok.
Add the component to your `configuration.yaml` file.
```yaml
hello_state:
```
After a start or a restart of Home Assistant the component will create an entry in the log.
```bash
16-03-12 14:16:42 INFO (MainThread) [custom_components.hello_state] The 'hello state' component is ready!
```
The next step is the introduction of configuration options. A user can pass configuration options to our component via `configuration.yaml`. To use them we'll use the passed in `config` variable to our `setup` method.
```python
import logging
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'hello_state'
CONF_TEXT = 'text'
DEFAULT_TEXT = 'No text!'
def setup(hass, config):
"""Set up the Hello State component. """
# Get the text from the configuration. Use DEFAULT_TEXT if no name is provided.
text = config[DOMAIN].get(CONF_TEXT, DEFAULT_TEXT)
# States are in the format DOMAIN.OBJECT_ID
hass.states.set('hello_state.Hello_State', text)
return True
```
To use the latest feature of our component, update the entry in your `configuration.yaml` file.
```yaml
hello_state:
text: 'Hello, World!'
```
Thanks to `DEFAULT_TEXT` variable the component will launch even if no `text:` field is used in the `configuration.yaml` file. Quite often there are variables which are required. It's important to check if all mandatory configuration variables are provided. If not, the setup should fail. We will use `voluptuous` as a helper to achieve this. The next listing shows the essential parts.
```python
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_TEXT): cv.string,
})
}, extra=vol.ALLOW_EXTRA)
```
Now, when `text:` is missing from the config, Home Assistant will alert the user and not setup your component.
After a start or a restart of Home Assistant the component will be visible in the frontend if the `configuration.yaml` file is up-to-date.
<p class='img'>
<img src='/img/en/development/create-component01.png' />
</p>
In order to expose attributes for a platform, you will need to define a property called `device_state_attributes` on the entity class, which will return a dictionary of attributes:
@property
def device_state_attributes(self):
"""Return device specific state attributes."""
return self._attributes
> Entities also have a similar property `state_attributes`, which normally doesn't need to be defined by new platforms. This property is used by base components to add standard sets of attributes to a state. Example: The light component uses `state_attributes` to add brightness to the state dictionary. If you are designing a new component, you should define `state_attributes` instead.
To get your component included in the Home Assistant releases, follow the steps described in the [Submit your work](development_submitting.md) section. Basically you only need to move your component in the `homeassistant/component/` directory of your fork and create a Pull Request.

View File

@ -0,0 +1,35 @@
---
title: "Catching up with Reality"
---
If it's taking a while to develop your feature, and you want to catch up with what's in the current Home Assistant `dev` branch, you can use `git rebase`. This will pull the latest Home Assistant changes locally, rewind your commits, bring in the latest changes from Home Assistant, and replay all of your commits on top.
> If you use the workflow below, it is important that you force push the update as described. Git might prompt you to do `git pull` first. Do **NOT** do that! It would mess up your commit history.
```bash
# Run this from your feature branch
$ git fetch upstream dev # to pull the latest changes into a local dev branch
$ git rebase upstream/dev # to put those changes into your feature branch before your changes
```
If rebase detects conflicts, repeat this process until all changes have been resolved:
1. `git status` shows you the file with the conflict; edit the file and resolve the lines between `<<<< | >>>>`
2. Add the modified file: `git add <file>` or `git add .`
3. Continue rebase: `git rebase --continue`
4. Repeat until you've resolved all conflicts
After rebasing your branch, you will have rewritten history relative to your GitHub fork's branch. When you go to push you will see an error that your history has diverged from the original branch. In order to get your GitHub fork up-to-date with your local branch, you will need to force push, using the following command:
```bash
# Run this from your feature branch
$ git push origin --force
```
Other workflows are covered in detail in the [Github documentation](https://help.github.com/articles/fork-a-repo/). Add an additional `remote` after you clone your fork.
```bash
$ git remote add upstream https://github.com/home-assistant/home-assistant.git
```
Then, `git pull --rebase upstream dev`.

View File

@ -0,0 +1,14 @@
---
title: "Development Checklist"
sidebar_label: Introduction
---
Before you commit any changes, check your work against these requirements:
- All communication to external devices or services must be wrapped in an external Python library hosted on [pypi](https://pypi.python.org/pypi).
- New dependencies are added to `requirements_all.txt` (if applicable), using `python3 -m script.gen_requirements_all`
- New codeowners are added to `CODEOWNERS` (if applicable), using `python3 -m script.hassfest`
- The `.coveragerc` file is updated to exclude your platform if there are no tests available or your new code uses a third-party library for communication with the device, service, or sensor
- Documentation is developed for [home-assistant.io](https://home-assistant.io/)
- Visit the [website documentation](https://www.home-assistant.io/developers/documentation/) for more information about contributing to [home-assistant.io](https://github.com/home-assistant/home-assistant.github.io).

View File

@ -0,0 +1,117 @@
---
title: "Set up Development Environment"
---
You'll need to set up a development environment if you want to develop a new feature or component for Home Assistant. Read on to learn how to set up.
## Preparing your environment
### Developing on Linux
Install the core dependencies.
```bash
$ sudo apt-get install python3-pip python3-dev python3-venv
```
In order to run `script/setup` below you will need some more dependencies.
```bash
$ sudo apt-get install autoconf libssl-dev libxml2-dev libxslt1-dev libjpeg-dev libffi-dev libudev-dev zlib1g-dev
$ sudo apt-get install -y libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libavresample-dev libavfilter-dev
```
> Different distributions have different package installation mechanisms and sometimes packages names as well. For example CentOS would use: `sudo yum install epel-release && sudo yum install python36 python36-devel mysql-devel gcc`
Additional dependencies exist if you plan to perform Frontend Development, please read the [Frontend](frontend_index.md) section to learn more.
### Developing on Windows
Due to Home Assistant is mainly designed and developed on Linux distributions, on Windows 10 you can setup a [Linux subsystem](https://docs.microsoft.com/windows/wsl/install-win10).
Open Powershell as an Administrator and run
```bash
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
```
From Windows Store install Ubuntu.
When the Linux subsystem is set up, perform install as for Linux.
```bash
$ sudo apt-get update
$ sudo apt-get install python3-pip python3-dev python3-venv
$ sudo apt-get install autoconf libssl-dev libxml2-dev libxslt1-dev libjpeg-dev libffi-dev libudev-dev zlib1g-dev
$ sudo apt-get install -y libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libavresample-dev libavfilter-dev
```
Hint: Git is included in Linux subsytem.
When invoking your installation (see below), make sure to specify a folder for configuration which is accessible from Windows.
```bash
$ mkdir -p ../config
$ hass -c ../config
```
### Developing on OS X
Install [Homebrew](https://brew.sh/), then use that to install Python 3:
```bash
$ brew install python3 autoconf
```
Then install ffmpeg:
```bash
$ brew install ffmpeg
```
## Setup Local Repository
Visit the [Home Assistant repository](https://github.com/home-assistant/home-assistant) and click **Fork**. Once forked, setup your local copy of the source using the commands:
```bash
$ git clone https://github.com/YOUR_GIT_USERNAME/home-assistant.git
$ cd home-assistant
$ git remote add upstream https://github.com/home-assistant/home-assistant.git
```
## Setting up virtual environment
To isolate your environment from the rest of the system, set up a [`venv`](https://docs.python.org/3/library/venv.html). Within the `home-assistant` directory, create and activate your virtual environment.
```bash
$ python3 -m venv venv
$ source venv/bin/activate
```
Install the requirements with a provided script named `setup`.
```bash
$ script/setup
```
Invoke your installation, adjusting the [configuration](https://www.home-assistant.io/docs/configuration/) if required.
```bash
$ hass
```
## Logging
By default logging in Home Assistant is tuned for operating in production (set to INFO by default, with some modules set to even less verbose logging levels).
You can use the [logger](https://www.home-assistant.io/components/logger/) component to adjust logging to DEBUG to see even more details about what is going on:
```yaml
logger:
default: info
logs:
homeassistant.core: debug
nest.nest: debug
asyncio: debug
homeassistant.components.cloud.iot: debug
```

View File

@ -0,0 +1,81 @@
---
title: "Style guidelines"
---
Home Assistant enforces strict [PEP8 style](https://www.python.org/dev/peps/pep-0008/) and [PEP 257 (Docstring Conventions)](https://www.python.org/dev/peps/pep-0257/) compliance on all code submitted. We automatically test every pull request as part of the linting process.
Summary of the most relevant points:
- Line length is limited to 79 characters (see below).
- Use 4 spaces per indentation level. We don't use tabs.
- Comments should be full sentences and end with a period.
- [Imports](https://www.python.org/dev/peps/pep-0008/#imports) should be ordered.
- Constants and the content of lists and dictionaries should be in alphabetical order.
- Avoid trailing whitespace but surround binary operators with a single space.
- Line separator should be set to `LF`.
The maximum line length comes directly from the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/#maximum-line-length), and is also used by the Python standard library. All code must pass these linting checks, and no exceptions will be made. There have already been numerous requests to increase the maximum line length, but after evaluating the options, the Home Assistant maintainers have decided to stay at 79 characters. This decision is final.
Those points may require that you adjust your IDE or editor settings.
## Our recommendations
For some cases [PEPs](https://www.python.org/dev/peps/) don't make a statement. This section covers our recommendations about the code style. Those points were collected from the existing code and based on what contributors and developers were using the most. This is basically a majority decision, thus you may not agree with it. But we would like to encourage you follow those recommendations to keep the code unified.
### Quotes
Use single quotes `'` for single word and `"` for multiple words or sentences.
```python
ATTR_WATERLEVEL = 'level'
CONF_ATTRIBUTION = "Data provided by the WUnderground weather service"
SENSOR_TYPES = {
'alerts': ['Alerts', None],
}
```
### File headers
The docstring in the file header should describe what the file is about.
```python
"""Support for MQTT lights."""
```
### Log messages
There is no need to add the platform or component name to the log messages. This will be added automatically. Like `syslog` messages there shouldn't be any period at the end. Try to avoid brackets and additional quotes around the output to make it easier for users to parse the log. A widely style is shown below but you are free to compose the messages as you like.
```python
_LOGGER.error("No route to device: %s", self._resource)
```
```bash
2017-05-01 14:28:07 ERROR [homeassistant.components.sensor.arest] No route to device: 192.168.0.18
```
Don't print out wrong API keys, tokens, usernames, or passwords. Also note that `_LOGGER.info` is reserved for the core, use `_LOGGER.debug` in anything else.
### Ordering of imports
Instead of order the imports manually, use [`isort`](https://github.com/timothycrosley/isort).
```bash
$ pip3 install isort
$ isort homeassistant/components/sensor/fixer.py
```
### Use new style string formatting
Prefer [new style string formatting](https://www.python.org/dev/peps/pep-3101/) over old.
```python
"{} {}".format('New', 'style')
"%s %s" % ('Old', 'style')
```
Except when doing logging here the format is:
```python
_LOGGER.info("Can't connect to the webservice %s at %s", string1, string2)
```

View File

@ -0,0 +1,10 @@
---
title: "Starting with Development"
sidebar_label: Introduction
---
Home Assistant is built from the ground up to be easily extensible using integrations. In this section, we're focusing on how to develop integrations.
Before you start, make sure that you have read up on the [Home Assistant architecture](architecture_index.md) so that you are familiar with the concepts that make up Home Assistant.
If you run into trouble following this documentation, don't hesitate to join our #devs_backend channel on [Discord](https://www.home-assistant.io/join-chat/).

View File

@ -0,0 +1,41 @@
---
title: "Submit your work"
---
> Always base your Pull Requests of of the current **`dev`** branch, not `master`.
Submit your improvements, fixes, and new features to Home Assistant one at a time, using GitHub [Pull Requests](https://help.github.com/articles/using-pull-requests). Here are the steps:
1. From your fork's dev branch, create a new branch to hold your changes:
`git checkout -b some-feature`
2. Make your changes, create a [new platform](creating_platform_index.md), develop a [new component](creating_component_index.md), or fix [issues](https://github.com/home-assistant/home-assistant/issues).
3. [Test your changes](development_testing.md) and check for style violations.
4. If everything looks good according to these [musts](development_checklist.md), commit your changes:
`git add .`
`git commit -m "Add some-feature"`
- Write a meaningful commit message and not only `Update` or `Fix`.
- Use a capital letter to start with your commit message.
- Don't prefix your commit message with `[bla.bla]` or `platform:`.
- Consider adding tests to ensure that your code works.
5. Push your committed changes back to your fork on GitHub:
`git push origin HEAD`
6. Follow [these steps](https://help.github.com/articles/creating-a-pull-request/) to create your pull request.
- On GitHub, navigate to the main page of the Home Assistant repository.
- In the "Branch" menu, choose the branch that contains your commits (from your fork).
- To the right of the Branch menu, click **New pull request**.
- Use the base branch dropdown menu to select the branch you'd like to merge your changes into, then use the compare branch drop-down menu to choose the topic branch you made your changes in. Make sure the Home Assistant branch matches with your forked branch (`dev`) else you will propose ALL commits between branches.
- Type a title and complete the provided description for your pull request.
- Click **Create pull request**.
7. Check for comments and suggestions on your pull request and keep an eye on the [CI output](https://travis-ci.org/home-assistant/home-assistant/).

View File

@ -0,0 +1,79 @@
---
title: "Testing your code"
---
As it states in the [Style guidelines section](development_guidelines.md) all code is checked to verify the following:
- All the unit tests pass
- All code passes the checks from the linting tools
Local testing is done using Tox, which has been installed as part of running `script/setup` in the [virtual environment](development_environment.md). To start the tests, activate the virtual environment and simply run the command:
```bash
$ tox
```
**Important:** Run `tox` before you create your pull request to avoid annoying fixes.
Running Tox will run unit tests against the locally available Pythons, as well as validate the code and document style using `pycodestyle`, `pydocstyle` and `pylint`. You can run tests on only one tox target -- just use `-e` to select an environment. For example, `tox -e lint` runs the linters only, and `tox -e py36` runs unit tests only on Python 3.6.
Tox uses virtual environments under the hood to create isolated testing environments. The tox virtual environments will get out-of-date when requirements change, causing test errors. Run `tox -r` to tell Tox to recreate the virtual environments.
OSX users may see an `Error creating virtualenv` when runnng `tox`. If this occurs, install the [tox-venv](https://pypi.org/project/tox-venv/) package using the command `pip install tox-venv` and try again.
### Adding new dependencies to test environment
If you are working on tests for a component or platform and you need the dependencies available inside the Tox environment, update the list inside `script/gen_requirements_all.py`. Then run the script and then run `tox -r` to recreate the virtual environments.
### Running single tests using Tox
You can pass arguments via Tox to py.test to be able to run single test suites or test files. Replace `py36` with the Python version that you use.
```bash
# Stop after the first test fails
$ tox -e py36 -- tests/test_core.py -x
# Run test with specified name
$ tox -e py36 -- tests/test_core.py -k test_split_entity_id
# Fail a test after it runs for 2 seconds
$ tox -e py36 -- tests/test_core.py --timeout 2
# Show the 10 slowest tests
$ tox -e py36 -- tests/test_core.py --duration=10
```
### Testing outside of Tox
Running tox will invoke the full test suite. Even if you specify which tox target to run, you still run all tests inside that target. That's not very convenient to quickly iterate on your code! To be able to run the specific test suites without Tox, you'll need to install the test dependencies into your Python environment:
```bash
$ pip3 install -r requirements_test_all.txt -c homeassistant/package_constraints.txt
```
Now that you have all test dependencies installed, you can run tests on individual files:
```bash
$ flake8 homeassistant/core.py
$ pylint homeassistant/core.py
$ pydocstyle homeassistant/core.py
$ py.test tests/test_core.py
```
You can also run linting tests against all changed files, as reported by `git diff upstream/dev... --diff-filter=d --name-only`, using the `lint` script:
```bash
$ script/lint
```
### Preventing Linter Errors
Save yourself the hassle of extra commits just to fix style errors by enabling the Flake8 git commit hook. Flake8 will check your code when you try to commit to the repository and block the commit if there are any style errors, which gives you a chance to fix them!
```bash
$ pip3 install flake8 flake8-docstrings
$ flake8 --install-hook=git
```
The `flake8-docstrings` extension will check docstrings according to [PEP257](https://www.python.org/dev/peps/pep-0257/) when running Flake8.
### Notes on PyLint and PEP8 validation
If you can't avoid a PyLint warning, add a comment to disable the PyLint check for that line with `# pylint: disable=YOUR-ERROR-NAME`. Example of an unavoidable one is if PyLint incorrectly reports that a certain object doesn't have a certain member.

View File

@ -0,0 +1,23 @@
---
title: "Adding type hints to your code"
---
Type hints in Python are static annotations of variables and functions, to let humans more easily understand the code. See the standard library [docs](https://docs.python.org/3/library/typing.html) and this PyCascades 2018 [talk](https://youtu.be/zKre4DKAB30).
Type hints are not required for all modules at the moment in Home Assistant, but we aim to have complete coverage of the core modules.
Adding type hints to an existing codebase can be a daunting task. To speed this up and help developers doing this, Instagram made the [`monkeytype`](https://pypi.org/project/MonkeyType/) program. It will analyze calls during runtime and try to assign the correct type hints to the code.
See [this instagram blog post](https://instagram-engineering.com/let-your-code-type-hint-itself-introducing-open-source-monkeytype-a855c7284881) for a description of the workflow involved to use the monkeytype program.
We've added a script to start a run of our test suite or a test module and tell the `monkeytype` program to analyze the run.
### Basic workflow
1. Run `script/monkeytype tests/path/to/your_test_module.py`.
2. Run `monkeytype stub homeassistant.your_actual_module`.
3. Look at output from the monkeytyped typing stub. If not totally bad, apply the stub to your module. You most likely will need to manually edit the typing in the last step.
4. Run `monkeytype apply homeassistant.your_actual_module`.
5. Check the diff and manually correct the typing if needed. Commit, push the branch and make a PR.
**Note:** Applying a monkeytyped stub to a module that has existing typing annotations might error and not work. This tool is most useful for totally untyped modules.

View File

@ -0,0 +1,80 @@
---
title: "Validate the input"
---
The `configuration.yaml` file contains the configuration options for components and platforms. We use [voluptuous](https://pypi.python.org/pypi/voluptuous) to make sure that the configuration provided by the user is valid. Some entries are optional or could be required to set up a platform or a component. Others must be a defined type or from an already-defined list.
We test the configuration to ensure that users have a great experience and minimize notifications if something is wrong with a platform or component setup before Home Assistant runs.
Besides [voluptuous](https://pypi.python.org/pypi/voluptuous) default types, many custom types are available. For an overview, take a look at the [config_validation.py](https://github.com/home-assistant/home-assistant/blob/master/homeassistant/helpers/config_validation.py) helper.
- Types: `string`, `byte`, and `boolean`
- Entity ID: `entity_id` and `entity_ids`
- Numbers: `small_float` and `positive_int`
- Time: `time`, `time_zone`
- Misc: `template`, `slug`, `temperature_unit`, `latitude`, `longitude`, `isfile`, `sun_event`, `ensure_list`, `port`, `url`, and `icon`
To validate platforms using [MQTT](https://www.home-assistant.io/components/mqtt/), `valid_subscribe_topic` and `valid_publish_topic` are available.
Some things to keep in mind:
- Use the constants defined in `const.py`
- Import `PLATFORM_SCHEMA` from the integration you are integrating with and extend it.
- Preferred order is `required` first and `optional` second
- Default values for optional configuration keys need to be valid values. Don't use a default which is `None` like `vol.Optional(CONF_SOMETHING, default=None): cv.string`, set the default to `default=''` if required.
### Snippets
This section contains snippets for the validation we use.
#### Default name
It's common to set a default for a sensor if the user doesn't provide a name to use.
```python
DEFAULT_NAME = 'Sensor name'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
```
#### Limit the values
You might want to limit the user's input to a couple of options.
```python
DEFAULT_METHOD = 'GET'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']),
```
#### Port
All port numbers are from a range of 1 to 65535.
```python
DEFAULT_PORT = 993
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
```
#### Lists
If a sensor has a pre-defined list of available options, test to make sure the configuration entry matches the list.
```python
SENSOR_TYPES = {
'article_cache': ('Article Cache', 'MB'),
'average_download_rate': ('Average Speed', 'MB/s'),
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
...
vol.Optional(CONF_MONITORED_VARIABLES, default=[]):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
```

View File

@ -0,0 +1,80 @@
---
title: Device Registry
sidebar_label: Introduction
---
The device registry is a registry where Home Assistant keeps track of devices. A device is represented in Home Assistant via one or more entities. For example, a battery-powered temperature and a humidity sensor might expose entities for temperature, humidity and battery level.
![Device registry overview](/img/en/device_registry/overview.png)
## What is a device?
A device in Home Assistant represents a physical device that has its own control unit. The control unit itself does not have to be smart, but it should be in control of what happens. For example, an Ecobee thermostat with 4 room sensors equals 5 devices in Home Assistant, one for the thermostat including all sensors inside it, and one for each sensor.
If you connect a sensor to another device to read some of its data, it should still be represented as two different devices. The reason for this is that the sensor could be moved to read the data of another device.
> Although not currently available, we could consider offering an option to users to merge devices.
## Device properties
| Attribute | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | Unique ID of device (generated by Home Assistant) |
| name | Name of this device |
| connections | A set of tuples of `(connection_type, connection identifier)`. Connection types are defined in the device registry module. |
| identifiers | Set of identifiers. They identify the device in the outside world. An example is a serial number. |
| manufacturer | The manufacturer of the device. |
| model | The model of the device. |
| config_entries | Config entries that are linked to this device. |
| sw_version | The firmware version of the device. |
| via_hub | Identifier of a device that routes messages between this device and Home Assistant. Examples of such devices are hubs. This is used to show device topology in Home Assistant. |
| area_id | The Area which the device is placed in. |
## Defining devices
> Entity device info is only read if the entity is loaded via a [config entry](config_entries_index.md).
Each entity is able to define a device via the `device_info` property. This property is read when an entity is added to Home Assistant via a config entry. A device will be matched up with an existing device via supplied identifiers and connections, like serial numbers or MAC addresses.
```python
# Inside a platform
class HueLight(LightEntity):
@property
def device_info(self):
return {
'identifiers': {
# Serial numbers are unique identifiers within a specific domain
(hue.DOMAIN, self.unique_id)
},
'name': self.name,
'manufacturer': self.light.manufacturername,
'model': self.light.productname,
'sw_version': self.light.swversion,
'via_hub': (hue.DOMAIN, self.api.bridgeid),
}
```
Components are also able to register devices in the case that there are no entities representing them. An example is a hub that communicates with the lights.
```python
# Inside a component
from homeassistant.helpers import device_registry as dr
device_registry = await dr.async_get_registry(hass)
device_registry.async_get_or_create(
config_entry=entry.entry_id,
connections={
(dr.CONNECTION_NETWORK_MAC, config.mac)
},
identifiers={
(DOMAIN, config.bridgeid)
},
manufacturer='Signify',
name=config.name,
model=config.modelid,
sw_version=config.swversion,
)
```

View File

@ -0,0 +1,132 @@
---
title: "Create a new page"
---
For a platform or component page, the fastest way is to make a copy of an existing page and edit it. The [Component overview](https://www.home-assistant.io/components/) and the [Examples section](https://www.home-assistant.io/cookbook/) are generated automatically, so there is no need to add a link to those pages.
Please honor the [Standards](documentation_standards.md) we have for the documentation.
If you start from scratch with a page, you need to add a header. Different sections of the documentation may need different headers.
```text
---
layout: page
title: "Awesome Sensor"
description: "home-assistant.io web presence"
date: 2015-06-17 08:00
sidebar: true
comments: false
sharing: true
footer: true
ha_release: "0.38"
ha_category: Sensor
ha_iot_class: "Local Polling"
ha_qa_scale: silver
---
Content... Written in markdown.
### {% linkable_title Linkable Header %}
...
```
Please keep in mind that if the `date:` entry is in the future then the page will not show up.
Additional keys for the file header:
- `logo`: Please check the separate section below.
- `ha_release`: The release when the integration was included, e.g., "0.38". If the current release is 0.37, make `ha_release` 0.38. If it's 0.30 or 0.40 please quote it with `" "`.
- `ha_category`: This entry is used to group the integration on the [Components overview](https://www.home-assistant.io/components/).
- `ha_iot_class`: [IoT class](https://www.home-assistant.io/blog/2016/02/12/classifying-the-internet-of-things) is the classifier for the device's behavior.
- `ha_qa_scale`: [Quality scale](https://www.home-assistant.io/docs/quality_scale/) is the representation of the integration's quality.
There are [pre-defined variables](https://jekyllrb.com/docs/variables/) available but usually, it's not necessary to use them when writing documentation.
A couple of points to remember:
- Document the needed steps to retrieve API keys or access token for the third party service or device if needed.
- Add screenshots to support the user where it makes sense.
- Add the type of the device(s) (incl. firmware) you have tested when you know that there are multiple out there.
### Configuration
Every platform page should contain a configuration sample. This sample must contain only the **required** variables to make it easy to copy and paste it for users into their `configuration.yaml` file.
The **Configuration Variables** section must use the `{% configuration %} ... {% endconfiguration %}` tag.
```text
{% configuration %}
api_key:
description: The API key to access the service.
required: true
type: string
name:
description: Name to use in the frontend.
required: false
default: The default name to use in the frontend.
type: string
monitored_conditions:
description: Conditions to display in the frontend.
required: true
type: map
keys:
weather:
description: A human-readable text summary.
temperature:
description: The current temperature.
{% endconfiguration %}
```
Available keys:
- **`description:`**: That the variable is about.
- **`required:`**: If the variable is required.
```text
required: true #=> Required
required: false #=> Optional
required: inclusive #=> Inclusive
required: exclusive #=> Exclusive
required: any string here #=> Any string here
```
- **`type:`**: The type of the variable. Allowed entries: `boolean`, `string`, `integer`, `float`, `time`, `template`, `device_class`, `icon` or `map`/`list` (for a list of entries). For multiple possibilities use `[string, integer]`. If you use `map`/`list` then should define `keys:` (see the [`template` sensor](https://www.home-assistant.io/components/sensor.template/) for an example). If you use `boolean`, then `default:` must be defined.
- **`default:`**: The default value for the variable.
### Embedding Code
You can use the [default markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code) to generate syntax highlighted code. For inline code wrap your code in back-ticks.
When you're writing code that is to be executed on the terminal, prefix it with `$`.
### Templates
For the [configuration templating](https://www.home-assistant.io/docs/configuration/templating/) [Jinja](http://jinja.pocoo.org/) is used. Check the [Documentation Standards](documentation_standards.md) for further details.
If you are don't escape templates then they will be rendered and appear blank on the website.
### HTML
The direct usage of HTML is supported but not recommended. The note boxes are an exception.
```html
<p class='note warning'>
You need to enable telnet on your router.
</p>
```
### Images, icons and logos
The images which are displayed on the pages are stored in various directories according to their purpose. If you want to use a logo and placed `logo:` in the file header then this image should be stored in `source/images/supported_brands`. The background must be transparent.
| Type | Location |
|:----------- |:------------------------------ |
| logos | source/images/supported_brands |
| blog | source/images/blog |
| screenshots | source/images/components |
Not everything (product, component, etc.) should have a logo. To show something for internal parts of Home Assistant we are using the [Material Design Icons](https://materialdesignicons.com/).
### Linking From The Sidebar
If you are adding a new page that requires linking from the sidebar, you need to edit the `docs_navigation.html` file in `source/_includes/asides/docs_navigation.html`.

View File

@ -0,0 +1,52 @@
---
title: "Documentation"
---
The user documentation is located at <https://www.home-assistant.io>. This section here is the place where we provide documentation and additional details about creating or modifying content.
The [home-assistant.io](https://home-assistant.io) website is built using [Jekyll](http://github.com/mojombo/jekyll) and [these dependencies](https://pages.github.com/versions/). The pages are written in [Markdown](http://daringfireball.net/projects/markdown/). To add a page, you don't need to know HTML.
You can use the "**Edit this page on GitHub**" link to edit pages without creating a fork. Keep in mind that you can't upload images while working this way. You work on your change and propose it via a Pull Request (PR).
Once you've created a Pull Request (PR), you can see a preview of the proposed changes by clicking *Details* against Netlify checker in the checkers section of the PR as soon as deployment is complete.
For larger changes, we suggest that you clone the website repository. This way, you can review your changes locally. The process of working on the website is no different from working on Home Assistant itself.
To test your changes locally, you need to install **Ruby** and its dependencies (gems):
- [Install Ruby](https://www.ruby-lang.org/en/documentation/installation/) if you don't have it already. Ruby version 2.3.0 or higher is required.
- Install `bundler`, a dependency manager for Ruby: `$ gem install bundler` (You might have to run this command as `sudo`).
- Fork the home-assistant.io [git repository](https://github.com/home-assistant/home-assistant.io).
- In your home-assistant.io root directory, run `$ bundle` to install the gems you need.
- Shortcut for Fedora: `$ sudo dnf -y install gcc-c++ ruby ruby-devel rubygem-bundler rubygem-json && bundle`
- Shortcut for Debian/Ubuntu: `$ sudo apt-get install ruby ruby-dev ruby-bundler ruby-json g++ zlib1g-dev && bundle`
Then you can work on the documentation:
- Run `bundle exec rake generate` to generate the very first preview. This will take a couple of minutes.
- Create/edit/update a page. The components/platforms documentation is located in `source/_components/`. `source/_docs/` contains the Home Assistant documentation itself.
- Test your changes to home-assistant.io locally: run `bundle exec rake preview` and navigate to <http://127.0.0.1:4000>. While this command is working, any changes to a file are automatically detected and will update the affected pages. You will have to manually reload them in the browser though.
- Create a Pull Request (PR) against the **next** branch of home-assistant.io if your documentation is a new feature, platform, or component.
- Create a Pull Request (PR) against the **current** branch of home-assistant.io if you fix stuff, create Cookbook entries, or expand existing documentation.
The site generated by `bundle exec rake` is only available locally. If you are developing on a headless machine, use port forwarding:
```bash
$ ssh -L 4000:localhost:4000 user_on_headless_machine@ip_of_headless_machine
```
## Speeding up site generation
Every release we post long changelogs to the website. This slows down generation of the website significantly! We include some tools to temporarily exclude components and blog posts that you're not working on out of the way.
```bash
bundle exec rake isolate[filename-of-blogpost-or-component]
```
When you're done working on the site, run the following command to move the pages back again:
```bash
bundle exec rake integrate
```

View File

@ -0,0 +1,122 @@
---
title: "Standards"
---
To ensure that the documentation for Home Assistant is consistent and easy to follow for both novice and expert users, we ask that you follow a very strict set of standards for developing the documentation.
## General Documentation
* The language of the documentation should be American-English.
* Don't put two spaces after a period and avoid the "Oxford comma".
* There is no limit for the line length. You are allowed to write in a flowing text style. This will make it easier to use the GitHub online editor in the future.
* Be objective and not gender favoring, polarizing, race related or religion inconsiderate.
* The case of brand names, services, protocols, components and platforms must match its respective counterpart. e.g., "Z-Wave" **not** "Zwave", "Z-wave", "Z Wave" or "ZWave". Also, "Input Select" **not** "input select" or "Input select".
* All headings should use the `{% linkable_title %}` tag.
* Do not use ALL CAPITALS for emphasis - use italics instead.
## Component and Platform Pages
* The **Configuration Variables** section must use the `{% configuration %}` tag.
* Configuration variables must document the requirement status (`false` or `true`).
* Configuration variables must document the default value, if any.
* Configuration variables must document the accepted value types (see [Configuration variables details](documentation_create_page.md#configuration)).
* For configuration variables that accept multiple types, separate the types with a comma (i.e. `string, int`).
* Use YAML sequence syntax in the sample code if it is supported.
* All examples should be formatted to be included in `configuration.yaml` unless explicitly stated.
* Use capital letters and `_` to indicate that the value needs to be replaced. E.g., `api_key: YOUR_API_KEY` or `api_key: REPLACE_ME`.
* If you know that the API key or value contains [control characters](https://en.wikipedia.org/wiki/YAML#Syntax), e.g., `#`, `[`, `?`, etc., wrap it in quotes and add a note.
* Component and platform names should be a link to their respective documentation pages.
Example configuration block
```yaml
{% configuration %}
some_key:
description: This is a description of what this key is for.
required: false
type: string
default: Optional default value - leave out if there isn't one
{% endconfiguration %}
```
## Templates
* All examples containing Jinja2 templates should be wrapped **outside** of the code markdown with the `{% raw %}` tag.
* Do not use `states.switch.source.state` in templates. Instead use `states()` and `is_state()`.
* Use double quotes (`"`) for ([more information](#single-vs-double-quotation-marks)):
* `friendly_name`
* Single-line templates:
* `value_template`
* `level_template`
* `icon_template`
* Children of `data_template`
* Use single quotes (`'`) for ([more information](#single-vs-double-quotation-marks):
* Strings inside of templates:
* States
* Entity IDs
* `unit_of_measurement`
* No whitespace around pipe character (`|`) for Jinja2 filters.
* Single whitespace after Jinja2 opening delimiters ({% raw %}`{{`{% endraw %}).
* Single whitespace before Jinja2 closing delimiters ({% raw %}`}}`{% endraw %}).
* Do not quote values for:
* `device_class`
* `platform`
* `condition`
* `service`
## Renaming Pages
It can happen that a component or platform is renamed, in this case the documentation needs to be updated as well. If you rename a page, add `redirect_from:` to the file header and let it point to the old location/name of the page. Please consider to add details, like release number or old component/platform name, to the page in a [note](/developers/documentation/create_page/#html).
```text
---
...
redirect_from: /getting-started/android/
---
```
Adding a redirect also applies if you move content around in the [documentation](/docs/).
## Single vs. Double Quotation Marks
Use single quotes (`'`) for strings inside of a template. It is more obvious to escape a single quote when necessary (i.e. `name` is a possessive noun), because the single quotes that wrap the string are closer in position to the apostrophe inside the string. Use double quotes (`"`) outside of a template (unless it is a multi-line template, in which case outside quotes are not required).
### Examples
#### Double Quotes Outside, Single Quotes Inside (Valid)
```yaml
automation:
...
action:
- service: notify.notify
data_template:
message: "{% if trigger.to_state.name == 'Dale\'s Bedroom' %}Someone's in your base, killing your noobs!{% else %}It's just another door.{% endif %}"
```
#### Single Quotes Outside, Double Quotes Inside (Invalid)
```yaml
automation:
...
action:
- service: notify.notify
data_template:
message: '{% if trigger.to_state.name == "Dale's Bedroom" %}Someone's in your base, killing your noobs!{% else %}It's just another door.{% endif %}'
```
#### Multi-Line Template (Valid)
```yaml
automation:
...
action:
- service: notify.notify
data_template:
message: >-
{% if trigger.to_state.name == 'Dale\'s Bedroom' %}
Someone's in your base, killing your noobs!
{% else %}
It's just another door.
{% endif %}
```

View File

@ -0,0 +1,25 @@
---
title: Air Quality Entity
sidebar_label: Air Quality
---
## 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 |
| ---------------------------- | ----- | ------------ | --------------------------------------------- |
| particulate_matter_2_5 | float | **Required** | The particulate matter 2.5 (<= 2.5 μm) level. |
| particulate_matter_10 | float | **Required** | The particulate matter 10 (<= 10 μm) level. |
| particulate_matter_0_1 | float | `None` | The particulate matter 0.1 (<= 0.1 μm) level. |
| air_quality_index | float | `None` | The Air Quality Index (AQI). |
| ozone | float | `None` | The O3 (ozone) level. |
| carbon_monoxide | float | `None` | The CO (carbon monoxide) level. |
| carbon_dioxide | float | `None` | The CO2 (carbon dioxide) level. |
| sulphur_dioxide | float | `None` | The SO2 (sulphur dioxide) level. |
| nitrogen_oxide | float | `None` | The N2O (nitrogen oxide) level. |
| nitrogen_monoxide | float | `None` | The NO (nitrogen monoxide) level. |
| nitrogen_dioxide | float | `None` | The NO2 (nitrogen dioxide) level. |
| volatile_organic_compounds | float | `None` | The volatile organic compounds (VOC) level. |
Properties have to follow the units defined in the `unit_system`.

View File

@ -0,0 +1,130 @@
---
title: Alarm Control Panel Entity
sidebar_label: Alarm Control Panel
---
> 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 |
| ----------- | ------ | ------------ | --------------------------------------------------------- |
| state | string | **Required** | One of the states listed in the **states** section. |
| code_format | string | `None` | One of the states listed in the **code formats** section. |
| changed_by | string | `None` | Last change triggered by. |
### States
| Value | Description |
| ---------------------- | ------------------------------------------- |
| `disarmed` | The alarm is disarmed (`off`). |
| `armed_home` | The alarm is armed in home mode. |
| `armed_away` | The alarm is armed in away mode. |
| `armed_night` | The alarm is armed in night mode. |
| `armed_custom_bypass`  | The alarm is armed in bypass mode. |
| `pending` | The alarm is pending (towards `triggered`). |
| `arming` | The alarm is arming. |
| `disarming` | The alarm is disarming. |
| `triggered` | The alarm is triggered. |
### Code Formats
| Value | Description |
| ------ | ------------------------------------------------- |
| None | No code required. |
| Number | Code is a number (Shows ten-key pad on frontend). |
| Any | Code is a string. |
## Methods
### Alarm Disarm
Send disarm command.
```python
class MyAlarm(AlarmControlPanel):
# Implement one of these methods.
def alarm_disarm(self, code=None) -> None:
"""Send disarm command."""
async def async_alarm_disarm(self, code=None) -> None:
"""Send disarm command."""
```
### Alarm Arm Home
Send arm home command.
```python
class MyAlarm(AlarmControlPanel):
# Implement one of these methods.
def alarm_arm_home(self, code=None) -> None:
"""Send arm home command."""
def async_alarm_arm_home(self, code=None) -> None:
"""Send arm home command."""
```
### Alarm Arm Away
Send arm away command.
```python
class MyAlarm(AlarmControlPanel):
# Implement one of these methods.
def alarm_arm_away(self, code=None) -> None:
"""Send arm away command."""
def async_alarm_arm_away(self, code=None) -> None:
"""Send arm away command."""
```
### Alarm Arm Night
Send arm night command.
```python
class MyAlarm(AlarmControlPanel):
# Implement one of these methods.
def alarm_arm_night(self, code=None) -> None:
"""Send arm night command."""
def async_alarm_arm_night(self, code=None) -> None:
"""Send arm night command."""
```
### Alarm Trigger
Send alarm trigger command.
```python
class MyAlarm(AlarmControlPanel):
# Implement one of these methods.
def alarm_trigger(self, code=None) -> None:
"""Send alarm trigger command."""
def async_alarm_trigger(self, code=None) -> None:
"""Send alarm trigger command."""
```
### Alarm Custom Bypass
Send arm custom bypass command.
```python
class MyAlarm(AlarmControlPanel):
# Implement one of these methods.
def alarm_arm_custom_bypass(self, code=None) -> None:
"""Send arm custom bypass command."""
def async_alarm_arm_custom_bypass(self, code=None) -> None:
"""Send arm custom bypass command."""
```

Some files were not shown because too many files have changed in this diff Show More