mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-12 20:06:28 +00:00
Version 81
This commit is contained in:
parent
61b7870b14
commit
6368c29228
@ -907,6 +907,36 @@
|
||||
"version-0.80.0-integration_quality_scale_index": {
|
||||
"title": "Integration Quality Scale",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.81.0-asyncio_index": {
|
||||
"title": "Asynchronous Programming",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.81.0-auth_api": {
|
||||
"title": "Authentication API",
|
||||
"sidebar_label": "API"
|
||||
},
|
||||
"version-0.81.0-auth_auth_module": {
|
||||
"title": "Multi-factor Authentication Modules"
|
||||
},
|
||||
"version-0.81.0-development_index": {
|
||||
"title": "Starting with Development",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.81.0-development_testing": {
|
||||
"title": "Testing your code"
|
||||
},
|
||||
"version-0.81.0-documentation_index": {
|
||||
"title": "Documentation"
|
||||
},
|
||||
"version-0.81.0-external_api_rest": {
|
||||
"title": "REST API"
|
||||
},
|
||||
"version-0.81.0-external_api_server_sent_events": {
|
||||
"title": "Server-sent events"
|
||||
},
|
||||
"version-0.81.0-hassio_addon_config": {
|
||||
"title": "Add-On Configuration"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
|
21
website/versioned_docs/version-0.81.0/asyncio_index.md
Normal file
21
website/versioned_docs/version-0.81.0/asyncio_index.md
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Asynchronous Programming
|
||||
sidebar_label: Introduction
|
||||
id: version-0.81.0-asyncio_index
|
||||
original_id: asyncio_index
|
||||
---
|
||||
|
||||
On September 29, 2016 we released [Home Assistant 0.29][0.29] as part of our bi-weekly release schedule. This release introduced a complete overhaul of the core spearheaded by [Ben Bangert][ben].
|
||||
|
||||
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 Python’s 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.
|
||||
|
||||
[0.29]: https://www.home-assistant.io/blog/2016/09/29/async-sleepiq-emoncms-stocks/
|
||||
[ben]: https://github.com/bbangert/
|
255
website/versioned_docs/version-0.81.0/auth_api.md
Normal file
255
website/versioned_docs/version-0.81.0/auth_api.md
Normal file
@ -0,0 +1,255 @@
|
||||
---
|
||||
title: Authentication API
|
||||
sidebar_label: API
|
||||
id: version-0.81.0-auth_api
|
||||
original_id: auth_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][oauth2-spec] combined with the [OAuth 2 IndieAuth extension][indieauth-spec] 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][indieauth-clients].
|
||||
|
||||
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
|
||||
|
||||
[](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"
|
||||
}
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
[oauth2-spec]: https://tools.ietf.org/html/rfc6749
|
||||
[indieauth-spec]: https://indieauth.spec.indieweb.org/
|
||||
[indieauth-clients]: https://indieauth.spec.indieweb.org/#client-identifier
|
||||
|
||||
## 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.
|
65
website/versioned_docs/version-0.81.0/auth_auth_module.md
Normal file
65
website/versioned_docs/version-0.81.0/auth_auth_module.md
Normal file
@ -0,0 +1,65 @@
|
||||
---
|
||||
title: Multi-factor Authentication Modules
|
||||
id: version-0.81.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-facor 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
|
||||
|
||||
> TODO: draw a diagram
|
||||
|
||||
User == select auth provider ==> LoginFlow.init == input/validate username/password ==> LoginFlow.finish ==> if user enabled mfa ==> LoginFlow.select_mfa_module ==> initialize(optional) ==> LoginFlow.mfa == input/validate MFA code ==> LoginFlow.finish ==> Done
|
||||
|
||||
## 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.
|
29
website/versioned_docs/version-0.81.0/development_index.md
Normal file
29
website/versioned_docs/version-0.81.0/development_index.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Starting with Development
|
||||
sidebar_label: Introduction
|
||||
id: version-0.81.0-development_index
|
||||
original_id: development_index
|
||||
---
|
||||
|
||||
Home Assistant is built from the ground up to be easily extensible using components. Home Assistant uses [Python 3](https://www.python.org/) for the backend and [Polymer (Web components)](https://www.polymer-project.org/) for the frontend.
|
||||
|
||||
Home Assistant is open-source and licensed under [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0). Here are links to the source:
|
||||
|
||||
- [home-assistant](https://github.com/home-assistant/home-assistant): Python server backend.
|
||||
- [home-assistant-polymer](https://github.com/home-assistant/home-assistant-polymer): Polymer UI.
|
||||
|
||||
For those new to contributing to open source software, make sure you are familiar with all of the tools and concepts used in Home Assistant before you start.
|
||||
|
||||
When contributing Home Assistant code:
|
||||
- [Github](https://guides.github.com/activities/hello-world/)
|
||||
- [Pip and Virtual Environments](https://www.dabapps.com/blog/introduction-to-pip-and-virtualenv-python/)
|
||||
- [Python 3](https://www.python.org/)
|
||||
- [Pylint](https://www.pylint.org)
|
||||
- [Flake8](http://flake8.pycqa.org/en/latest/)
|
||||
- [Tox](http://tox.readthedocs.org/en/latest/)
|
||||
- [TravisCl](https://travis-ci.org/)
|
||||
|
||||
Home Assistant follows [Debian Stable](https://packages.debian.org/stable/python/python3) for the minimum Python version, which is currently [Python 3.5.3](https://www.python.org/downloads/release/python-353/).
|
||||
|
||||
When contributing 3rd Party code to be used by Home Assistant:
|
||||
- [Publishing your own PyPI package](https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/)
|
80
website/versioned_docs/version-0.81.0/development_testing.md
Normal file
80
website/versioned_docs/version-0.81.0/development_testing.md
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Testing your code
|
||||
id: version-0.81.0-development_testing
|
||||
original_id: development_testing
|
||||
---
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
53
website/versioned_docs/version-0.81.0/documentation_index.md
Normal file
53
website/versioned_docs/version-0.81.0/documentation_index.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Documentation
|
||||
id: version-0.81.0-documentation_index
|
||||
original_id: documentation_index
|
||||
---
|
||||
|
||||
The user documentation is located at [https://www.home-assistant.io](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`
|
||||
- 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 && 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. 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](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 `bundle exec rake generate` prior to `bundle exec rake preview` for the very first preview.
|
||||
|
||||
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
|
||||
```
|
517
website/versioned_docs/version-0.81.0/external_api_rest.md
Normal file
517
website/versioned_docs/version-0.81.0/external_api_rest.md
Normal file
@ -0,0 +1,517 @@
|
||||
---
|
||||
title: REST API
|
||||
id: version-0.81.0-external_api_rest
|
||||
original_id: external_api_rest
|
||||
---
|
||||
|
||||
Home Assistant runs a web server accessible on port 8123.
|
||||
|
||||
* http://IP_ADDRESS:8123/ is an interface to control Home Assistant.
|
||||
* http://IP_ADDRESS:8123/api/ is a Rest API.
|
||||
|
||||
The API accepts and returns only JSON encoded objects. All API calls have to be accompanied by the header `X-HA-Access: YOUR_PASSWORD` (YOUR_PASSWORD as specified in your `configuration.yaml` file in the [`http:` section](https://www.home-assistant.io/components/http/)).
|
||||
|
||||
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.
|
||||
|
||||
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)
|
||||
```
|
||||
|
||||
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_id>` to filter on a single entity
|
||||
- `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."
|
||||
}
|
||||
```
|
@ -0,0 +1,74 @@
|
||||
---
|
||||
title: Server-sent events
|
||||
id: version-0.81.0-external_api_server_sent_events
|
||||
original_id: external_api_server_sent_events
|
||||
---
|
||||
|
||||
The [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) feature is a one-way channel from your Home Assistant server to a client which is acting as a consumer. For a bi-directional streaming API, check out the [WebSocket API](external_api_websocket.md).
|
||||
|
||||
The URI that is generating the data is `/api/stream`.
|
||||
|
||||
A requirement on the client-side is existing support for the [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) interface.
|
||||
|
||||
There are various ways to access the stream. If you have not set an `api_password` in the [`http`](https://www.home-assistant.io/components/http/) section of your `configuration.yaml` file then you use your modern browser to read the messages. A command-line option is `curl`:
|
||||
|
||||
```bash
|
||||
$ curl -X GET -H 'Authorization: Bearer ABCDEFGH' \
|
||||
-H "Content-Type: application/json" http://localhost:8123/api/stream
|
||||
```
|
||||
|
||||
> Will no longer work with the new Authentication system.
|
||||
|
||||
You can create a convenient view for this by creating an HTML file (`sse.html`) in the `www` folder of your Home Assistant configuration directory (`.homeassistant`). Paste this snippet into the file:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Getting Home Assistant server events</h1>
|
||||
<div id="events"></div>
|
||||
<script type="text/javascript">
|
||||
var source = new EventSource("/api/stream?api_password=YOUR_PASSWORD");
|
||||
source.onmessage = function(event) {
|
||||
document.getElementById("events").innerHTML += event.data + "<br>";
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Visit [http://localhost:8123/local/sse.html](http://localhost:8123/local/sse.html) to see the stream of events.
|
||||
|
||||
## Examples
|
||||
|
||||
A simple way to consume server-sent events is to use a command-line http client like [httpie](https://httpie.org/). Installation info is on the site (if you use Homebrew, it's `brew install httpie`). Once installed, run this snippet from your terminal:
|
||||
|
||||
```bash
|
||||
$ http --stream http://localhost:8123/api/stream 'Authorization:Bearer ABCDEFGH' content-type:application/json
|
||||
```
|
||||
|
||||
### Website
|
||||
|
||||
> Will no longer work with the new Authentication system.
|
||||
|
||||
The [home-assistant-sse](https://github.com/fabaff/home-assistant-sse) repository contains a more advanced example.
|
||||
|
||||
### Python
|
||||
|
||||
> Will no longer work with the new Authentication system.
|
||||
|
||||
If you want to test the server-sent events without creating a website, the Python module [`sseclient` ](https://pypi.python.org/pypi/sseclient/) can help. To install (assuming Python and pip3 are already installed):
|
||||
|
||||
```bash
|
||||
$ pip3 install sseclient
|
||||
```
|
||||
|
||||
A simple script to consume SSE in Python looks like this:
|
||||
|
||||
```python
|
||||
from sseclient import SSEClient
|
||||
|
||||
messages = SSEClient('http://localhost:8123/api/stream?api_password=YOUR_PASSWORD')
|
||||
for msg in messages:
|
||||
print(msg)
|
||||
```
|
209
website/versioned_docs/version-0.81.0/hassio_addon_config.md
Normal file
209
website/versioned_docs/version-0.81.0/hassio_addon_config.md
Normal file
@ -0,0 +1,209 @@
|
||||
---
|
||||
title: Add-On Configuration
|
||||
id: version-0.81.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 | 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`, `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`.
|
||||
| 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.
|
||||
| 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.
|
@ -1,4 +1,5 @@
|
||||
[
|
||||
"0.81.0",
|
||||
"0.80.0",
|
||||
"0.79.0",
|
||||
"0.78.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user