mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-14 21:06:28 +00:00
Version bump to 0.90.0
This commit is contained in:
parent
6d97e4d7df
commit
d052e8a3a7
@ -1171,6 +1171,38 @@
|
||||
},
|
||||
"version-0.89.0-internationalization_translation": {
|
||||
"title": "Translation"
|
||||
},
|
||||
"version-0.90.0-app_integration_sending_data": {
|
||||
"title": "Sending data home"
|
||||
},
|
||||
"version-0.90.0-auth_permissions": {
|
||||
"title": "Permissions"
|
||||
},
|
||||
"version-0.90.0-config_entries_index": {
|
||||
"title": "Config Entries",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.90.0-development_environment": {
|
||||
"title": "Set up Development Environment"
|
||||
},
|
||||
"version-0.90.0-device_registry_index": {
|
||||
"title": "Device Registry",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.90.0-external_api_rest": {
|
||||
"title": "REST API"
|
||||
},
|
||||
"version-0.90.0-external_api_websocket": {
|
||||
"title": "WebSocket API"
|
||||
},
|
||||
"version-0.90.0-hassio_addon_config": {
|
||||
"title": "Add-On Configuration"
|
||||
},
|
||||
"version-0.90.0-hassio_addon_tutorial": {
|
||||
"title": "Tutorial: Making your first add-on"
|
||||
},
|
||||
"version-0.90.0-maintenance": {
|
||||
"title": "Maintenance"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
|
@ -0,0 +1,146 @@
|
||||
---
|
||||
title: Sending data home
|
||||
id: version-0.90.0-app_integration_sending_data
|
||||
original_id: app_integration_sending_data
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
## 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 will need to record which WiFi is the home network, and use a direct connection when connected to the home WiFi network.
|
||||
|
||||
## Interaction basics
|
||||
|
||||
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>",
|
||||
// other info
|
||||
}
|
||||
```
|
||||
|
||||
If you received a `secret` during registration, you will need to encrypt your message and wrap it in an encrypted message:
|
||||
|
||||
```json5
|
||||
{
|
||||
"type": "encrypted",
|
||||
"data": "<encrypted message>"
|
||||
}
|
||||
```
|
||||
|
||||
## Update device location
|
||||
|
||||
This message will inform Home Assistant of new location information.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "update_location",
|
||||
"gps": [12.34, 56.78],
|
||||
"gps_accuracy": 120,
|
||||
"battery": 45,
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Type | Description
|
||||
| --- | ---- | -----------
|
||||
| `gps` | latlong | Current location as latitude and longitude.
|
||||
| `gps_accuracy` | int | GPS accurracy in meters.
|
||||
| `battery` | int | Percentage of battery the device has left.
|
||||
|
||||
## Call a service
|
||||
|
||||
Call a service in Home Assistant.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "call_service",
|
||||
"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",
|
||||
"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
|
||||
|
||||
> This API is very likely to change in an upcoming release. Support to render multiple templates at once will be added.
|
||||
|
||||
Renders a template and returns the result.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "render_template",
|
||||
"template": "Hello {{ name }}, you are {{ states('person.paulus') }}.",
|
||||
"variables": {
|
||||
"name": "Paulus"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| 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",
|
||||
"app_data": {
|
||||
"push_notification_key": "abcd"
|
||||
},
|
||||
"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_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.
|
||||
| `app_data` | Dict | App data can be used if the app has a supporting component that extends mobile_app functionality.
|
273
website/versioned_docs/version-0.90.0/auth_permissions.md
Normal file
273
website/versioned_docs/version-0.90.0/auth_permissions.md
Normal file
@ -0,0 +1,273 @@
|
||||
---
|
||||
title: Permissions
|
||||
id: version-0.90.0-auth_permissions
|
||||
original_id: auth_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,
|
||||
policy=POLICY_CONTROL,
|
||||
)
|
||||
|
||||
if not user.permissions.check_entity(entity_id, POLICY_CONTROL):
|
||||
raise Unauthorized(
|
||||
context=call.context,
|
||||
entity_id=entity_id,
|
||||
policy=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
|
||||
```
|
136
website/versioned_docs/version-0.90.0/config_entries_index.md
Normal file
136
website/versioned_docs/version-0.90.0/config_entries_index.md
Normal file
@ -0,0 +1,136 @@
|
||||
---
|
||||
title: Config Entries
|
||||
sidebar_label: Introduction
|
||||
id: version-0.90.0-config_entries_index
|
||||
original_id: config_entries_index
|
||||
---
|
||||
|
||||
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->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->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->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->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->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->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->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->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)).
|
||||
|
||||
Platforms will not need to add any logic for unloading a config entry. The entity component will take care of this.
|
||||
If you need to clean up resources used for an entity, implement the `async_will_remove_from_hass` method on the Entity ([example](https://github.com/home-assistant/home-assistant/blob/0.68.0/homeassistant/components/media_player/cast.py#L313)).
|
||||
|
||||
## 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."""
|
||||
```
|
120
website/versioned_docs/version-0.90.0/development_environment.md
Normal file
120
website/versioned_docs/version-0.90.0/development_environment.md
Normal file
@ -0,0 +1,120 @@
|
||||
---
|
||||
title: Set up Development Environment
|
||||
id: version-0.90.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
|
||||
$ 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
|
||||
```
|
@ -0,0 +1,85 @@
|
||||
---
|
||||
title: Device Registry
|
||||
sidebar_label: Introduction
|
||||
id: version-0.90.0-device_registry_index
|
||||
original_id: device_registry_index
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
<img
|
||||
src='/img/en/device_registry/overview.png'
|
||||
alt='Device registry overview'
|
||||
/>
|
||||
|
||||
## 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,
|
||||
)
|
||||
```
|
530
website/versioned_docs/version-0.90.0/external_api_rest.md
Normal file
530
website/versioned_docs/version-0.90.0/external_api_rest.md
Normal file
@ -0,0 +1,530 @@
|
||||
---
|
||||
title: REST API
|
||||
id: version-0.90.0-external_api_rest
|
||||
original_id: external_api_rest
|
||||
---
|
||||
|
||||
Home Assistant provides a RESTful API on the same port as the web frontend. (default port is port 8123).
|
||||
|
||||
If you are not using the [`frontend`](https://www.home-assistant.io/components/frontend/) in your setup then you need to add the [`api` component](https://www.home-assistant.io/components/api/) to your `configuration.yaml` file.
|
||||
|
||||
* http://IP_ADDRESS:8123/ is an interface to control Home Assistant.
|
||||
* http://IP_ADDRESS:8123/api/ is a RESTful API.
|
||||
|
||||
The API accepts and returns only JSON encoded objects.
|
||||
|
||||
All API calls have to be accompanied by the header `Authorization: Bearer ABCDEFGH`, where `ABCDEFGH` is replaced by your token. You can obtain a token ("Long-Lived Access Token") by logging into the frontend using a web browser, and going to [your profile](https://www.home-assistant.io/docs/authentication/#your-account-profile) `http://IP_ADDRESS:8123/profile`.
|
||||
|
||||
There are multiple ways to consume the Home Assistant Rest API. One is with `curl`:
|
||||
|
||||
```bash
|
||||
$ curl -X GET \
|
||||
-H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://IP_ADDRESS:8123/ENDPOINT
|
||||
```
|
||||
|
||||
Another option is to use Python and the [Requests](http://docs.python-requests.org/en/latest/) module.
|
||||
|
||||
```python
|
||||
from requests import get
|
||||
|
||||
url = 'http://localhost:8123/ENDPOINT'
|
||||
headers = {
|
||||
'Authorization': 'Bearer ABCDEFGH',
|
||||
'content-type': 'application/json',
|
||||
}
|
||||
|
||||
response = get(url, headers=headers)
|
||||
print(response.text)
|
||||
```
|
||||
Another option is to use the Restful Command component https://www.home-assistant.io/components/rest_command/ in a Home Assistant automation or script.
|
||||
|
||||
```yaml
|
||||
turn_light_on:
|
||||
url: http://localhost:8123/api/states/light.study_light
|
||||
method: POST
|
||||
headers:
|
||||
authorization: 'Bearer ABCDEFGH'
|
||||
content-type: 'application/json'
|
||||
payload: '{"state":"on"}'
|
||||
```
|
||||
|
||||
Successful calls will return status code 200 or 201. Other status codes that can return are:
|
||||
|
||||
- 400 (Bad Request)
|
||||
- 401 (Unauthorized)
|
||||
- 404 (Not Found)
|
||||
- 405 (Method not allowed)
|
||||
|
||||
### Actions
|
||||
|
||||
The API supports the following actions:
|
||||
|
||||
#### GET /api/
|
||||
|
||||
Returns a message if the API is up and running.
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "API running."
|
||||
}
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/
|
||||
```
|
||||
|
||||
#### GET /api/config
|
||||
|
||||
Returns the current configuration as JSON.
|
||||
|
||||
```json
|
||||
{
|
||||
"components":[
|
||||
"sensor.cpuspeed",
|
||||
"frontend",
|
||||
"config.core",
|
||||
"http",
|
||||
"map",
|
||||
"api",
|
||||
"sun",
|
||||
"config",
|
||||
"discovery",
|
||||
"conversation",
|
||||
"recorder",
|
||||
"group",
|
||||
"sensor",
|
||||
"websocket_api",
|
||||
"automation",
|
||||
"config.automation",
|
||||
"config.customize"
|
||||
],
|
||||
"config_dir":"/home/ha/.homeassistant",
|
||||
"elevation":510,
|
||||
"latitude":45.8781529,
|
||||
"location_name":"Home",
|
||||
"longitude":8.458853651,
|
||||
"time_zone":"Europe/Zurich",
|
||||
"unit_system":{
|
||||
"length":"km",
|
||||
"mass":"g",
|
||||
"temperature":"\u00b0C",
|
||||
"volume":"L"
|
||||
},
|
||||
"version":"0.56.2",
|
||||
"whitelist_external_dirs":[
|
||||
"/home/ha/.homeassistant/www",
|
||||
"/home/ha/.homeassistant/"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/config
|
||||
```
|
||||
|
||||
#### GET /api/discovery_info
|
||||
|
||||
Returns basic information about the Home Assistant instance as JSON.
|
||||
|
||||
```json
|
||||
{
|
||||
"base_url": "http://192.168.0.2:8123",
|
||||
"location_name": "Home",
|
||||
"requires_api_password": true,
|
||||
"version": "0.56.2"
|
||||
}
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/discovery_info
|
||||
```
|
||||
|
||||
#### GET /api/events
|
||||
|
||||
Returns an array of event objects. Each event object contains event name and listener count.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"event": "state_changed",
|
||||
"listener_count": 5
|
||||
},
|
||||
{
|
||||
"event": "time_changed",
|
||||
"listener_count": 2
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/events
|
||||
```
|
||||
|
||||
#### GET /api/services
|
||||
|
||||
Returns an array of service objects. Each object contains the domain and which services it contains.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"domain": "browser",
|
||||
"services": [
|
||||
"browse_url"
|
||||
]
|
||||
},
|
||||
{
|
||||
"domain": "keyboard",
|
||||
"services": [
|
||||
"volume_up",
|
||||
"volume_down"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/services
|
||||
```
|
||||
|
||||
#### GET /api/history/period/<timestamp>
|
||||
|
||||
Returns an array of state changes in the past. Each object contains further details for the entities.
|
||||
|
||||
The `<timestamp>` (`YYYY-MM-DDThh:mm:ssTZD`) is optional and defaults to 1 day before the time of the request. It determines the beginning of the period.
|
||||
|
||||
You can pass the following optional GET parameters:
|
||||
|
||||
- `filter_entity_id=<entity_ids>` to filter on one or more entities - comma separated.
|
||||
- `end_time=<timestamp>` to choose the end of the period in URL encoded format (defaults to 1 day).
|
||||
|
||||
```json
|
||||
[
|
||||
[
|
||||
{
|
||||
"attributes": {
|
||||
"friendly_name": "Weather Temperature",
|
||||
"unit_of_measurement": "\u00b0C"
|
||||
},
|
||||
"entity_id": "sensor.weather_temperature",
|
||||
"last_changed": "2016-02-06T22:15:00+00:00",
|
||||
"last_updated": "2016-02-06T22:15:00+00:00",
|
||||
"state": "-3.9"
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
"friendly_name": "Weather Temperature",
|
||||
"unit_of_measurement": "\u00b0C"
|
||||
},
|
||||
"entity_id": "sensor.weather_temperature",
|
||||
"last_changed": "2016-02-06T22:15:00+00:00",
|
||||
"last_updated": "2016-02-06T22:15:00+00:00",
|
||||
"state": "-1.9"
|
||||
},
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Sample `curl` commands:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8123/api/history/period/2016-12-29T00:00:00+02:00
|
||||
```
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8123/api/history/period/2016-12-29T00:00:00+02:00?filter_entity_id=sensor.temperature
|
||||
```
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8123/api/history/period/2016-12-29T00:00:00+02:00?end_time=2016-12-31T00%3A00%3A00%2B02%3A00
|
||||
```
|
||||
|
||||
#### GET /api/states
|
||||
|
||||
Returns an array of state objects. Each state has the following attributes: entity_id, state, last_changed and attributes.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"attributes": {},
|
||||
"entity_id": "sun.sun",
|
||||
"last_changed": "2016-05-30T21:43:32.418320+00:00",
|
||||
"state": "below_horizon"
|
||||
},
|
||||
{
|
||||
"attributes": {},
|
||||
"entity_id": "process.Dropbox",
|
||||
"last_changed": "22016-05-30T21:43:32.418320+00:00",
|
||||
"state": "on"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/states
|
||||
```
|
||||
|
||||
#### GET /api/states/<entity_id>
|
||||
|
||||
Returns a state object for specified entity_id. Returns 404 if not found.
|
||||
|
||||
```json
|
||||
{
|
||||
"attributes":{
|
||||
"azimuth":336.34,
|
||||
"elevation":-17.67,
|
||||
"friendly_name":"Sun",
|
||||
"next_rising":"2016-05-31T03:39:14+00:00",
|
||||
"next_setting":"2016-05-31T19:16:42+00:00"
|
||||
},
|
||||
"entity_id":"sun.sun",
|
||||
"last_changed":"2016-05-30T21:43:29.204838+00:00",
|
||||
"last_updated":"2016-05-30T21:50:30.529465+00:00",
|
||||
"state":"below_horizon"
|
||||
}
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8123/api/states/sensor.kitchen_temperature
|
||||
```
|
||||
|
||||
#### GET /api/error_log
|
||||
|
||||
Retrieve all errors logged during the current session of Home Assistant as a plaintext response.
|
||||
|
||||
```text
|
||||
15-12-20 11:02:50 homeassistant.components.recorder: Found unfinished sessions
|
||||
15-12-20 11:03:03 netdisco.ssdp: Error fetching description at http://192.168.1.1:8200/rootDesc.xml
|
||||
15-12-20 11:04:36 homeassistant.components.alexa: Received unknown intent HelpIntent
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8123/api/error_log
|
||||
```
|
||||
|
||||
#### GET /api/camera_proxy/camera.<entity_id>
|
||||
|
||||
Returns the data (image) from the specified camera entity_id.
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8123/api/camera_proxy/camera.my_sample_camera?time=1462653861261 -o image.jpg
|
||||
```
|
||||
|
||||
#### POST /api/states/<entity_id>
|
||||
|
||||
Updates or creates the current state of an entity.
|
||||
|
||||
Expects a JSON object that has at least a state attribute:
|
||||
|
||||
```json
|
||||
{
|
||||
"state": "below_horizon",
|
||||
"attributes": {
|
||||
"next_rising":"2016-05-31T03:39:14+00:00",
|
||||
"next_setting":"2016-05-31T19:16:42+00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The return code is 200 if the entity existed, 201 if the state of a new entity was set. A location header will be returned with the URL of the new resource. The response body will contain a JSON encoded State object.
|
||||
|
||||
```json
|
||||
{
|
||||
"attributes": {
|
||||
"next_rising":"2016-05-31T03:39:14+00:00",
|
||||
"next_setting":"2016-05-31T19:16:42+00:00"
|
||||
},
|
||||
"entity_id": "sun.sun",
|
||||
"last_changed": "2016-05-30T21:43:29.204838+00:00",
|
||||
"last_updated": "2016-05-30T21:47:30.533530+00:00",
|
||||
"state": "below_horizon"
|
||||
}
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X POST -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"state": "25", "attributes": {"unit_of_measurement": "°C"}}' \
|
||||
http://localhost:8123/api/states/sensor.kitchen_temperature
|
||||
```
|
||||
|
||||
#### POST /api/events/<event_type>
|
||||
|
||||
Fires an event with event_type
|
||||
|
||||
You can pass an optional JSON object to be used as `event_data`.
|
||||
|
||||
```json
|
||||
{
|
||||
"next_rising":"2016-05-31T03:39:14+00:00",
|
||||
}
|
||||
```
|
||||
|
||||
Returns a message if successful.
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Event download_file fired."
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /api/services/<domain>/<service>
|
||||
|
||||
Calls a service within a specific domain. Will return when the service has been executed or after 10 seconds, whichever comes first.
|
||||
|
||||
You can pass an optional JSON object to be used as `service_data`.
|
||||
|
||||
```json
|
||||
{
|
||||
"entity_id": "light.Ceiling"
|
||||
}
|
||||
```
|
||||
|
||||
Returns a list of states that have changed while the service was being executed.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"attributes": {},
|
||||
"entity_id": "sun.sun",
|
||||
"last_changed": "2016-05-30T21:43:32.418320+00:00",
|
||||
"state": "below_horizon"
|
||||
},
|
||||
{
|
||||
"attributes": {},
|
||||
"entity_id": "process.Dropbox",
|
||||
"last_changed": "22016-05-30T21:43:32.418320+00:00",
|
||||
"state": "on"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Sample `curl` commands:
|
||||
|
||||
Turn the light on:
|
||||
|
||||
```bash
|
||||
$ curl -X POST -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"entity_id": "switch.christmas_lights"}' \
|
||||
http://localhost:8123/api/services/switch/turn_on
|
||||
```
|
||||
|
||||
Send a MQTT message:
|
||||
|
||||
```bash
|
||||
$ curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "x-ha-access:YOUR_PASSWORD" \
|
||||
-d '{"payload": "OFF", "topic": "home/fridge", "retain": "True"}' \
|
||||
http://localhost:8123/api/services/mqtt/publish
|
||||
```
|
||||
|
||||
> The result will include any states that changed while the service was being executed, even if their change was the result of something else happening in the system.
|
||||
|
||||
#### POST /api/template
|
||||
|
||||
Render a Home Assistant template. [See template docs for more information.](https://www.home-assistant.io/topics/templating/)
|
||||
|
||||
```json
|
||||
{
|
||||
"template": "Paulus is at {{ states('device_tracker.paulus') }}!"
|
||||
}
|
||||
```
|
||||
|
||||
Returns the rendered template in plain text.
|
||||
|
||||
```text
|
||||
Paulus is at work!
|
||||
```
|
||||
|
||||
Sample `curl` command:
|
||||
|
||||
```bash
|
||||
$ curl -X POST -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"template": "It is {{ now }}!"}' http://localhost:8123/api/template
|
||||
```
|
||||
|
||||
#### POST /api/event_forwarding
|
||||
|
||||
Set up event forwarding to another Home Assistant instance.
|
||||
|
||||
Requires a JSON object that represents the API to forward to.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"host": "machine",
|
||||
"api_password": "my_super_secret_password",
|
||||
"port": 8880 // optional
|
||||
}
|
||||
```
|
||||
|
||||
It will return a message if event forwarding was set up successfully.
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Event forwarding setup."
|
||||
}
|
||||
```
|
||||
|
||||
#### DELETE /api/event_forwarding
|
||||
|
||||
Cancel event forwarding to another Home Assistant instance.<br>
|
||||
|
||||
Requires a JSON object that represents the API to cancel forwarding to.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"host": "machine",
|
||||
"api_password": "my_super_secret_password",
|
||||
"port": 8880 // optional
|
||||
}
|
||||
```
|
||||
|
||||
It will return a message if event forwarding was canceled successfully.
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Event forwarding cancelled."
|
||||
}
|
||||
```
|
436
website/versioned_docs/version-0.90.0/external_api_websocket.md
Normal file
436
website/versioned_docs/version-0.90.0/external_api_websocket.md
Normal file
@ -0,0 +1,436 @@
|
||||
---
|
||||
title: WebSocket API
|
||||
id: version-0.90.0-external_api_websocket
|
||||
original_id: external_api_websocket
|
||||
---
|
||||
|
||||
Home Assistant contains a WebSocket API. This API can be used to stream information from a Home Assistant instance to any client that implements WebSockets. Implementations in different languages:
|
||||
|
||||
- [JavaScript](https://github.com/home-assistant/home-assistant-js-websocket) - powers the frontend
|
||||
- [Python](https://raw.githubusercontent.com/home-assistant/home-assistant-dev-helper/master/ha-websocket-client.py) - CLI client using [`asyncws`](https://async-websockets.readthedocs.io/en/latest/)
|
||||
- [JavaScript/HTML](https://raw.githubusercontent.com/home-assistant/home-assistant-dev-helper/master/ha-websocket.html) - WebSocket connection in your browser
|
||||
|
||||
Connect your websocket implementation to `ws://localhost:8123/api/websocket`. You will need a valid access token.
|
||||
|
||||
If you are not using the [`frontend`](https://www.home-assistant.io/components/frontend/) in your setup then you need to add the [`websocket_api` component](https://www.home-assistant.io/components/websocket_api/) to your `configuration.yaml` file to use the WebSocket API.
|
||||
|
||||
## Server states
|
||||
|
||||
1. Client connects.
|
||||
1. Authentication phase starts.
|
||||
- Server sends `auth_required` message.
|
||||
- Client sends `auth` message.
|
||||
- If `auth` message correct: go to 3.
|
||||
- Server sends `auth_invalid`. Go to 6.
|
||||
1. Send `auth_ok` message
|
||||
1. Authentication phase ends.
|
||||
1. Command phase starts.
|
||||
1. Client can send commands.
|
||||
1. Server can send results of previous commands.
|
||||
1. Client or server disconnects session.
|
||||
|
||||
During the command phase, the client attaches a unique identifier to each message. The server will add this identifier to each message so that the client can link each message to its origin.
|
||||
|
||||
## Message format
|
||||
|
||||
Each API message is a JSON serialized object containing a `type` key. After the authentication phase messages also must contain an `id`, an integer that contains the number of interactions.
|
||||
|
||||
Example of an auth message:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth",
|
||||
"access_token": "ABCDEFGHIJKLMNOPQ"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 5,
|
||||
"type":"event",
|
||||
"event":{
|
||||
"data":{},
|
||||
"event_type":"test_event",
|
||||
"time_fired":"2016-11-26T01:37:24.265429+00:00",
|
||||
"origin":"LOCAL"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication phase
|
||||
|
||||
When a client connects to the server, the server will test if the client is authenticated. Authentication will not be necessary if no api_password is set or if the user fulfills one of the other criteria for authentication (trusted network, password in url/header).
|
||||
|
||||
If no authentication is needed, the authentication phase will complete and the server will send an `auth_ok` message.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth_ok"
|
||||
}
|
||||
```
|
||||
|
||||
If authentication is necessary, the server sends out `auth_required`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth_required"
|
||||
}
|
||||
```
|
||||
|
||||
This means that the next message from the client should be an auth message. You can authorize with an access token.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth",
|
||||
"access_token": "ABCDEFGH"
|
||||
}
|
||||
```
|
||||
|
||||
For now, we also support authentication with an API password (legacy auth).
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth",
|
||||
"api_password": "supersecret"
|
||||
}
|
||||
```
|
||||
|
||||
If the client supplies valid authentication, the authentication phase will complete by the server sending the `auth_ok` message:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth_ok"
|
||||
}
|
||||
```
|
||||
|
||||
If the data is incorrect, the server will reply with `auth_invalid` message and disconnect the session.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth_invalid",
|
||||
"message": "Invalid password"
|
||||
}
|
||||
```
|
||||
|
||||
## Command phase
|
||||
|
||||
During this phase the client can give commands to the server. The server will respond to each command with a `result` message indicating when the command is done and if it was successful.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 6.
|
||||
"type": "result",
|
||||
"success": true,
|
||||
// Can contain extra result info
|
||||
"result": null
|
||||
}
|
||||
```
|
||||
|
||||
## Subscribe to events
|
||||
|
||||
The command `subscribe_events` will subscribe your client to the event bus. You can either listen to all events or to a specific event type. If you want to listen to multiple event types, you will have to send multiple `subscribe_events` commands.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 18,
|
||||
"type": "subscribe_events",
|
||||
// Optional
|
||||
"event_type": "state_changed"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message to indicate that the subscription is active.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 18,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": null
|
||||
}
|
||||
```
|
||||
|
||||
For each event that matches, the server will send a message of type `event`. The `id` in the message will point at the original `id` of the `listen_event` command.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 18,
|
||||
"type":"event",
|
||||
"event":{
|
||||
"data":{
|
||||
"entity_id":"light.bed_light",
|
||||
"new_state":{
|
||||
"entity_id":"light.bed_light",
|
||||
"last_changed":"2016-11-26T01:37:24.265390+00:00",
|
||||
"state":"on",
|
||||
"attributes":{
|
||||
"rgb_color":[
|
||||
254,
|
||||
208,
|
||||
0
|
||||
],
|
||||
"color_temp":380,
|
||||
"supported_features":147,
|
||||
"xy_color":[
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"brightness":180,
|
||||
"white_value":200,
|
||||
"friendly_name":"Bed Light"
|
||||
},
|
||||
"last_updated":"2016-11-26T01:37:24.265390+00:00"
|
||||
},
|
||||
"old_state":{
|
||||
"entity_id":"light.bed_light",
|
||||
"last_changed":"2016-11-26T01:37:10.466994+00:00",
|
||||
"state":"off",
|
||||
"attributes":{
|
||||
"supported_features":147,
|
||||
"friendly_name":"Bed Light"
|
||||
},
|
||||
"last_updated":"2016-11-26T01:37:10.466994+00:00"
|
||||
}
|
||||
},
|
||||
"event_type":"state_changed",
|
||||
"time_fired":"2016-11-26T01:37:24.265429+00:00",
|
||||
"origin":"LOCAL"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Unsubscribing from events
|
||||
|
||||
You can unsubscribe from previously created subscription events. Pass the id of the original subscription command as value to the subscription field.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "unsubscribe_events",
|
||||
"subscription": 18
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message to indicate that unsubscribing was successful.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": null
|
||||
}
|
||||
```
|
||||
|
||||
### Calling a service
|
||||
|
||||
This will call a service in Home Assistant. Right now there is no return value. The client can listen to `state_changed` events if it is interested in changed entities as a result of a service call.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 24,
|
||||
"type": "call_service",
|
||||
"domain": "light",
|
||||
"service": "turn_on",
|
||||
// Optional
|
||||
"service_data": {
|
||||
"entity_id": "light.kitchen"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The server will indicate with a message indicating that the service is done executing.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 24,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": null
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching states
|
||||
|
||||
This will get a dump of all the current states in Home Assistant.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "get_states"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message containing the states.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching config
|
||||
|
||||
This will get a dump of the current config in Home Assistant.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "get_config"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message containing the config.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching services
|
||||
|
||||
This will get a dump of the current services in Home Assistant.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "get_services"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message containing the services.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching panels
|
||||
|
||||
This will get a dump of the current registered panels in Home Assistant.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "get_panels"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message containing the current registered panels.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching camera thumbnails
|
||||
|
||||
_Introduced in Home Assistant 0.69._
|
||||
|
||||
Return a b64 encoded thumbnail of a camera entity.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "camera_thumbnail"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with a result message containing the thumbnail.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": {
|
||||
"content_type": "image/jpeg",
|
||||
"content": "<base64 encoded image>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching media player thumbnails
|
||||
|
||||
_Introduced in Home Assistant 0.69._
|
||||
|
||||
Fetch a base64 encoded thumbnail picture for a media player.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "media_player_thumbnail",
|
||||
"entity_id": "media_player.living_room"
|
||||
}
|
||||
```
|
||||
|
||||
The server will respond with the image encoded via base64.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "result",
|
||||
"success": true,
|
||||
"result": {
|
||||
"content_type": "image/jpeg",
|
||||
"content": "<base64 encoded image>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Pings and Pongs
|
||||
|
||||
The API supports receiving a ping from the client and returning a pong. This serves as a heartbeat to ensure the connection is still alive:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "ping"
|
||||
}
|
||||
```
|
||||
|
||||
The server must send a pong back as quickly as possible, if the connection is still active:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 19,
|
||||
"type": "pong"
|
||||
}
|
||||
```
|
||||
|
||||
## Error handling
|
||||
|
||||
If an error occurs, the `success` key in the `result` message will be set to `false`. It will contain an `error` key containing an object with two keys: `code` and `message`.
|
||||
|
||||
| Code | Description |
|
||||
| ----- | ------------ |
|
||||
| 1 | A non-increasing identifier has been supplied.
|
||||
| 2 | Received message is not in expected format (voluptuous validation error).
|
||||
| 3 | Requested item cannot be found
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 12,
|
||||
"type":"result",
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": 2,
|
||||
"message": "Message incorrectly formatted: expected str for dictionary value @ data['event_type']. Got 100"
|
||||
}
|
||||
}
|
||||
```
|
211
website/versioned_docs/version-0.90.0/hassio_addon_config.md
Normal file
211
website/versioned_docs/version-0.90.0/hassio_addon_config.md
Normal file
@ -0,0 +1,211 @@
|
||||
---
|
||||
title: Add-On Configuration
|
||||
id: version-0.90.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 | Description |
|
||||
|-----|-------------|
|
||||
| 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"
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Type | Required | Description |
|
||||
| --- | ---- | -------- | ----------- |
|
||||
| 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 | yes | List of supported arch: `armhf`, `armv7`, `aarch64`, `amd64`, `i386`.
|
||||
| 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"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Required | Description |
|
||||
| --- | -------- | ----------- |
|
||||
| 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.
|
182
website/versioned_docs/version-0.90.0/hassio_addon_tutorial.md
Normal file
182
website/versioned_docs/version-0.90.0/hassio_addon_tutorial.md
Normal file
@ -0,0 +1,182 @@
|
||||
---
|
||||
title: Tutorial: Making your first add-on
|
||||
id: version-0.90.0-hassio_addon_tutorial
|
||||
original_id: hassio_addon_tutorial
|
||||
---
|
||||
|
||||
So you've got Home Assistant going and you've been enjoying the built-in add-ons but you're missing this one application. Time to make your own add-on! In Hass.io 0.24 we introduced the option to have local add-ons be build on your device. This is great for developing new add-ons locally.
|
||||
|
||||
To get started with developing add-ons, we first need access to where Hass.io looks for local add-ons. For this you can use the Samba add-on or the SSH add-on.
|
||||
|
||||
For Samba, once you have enabled and started it, your Hass.io instance will show up in your local network tab and share a folder called "addons". This is the folder to store your custom add-ons.
|
||||
|
||||
If you are on macOS and the folder is not showing up automatically, go to Finder and press CMD+K then enter 'smb://hassio.local'
|
||||
|
||||

|
||||
|
||||
For SSH, you will have to install it. Before you can start it, you will have to have a private/public key pair and store your public key in the add-on config ([see docs for more info][ssh]). Once started, you can SSH to Hass.io and store your custom add-ons in "/addons".
|
||||
|
||||

|
||||
|
||||
Once you have located your add-on directory, it's time to get started!
|
||||
|
||||
[ssh]: https://www.home-assistant.io/addons/ssh/
|
||||
|
||||
## Step 1: The basics
|
||||
|
||||
- Create a new directory called `hello_world`
|
||||
- Inside that directory create three files.
|
||||
|
||||
`Dockerfile`:
|
||||
```
|
||||
ARG BUILD_FROM
|
||||
FROM $BUILD_FROM
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
|
||||
# Copy data for add-on
|
||||
COPY run.sh /
|
||||
RUN chmod a+x /run.sh
|
||||
|
||||
CMD [ "/run.sh" ]
|
||||
```
|
||||
|
||||
`config.json`:
|
||||
```json
|
||||
{
|
||||
"name": "Hello world",
|
||||
"version": "1",
|
||||
"slug": "hello_world",
|
||||
"description": "My first real add-on!",
|
||||
"arch": ["armhf", "armv7", "aarch64", "amd64", "i386"],
|
||||
"startup": "before",
|
||||
"boot": "auto",
|
||||
"options": {},
|
||||
"schema": {}
|
||||
}
|
||||
```
|
||||
|
||||
`run.sh`:
|
||||
```bash
|
||||
echo Hello world!
|
||||
```
|
||||
Make sure your editor is using UNIX-like line breaks (LF), not Dos/Windows (CRLF).
|
||||
|
||||
## Step 2: Installing and testing your add-on
|
||||
|
||||
Now comes the fun part, time to open the Hass.io UI and install and run your add-on.
|
||||
|
||||
- Open the Home Assistant frontend
|
||||
- Go to the Hass.io panel
|
||||
- On the top right click the shopping basket to go to the add-on store.
|
||||
|
||||

|
||||
|
||||
- On the top right click the refresh button
|
||||
- You should now see a new card called "Local" that lists your add-on!
|
||||
|
||||

|
||||
|
||||
- Click on your add-on to go to the add-on details page.
|
||||
- Install your add-on
|
||||
- Start your add-on
|
||||
- Refresh the logs of your add-on, you should now see "Hello world!" in your logs.
|
||||
|
||||

|
||||
|
||||
### I don't see my add-on?!
|
||||
|
||||
Oops! You clicked refresh in the store and your add-on didn't show up. Or maybe you just updated an option, clicked refresh and saw your add-on disappear.
|
||||
|
||||
When this happens, it means that your `config.json` is invalid. It's either invalid JSON or one of the specified options is incorrect. To see what went wrong, go to the Hass.io panel and in the supervisor card click on "View logs". This should bring you to a page with the logs of the supervisor. Scroll to the bottom and you should be able to find the validation error.
|
||||
|
||||
Once you fixed the error, go to the add-on store and click refresh again.
|
||||
|
||||
## Step 3: Hosting a server
|
||||
|
||||
Until now we've been able to do some basic stuff, but it's not very useful yet. So let's take it one step further and host a server that we expose on a port. For this we're going to use the built-in HTTP server that comes with Python 3.
|
||||
|
||||
To do this, we will need to update our files as follows:
|
||||
|
||||
- `Dockerfile`: Install Python 3
|
||||
- `config.json`: Make the port from the container available on the host
|
||||
- `run.sh`: Run the Python 3 command to start the HTTP server
|
||||
|
||||
Add to your `Dockerfile` before `RUN`:
|
||||
|
||||
```
|
||||
# Install requirements for add-on
|
||||
RUN apk add --no-cache python3
|
||||
|
||||
# Python 3 HTTP Server serves the current working dir
|
||||
# So let's set it to our add-on persistent data directory.
|
||||
WORKDIR /data
|
||||
```
|
||||
|
||||
Add "ports" to `config.json`. This will make TCP on port 8000 inside the container available on the host on port 8000.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Hello world",
|
||||
"version": "0.2",
|
||||
"slug": "hello_world",
|
||||
"description": "My first real add-on!",
|
||||
"arch": ["armhf", "armv7", "aarch64", "amd64", "i386"],
|
||||
"startup": "before",
|
||||
"boot": "auto",
|
||||
"options": {},
|
||||
"schema": {},
|
||||
"ports": {
|
||||
"8000/tcp": 8000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Update `run.sh` to start the Python 3 server:
|
||||
|
||||
```
|
||||
python3 -m http.server
|
||||
```
|
||||
|
||||
## Step 4: Installing the update
|
||||
|
||||
Since we updated the version number in our `config.json`, Home Assistant will show an update button when looking at the add-on details. You might have to refresh your browser or click the refresh button in the add-on store for it to show up. If you did not update the version number, you can also uninstall and install the add-on again. After installing the add-on again, make sure you start it.
|
||||
|
||||
Now navigate to [http://hassio.local:8000](http://hassio.local:8000) to see our server in action!
|
||||
|
||||

|
||||
|
||||
## Bonus: Working with add-on options
|
||||
|
||||
In the screenshot you've probably seen that our server only served up 1 file: `options.json`. This file contains the user configuration for this add-on. Because we specified an empty "config" and "schema" in our `config.json`, the file is currently empty.
|
||||
|
||||
Let's see if we can get some data into that file!
|
||||
|
||||
To do this, we need to specify the default options and a schema for the user to change the options.
|
||||
|
||||
Change the options and schema entries in your `config.json` with the following:
|
||||
|
||||
```json
|
||||
{
|
||||
…
|
||||
|
||||
"options": {
|
||||
"beer": true,
|
||||
"wine": true,
|
||||
"liquor": false,
|
||||
"name": "world",
|
||||
"year": 2017
|
||||
},
|
||||
"schema": {
|
||||
"beer": "bool",
|
||||
"wine": "bool",
|
||||
"liquor": "bool",
|
||||
"name": "str",
|
||||
"year": "int"
|
||||
},
|
||||
|
||||
…
|
||||
}
|
||||
```
|
||||
|
||||
Refresh the add-on store and re-install your add-on. You will now see the options available in the add-on config screen. When you now go back to our Python 3 server and download `options.json`, you'll see the options you set. [Example of how options.json can be used inside `run.sh`](https://github.com/home-assistant/hassio-addons/blob/master/mosquitto/run.sh#L4-L6)
|
47
website/versioned_docs/version-0.90.0/maintenance.md
Normal file
47
website/versioned_docs/version-0.90.0/maintenance.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Maintenance
|
||||
id: version-0.90.0-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 through the `REQUIREMENTS = ['modules-xyz==0.3']` entry, 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.
|
||||
|
@ -1,4 +1,5 @@
|
||||
[
|
||||
"0.90.0",
|
||||
"0.89.0",
|
||||
"0.88.0",
|
||||
"0.87.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user