mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-25 18:26:29 +00:00
Release 105
This commit is contained in:
parent
2fa24e3ff7
commit
f38d749f22
@ -734,6 +734,58 @@
|
||||
"version-0.104.0/version-0.104.0-reproduce_state_index": {
|
||||
"title": "Reproduce State / Scene support"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-app_integration_notifications": {
|
||||
"title": "Push Notifications"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-app_integration_sensors": {
|
||||
"title": "Sensors"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-dev_101_services": {
|
||||
"title": "Integration Services",
|
||||
"sidebar_label": "Custom Services"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-device_automation_condition": {
|
||||
"title": "Device Conditions",
|
||||
"sidebar_label": "Conditions"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-documentation_standards": {
|
||||
"title": "Standards"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-entity_cover": {
|
||||
"title": "Cover Entity",
|
||||
"sidebar_label": "Cover"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-entity_index": {
|
||||
"title": "Entity",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-entity_lock": {
|
||||
"title": "Lock Entity",
|
||||
"sidebar_label": "Lock"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-entity_registry_disabled_by": {
|
||||
"title": "Entity Registry and disabling entities",
|
||||
"sidebar_label": "Disabling entities"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-external_api_rest": {
|
||||
"title": "REST API"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-frontend_data": {
|
||||
"title": "Frontend data",
|
||||
"sidebar_label": "Data"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-hassio_addon_config": {
|
||||
"title": "Add-On Configuration"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-hassio_addon_presentation": {
|
||||
"title": "Presenting your addon"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-integration_fetching_data": {
|
||||
"title": "Fetching Data"
|
||||
},
|
||||
"version-0.105.0/version-0.105.0-integration_quality_scale_index": {
|
||||
"title": "Integration Quality Scale"
|
||||
},
|
||||
"version-0.72/version-0.72-architecture_components": {
|
||||
"title": "Components Architecture",
|
||||
"sidebar_label": "Components"
|
||||
|
@ -0,0 +1,239 @@
|
||||
---
|
||||
title: Push Notifications
|
||||
id: version-0.105.0-app_integration_notifications
|
||||
original_id: app_integration_notifications
|
||||
---
|
||||
|
||||
The `mobile_app` component has a notify platform built in that allows for a generic way to send push notifications to your users without requiring installation of an external custom component.
|
||||
|
||||
## Enabling push notifications
|
||||
|
||||
To enable the notify platform for your application, you must set two keys in the `app_data` object during the initial registration or later update of an existing registration.
|
||||
|
||||
| Key | Type | Description
|
||||
| --- | ---- | -----------
|
||||
| `push_token` | string | A push notification token unique to your users device. For example, this could be a APNS token or a FCM Instance ID/token.
|
||||
| `push_url` | string | The URL on your server that push notifications will be HTTP POSTed to.
|
||||
|
||||
You should advise the user to restart Home Assistant after you set these keys in order for them to see the notify target. It will have the format `notify.mobile_app_<safed_device_name>`.
|
||||
|
||||
## Deploying a server component
|
||||
|
||||
The notify platform doesn't concern itself with how to notify your users. It simply forwards a notification to your external server where you should actually handle the request.
|
||||
This approach allows you to maintain full control over your push notification infrastructure.
|
||||
|
||||
See the next section of this document for an example server implementation of a push notification forwarder that uses Firebase Cloud Functions and Firebase Cloud Messaging.
|
||||
|
||||
Your server should accept a HTTP POST payload like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World",
|
||||
"title": "Test message sent via mobile_app.notify",
|
||||
"push_token": "my-secure-token",
|
||||
"registration_info": {
|
||||
"app_id": "io.home-assistant.iOS",
|
||||
"app_version": "1.0.0",
|
||||
"os_version": "12.2"
|
||||
},
|
||||
"data": {
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It should respond with a 201 status code assuming the notification was queued for delivery successfully.
|
||||
|
||||
### Errors
|
||||
|
||||
If an error occurs you should return a description of what went wrong with a status code _other than_ 201 or 429. An error response must be a JSON object and can contain one of the following keys:
|
||||
|
||||
| Key | Type | Description
|
||||
| --- | ---- | -----------
|
||||
| `errorMessage` | string | If provided, it will be appended to a preset error message. For example, if `errorMessage` is "Could not communicate with Apple" it will be output in the log like "Internal server error, please try again later: Could not communicate with Apple"
|
||||
| `message` | string | If provided, it will be output directly to the logs at the warning log level.
|
||||
|
||||
No matter what key you use, you should try to be as descriptive as possible about what went wrong and, if possible, how the user can fix it.
|
||||
|
||||
### Rate limits
|
||||
|
||||
The notify platform also supports exposing rate limits to users. Home Assistant suggests you implement a conservative rate limit to keep your costs low and also so that users don't overload themselves with too many notifications.
|
||||
For reference, Home Assistant Companion has a maximum sendable notifications per 24 hours of 150 notifications. The rate limit resets for all users at midnight, UTC. You of course are free to use whatever configuration for your own rate limiting.
|
||||
|
||||
If you choose to implement rate limiting, your successful server response should look like the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"rateLimits": {
|
||||
"successful": 1,
|
||||
"errors": 5,
|
||||
"maximum": 150,
|
||||
"resetsAt": "2019-04-08T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Type | Description
|
||||
| --- | ---- | -----------
|
||||
| `successful` | integer | The number of successful push notifications the user has sent during the rate limit period.
|
||||
| `errors` | integer | The number of failed push notifications the user has sent during the rate limit period.
|
||||
| `maximum` | integer | The maximum number of push notifications the user can send during the users rate limit period.
|
||||
| `resetsAt` | ISO8601 timestamp | The timestamp that the users rate limit period expires at. Must be provided in the UTC timezone.
|
||||
|
||||
The rate limits will be output to the log at the warning log level after every notification is successfully sent. Home Assistant will also output the exact time remaining until the rate limit period resets.
|
||||
|
||||
Once the user hits their maximum amount of notifications sent in the rate limit period, you should start responding with a 429 status code until the rate limit period expires. The response object can optionally contain a key, `message` which will be output to the Home Assistant log instead of the standard error message.
|
||||
|
||||
The notify platform does not itself implement any kind of rate limit protections. Users will be able to keep sending you notifications, so you should reject them with a 429 status code as early in your logic as possible.
|
||||
|
||||
## Example server implementation
|
||||
The below code is a Firebase Cloud Function that forwards notifications to Firebase Cloud Messaging. To deploy this, you should create a new Firestore database named `rateLimits`. Then, you can deploy the following code.
|
||||
Also, ensure that you have properly configured your project with the correct authentication keys for APNS and FCM.
|
||||
|
||||
```javascript
|
||||
'use strict';
|
||||
|
||||
const functions = require('firebase-functions');
|
||||
const admin = require('firebase-admin');
|
||||
admin.initializeApp();
|
||||
|
||||
var db = admin.firestore();
|
||||
|
||||
const MAX_NOTIFICATIONS_PER_DAY = 150;
|
||||
|
||||
exports.sendPushNotification = functions.https.onRequest(async (req, res) => {
|
||||
console.log('Received payload', req.body);
|
||||
var today = getToday();
|
||||
var token = req.body.push_token;
|
||||
var ref = db.collection('rateLimits').doc(today).collection('tokens').doc(token);
|
||||
|
||||
var payload = {
|
||||
notification: {
|
||||
body: req.body.message,
|
||||
},
|
||||
token: token,
|
||||
};
|
||||
|
||||
if(req.body.title) {
|
||||
payload.notification.title = req.body.title;
|
||||
}
|
||||
|
||||
if(req.body.data) {
|
||||
if(req.body.data.android) {
|
||||
payload.android = req.body.data.android;
|
||||
}
|
||||
if(req.body.data.apns) {
|
||||
payload.apns = req.body.data.apns;
|
||||
}
|
||||
if(req.body.data.data) {
|
||||
payload.data = req.body.data.data;
|
||||
}
|
||||
if(req.body.data.webpush) {
|
||||
payload.webpush = req.body.data.webpush;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Notification payload', JSON.stringify(payload));
|
||||
|
||||
var docExists = false;
|
||||
var docData = {
|
||||
deliveredCount: 0,
|
||||
errorCount: 0,
|
||||
totalCount: 0,
|
||||
};
|
||||
|
||||
try {
|
||||
let currentDoc = await ref.get();
|
||||
docExists = currentDoc.exists;
|
||||
if(currentDoc.exists) {
|
||||
docData = currentDoc.data();
|
||||
}
|
||||
} catch(err) {
|
||||
console.error('Error getting document!', err);
|
||||
return handleError(res, 'getDoc', err);
|
||||
}
|
||||
|
||||
if(docData.deliveredCount > MAX_NOTIFICATIONS_PER_DAY) {
|
||||
return res.status(429).send({
|
||||
errorType: 'RateLimited',
|
||||
message: 'The given target has reached the maximum number of notifications allowed per day. Please try again later.',
|
||||
target: token,
|
||||
rateLimits: getRateLimitsObject(docData),
|
||||
});
|
||||
}
|
||||
|
||||
docData.totalCount = docData.totalCount + 1;
|
||||
|
||||
var messageId;
|
||||
try {
|
||||
messageId = await admin.messaging().send(payload);
|
||||
docData.deliveredCount = docData.deliveredCount + 1;
|
||||
} catch(err) {
|
||||
docData.errorCount = docData.errorCount + 1;
|
||||
await setRateLimitDoc(ref, docExists, docData, res);
|
||||
return handleError(res, 'sendNotification', err);
|
||||
}
|
||||
|
||||
console.log('Successfully sent message:', messageId);
|
||||
|
||||
await setRateLimitDoc(ref, docExists, docData, res);
|
||||
|
||||
return res.status(201).send({
|
||||
messageId: messageId,
|
||||
sentPayload: payload,
|
||||
target: token,
|
||||
rateLimits: getRateLimitsObject(docData),
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
async function setRateLimitDoc(ref, docExists, docData, res) {
|
||||
try {
|
||||
if(docExists) {
|
||||
console.log('Updating existing doc!');
|
||||
await ref.update(docData);
|
||||
} else {
|
||||
console.log('Creating new doc!');
|
||||
await ref.set(docData);
|
||||
}
|
||||
} catch(err) {
|
||||
if(docExists) {
|
||||
console.error('Error updating document!', err);
|
||||
} else {
|
||||
console.error('Error creating document!', err);
|
||||
}
|
||||
return handleError(res, 'setDocument', err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleError(res, step, incomingError) {
|
||||
if (!incomingError) return null;
|
||||
console.error('InternalError during', step, incomingError);
|
||||
return res.status(500).send({
|
||||
errorType: 'InternalError',
|
||||
errorStep: step,
|
||||
message: incomingError.message,
|
||||
});
|
||||
}
|
||||
|
||||
function getToday() {
|
||||
var today = new Date();
|
||||
var dd = String(today.getDate()).padStart(2, '0');
|
||||
var mm = String(today.getMonth() + 1).padStart(2, '0');
|
||||
var yyyy = today.getFullYear();
|
||||
return yyyy + mm + dd;
|
||||
}
|
||||
|
||||
function getRateLimitsObject(doc) {
|
||||
var d = new Date();
|
||||
return {
|
||||
successful: (doc.deliveredCount || 0),
|
||||
errors: (doc.errorCount || 0),
|
||||
total: (doc.totalCount || 0),
|
||||
maximum: MAX_NOTIFICATIONS_PER_DAY,
|
||||
remaining: (MAX_NOTIFICATIONS_PER_DAY - doc.deliveredCount),
|
||||
resetsAt: new Date(d.getFullYear(), d.getMonth(), d.getDate()+1)
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Sensors
|
||||
id: version-0.105.0-app_integration_sensors
|
||||
original_id: app_integration_sensors
|
||||
---
|
||||
|
||||
The `mobile_app` component supports exposing custom sensors that can be managed entirely via your app.
|
||||
|
||||
## Registering a sensor
|
||||
|
||||
All sensors must be registered before they can get updated. You can only register one sensor at a time, unlike updating sensors.
|
||||
|
||||
To register a sensor, make a request to the webhook like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"attributes": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"device_class": "battery",
|
||||
"icon": "mdi:battery",
|
||||
"name": "Battery State",
|
||||
"state": "12345",
|
||||
"type": "sensor",
|
||||
"unique_id": "battery_state",
|
||||
"unit_of_measurement": "%"
|
||||
},
|
||||
"type": "register_sensor"
|
||||
}
|
||||
```
|
||||
|
||||
The valid keys are:
|
||||
|
||||
| Key | Type | Required | Description |
|
||||
|---------------------|-------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| attributes | object | No | Attributes to attach to the sensor |
|
||||
| device_class | string | No | One of the valid device classes. [Binary Sensor Classes](https://www.home-assistant.io/components/binary_sensor/#device-class), [Sensor Classes](https://www.home-assistant.io/components/sensor/#device-class) |
|
||||
| icon | Material Design Icon (string) | No | Must be prefixed `mdi:`. If not provided, default value is `mdi:cellphone` |
|
||||
| name | string | Yes | The name of the sensor |
|
||||
| state | bool, float, int, string | Yes | The state of the sensor |
|
||||
| type | string | Yes | The type of the sensor. Must be one of `binary_sensor` or `sensor` |
|
||||
| unique_id | string | Yes | An identifier unique to this installation of your app. You'll need this later. Usually best when its a safe version of the sensor name |
|
||||
| unit_of_measurement | string | No | The unit of measurement for the sensor |
|
||||
|
||||
Sensors will appear as soon as they are registered.
|
||||
|
||||
## Updating a sensor
|
||||
|
||||
Once a sensor has been registered, you need to update it. This is very similar to registering it, but you can update all your sensors at the same time.
|
||||
|
||||
For example, to update the sensor we registered above, you would send this:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"attributes": {
|
||||
"hello": "world"
|
||||
},
|
||||
"icon": "mdi:battery",
|
||||
"state": 123,
|
||||
"type": "sensor",
|
||||
"unique_id": "battery_state"
|
||||
}
|
||||
],
|
||||
"type": "update_sensor_states"
|
||||
}
|
||||
```
|
||||
|
||||
Only some of the keys are allowed during updates:
|
||||
|
||||
| Key | Type | Required | Description |
|
||||
|---------------------|-------------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| attributes | object | No | Attributes to attach to the sensor |
|
||||
| icon | Material Design Icon (string) | No | Must be prefixed `mdi:` |
|
||||
| state | bool, float, int, string | Yes | The state of the sensor |
|
||||
| type | string | Yes | The type of the sensor. Must be one of `binary_sensor` or `sensor` |
|
||||
| unique_id | string | Yes | An identifier unique to this installation of your app. You'll need this later. Usually best when its a safe version of the sensor name |
|
||||
|
109
website/versioned_docs/version-0.105.0/dev_101_services.md
Normal file
109
website/versioned_docs/version-0.105.0/dev_101_services.md
Normal file
@ -0,0 +1,109 @@
|
||||
---
|
||||
title: Integration Services
|
||||
sidebar_label: Custom Services
|
||||
id: version-0.105.0-dev_101_services
|
||||
original_id: dev_101_services
|
||||
---
|
||||
|
||||
Home Assistant provides ready-made services for a lot of things, but it doesn't always cover everything. Instead of trying to change Home Assistant, it is preferred to add it as a service under your own integration first. Once we see a pattern in these services, we can talk about generalizing them.
|
||||
|
||||
This is a simple "hello world" example to show the basics of registering a service. To use this example, create the file `<config dir>/custom_components/hello_service/__init__.py` and copy the below example code.
|
||||
|
||||
Services can be called from automations and from the service "Developer tools" in the frontend.
|
||||
|
||||
```python
|
||||
DOMAIN = "hello_service"
|
||||
|
||||
ATTR_NAME = "name"
|
||||
DEFAULT_NAME = "World"
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up is called when Home Assistant is loading our component."""
|
||||
|
||||
def handle_hello(call):
|
||||
"""Handle the service call."""
|
||||
name = call.data.get(ATTR_NAME, DEFAULT_NAME)
|
||||
|
||||
hass.states.set("hello_service.hello", name)
|
||||
|
||||
hass.services.register(DOMAIN, "hello", handle_hello)
|
||||
|
||||
# Return boolean to indicate that initialization was successfully.
|
||||
return True
|
||||
```
|
||||
|
||||
Load the integration by adding the following to your `configuration.yaml`. When your component is loaded, a new service should be available to call.
|
||||
|
||||
```yaml
|
||||
# configuration.yaml entry
|
||||
hello_service:
|
||||
```
|
||||
|
||||
Open the frontend and in the sidebar, click the first icon in the developer tool section. This will open the Call Service developer tool. On the right, find your service and click on it. This will automatically fill in the correct values.
|
||||
|
||||
Pressing "Call Service" will now call your service without any parameters. This will cause your service to create a state with the default name 'World'. If you want to specify the name, you have to specify parameters. Add the following JSON as Service Data and press "Call Service again".
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Planet"
|
||||
}
|
||||
```
|
||||
|
||||
The service will now overwrite the previous state with "Planet".
|
||||
|
||||
## Service descriptions
|
||||
|
||||
Adding services is only useful if users know about them. In Home Assistant we use a `services.yaml` as part of your integration to describe the services.
|
||||
|
||||
Services are published under the domain name of your integration, so in `services.yaml` we only use the service name as the base key.
|
||||
|
||||
```yaml
|
||||
# Example services.yaml entry
|
||||
|
||||
set_speed:
|
||||
# Description of the service
|
||||
description: Sets fan speed.
|
||||
# Different fields that your service accepts
|
||||
fields:
|
||||
# Key of the field
|
||||
entity_id:
|
||||
# Description of the field
|
||||
description: Name(s) of the entities to set
|
||||
# Example value that can be passed for this field
|
||||
example: "fan.living_room"
|
||||
speed:
|
||||
description: Speed setting
|
||||
example: "low"
|
||||
```
|
||||
|
||||
## Entity Services
|
||||
|
||||
Sometimes you want to provide extra services to control your entities. For example, the Sonos integration provides services to group and ungroup devices. Entity services are special because there are many different ways a user can specify entities. It can use areas, a group or a list of entities.
|
||||
|
||||
You need to register entity services in your platforms, like `<your-domain>/media_player.py`. These services will be made available under your domain and not the media player domain. Example code:
|
||||
|
||||
```python
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform, service
|
||||
|
||||
async def async_setup_entry(hass, entry):
|
||||
"""Set up the media player platform for Sonos."""
|
||||
|
||||
platform = entity_platform.current_platform.get()
|
||||
|
||||
# This will call Entity.set_sleep_timer(sleep_time=VALUE)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_TIMER,
|
||||
{
|
||||
vol.Required('sleep_time'): cv.time_period,
|
||||
},
|
||||
"set_sleep_timer",
|
||||
)
|
||||
```
|
||||
|
||||
If you need more control over the service call, you can also pass an async function that instead of `"set_sleep_timer"`:
|
||||
|
||||
```python
|
||||
async def custom_set_sleep_timer(entity, service_call):
|
||||
await entity.set_sleep_timer(service_call.data['sleep_time'])
|
||||
```
|
@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Device Conditions
|
||||
sidebar_label: Conditions
|
||||
id: version-0.105.0-device_automation_condition
|
||||
original_id: device_automation_condition
|
||||
---
|
||||
|
||||
Device conditions allow a user to check if a certain condition is met. Examples are is a light on or is the floor wet.
|
||||
|
||||
Device conditions are defined as dictionaries. These dictionaries are created by your integration and are passed to your integration to create a function that checks the condition.
|
||||
|
||||
Device conditions can be provided by the integration that provides the device (e.g. ZHA, deCONZ) or the entity integrations that the device has entities with (e.g. light, humidity sensor).
|
||||
An example of the latter could be to check if a light is on or the floor is wet.
|
||||
|
||||
Home Assistant includes a template to get started with device conditions. To get started, run inside a development environment `python3 -m script.scaffold device_condition`.
|
||||
|
||||
The template will create a new file `device_condition.py` in your integration folder and a matching test file. The file contains the following functions and constants:
|
||||
|
||||
## `CONDITION_SCHEMA`
|
||||
|
||||
This is the schema for conditions. The base schema should be extended from `homeassistant.helpers.config_validation.DEVICE_CONDITION_BASE_SCHEMA`.
|
||||
|
||||
## `async async_get_conditions(hass, device_id)`
|
||||
|
||||
Return a list of conditions that this device supports.
|
||||
|
||||
## `async async_condition_from_config(config, config_validation)`
|
||||
|
||||
Create a condition function from a function. The condition functions should be an async-friendly callback that evaluates the condition and returns a `bool`.
|
@ -0,0 +1,123 @@
|
||||
---
|
||||
title: Standards
|
||||
id: version-0.105.0-documentation_standards
|
||||
original_id: documentation_standards
|
||||
---
|
||||
|
||||
To ensure that the documentation for Home Assistant is consistent and easy to follow for both novice and expert users, we ask that you follow a very strict set of standards for developing the documentation.
|
||||
|
||||
## General Documentation
|
||||
|
||||
* The language of the documentation should be American-English.
|
||||
* Don't put two spaces after a period and avoid the "Oxford comma".
|
||||
* There is no limit for the line length. You are allowed to write in a flowing text style. This will make it easier to use the GitHub online editor in the future.
|
||||
* Be objective and not gender favoring, polarizing, race related or religion inconsiderate.
|
||||
* The case of brand names, services, protocols, integrations and platforms must match its respective counterpart. e.g., "Z-Wave" **not** "Zwave", "Z-wave", "Z Wave" or "ZWave". Also, "Input Select" **not** "input select" or "Input select".
|
||||
* Do not use ALL CAPITALS for emphasis - use italics instead.
|
||||
|
||||
## Integration and Platform Pages
|
||||
|
||||
* The **Configuration Variables** section must use the `{% configuration %}` tag.
|
||||
* Configuration variables must document the requirement status (`false` or `true`).
|
||||
* Configuration variables must document the default value, if any.
|
||||
* Configuration variables must document the accepted value types (see [Configuration variables details](documentation_create_page.md#configuration)).
|
||||
* For configuration variables that accept multiple types, separate the types with a comma (i.e. `string, int`).
|
||||
* Use YAML sequence syntax in the sample code if it is supported.
|
||||
* All examples should be formatted to be included in `configuration.yaml` unless explicitly stated.
|
||||
* Use capital letters and `_` to indicate that the value needs to be replaced. E.g., `api_key: YOUR_API_KEY` or `api_key: REPLACE_ME`.
|
||||
* If you know that the API key or value contains [control characters](https://en.wikipedia.org/wiki/YAML#Syntax), e.g., `#`, `[`, `?`, etc., wrap it in quotes and add a note.
|
||||
* Integration and platform names should be a link to their respective documentation pages.
|
||||
|
||||
Example configuration block
|
||||
|
||||
```yaml
|
||||
{% configuration %}
|
||||
some_key:
|
||||
description: This is a description of what this key is for.
|
||||
required: false
|
||||
type: string
|
||||
default: Optional default value - leave out if there isn't one
|
||||
{% endconfiguration %}
|
||||
```
|
||||
|
||||
## Templates
|
||||
|
||||
* All examples containing Jinja2 templates should be wrapped **outside** of the code markdown with the `{% raw %}` tag.
|
||||
* Do not use `states.switch.source.state` in templates. Instead use `states()` and `is_state()`.
|
||||
* Use double quotes (`"`) for ([more information](#single-vs-double-quotation-marks)):
|
||||
* `friendly_name`
|
||||
* Single-line templates:
|
||||
* `value_template`
|
||||
* `level_template`
|
||||
* `icon_template`
|
||||
* Children of `data_template`
|
||||
* Use single quotes (`'`) for ([more information](#single-vs-double-quotation-marks):
|
||||
* Strings inside of templates:
|
||||
* States
|
||||
* Entity IDs
|
||||
* `unit_of_measurement`
|
||||
* No whitespace around pipe character (`|`) for Jinja2 filters.
|
||||
* Single whitespace after Jinja2 opening delimiters ({% raw %}`{{`{% endraw %}).
|
||||
* Single whitespace before Jinja2 closing delimiters ({% raw %}`}}`{% endraw %}).
|
||||
* Do not quote values for:
|
||||
* `device_class`
|
||||
* `platform`
|
||||
* `condition`
|
||||
* `service`
|
||||
|
||||
## Renaming Pages
|
||||
|
||||
It can happen that an integration or platform is renamed, in this case the documentation needs to be updated as well. If you rename a page, add `redirect_from:` to the file header and let it point to the old location/name of the page. Please consider to add details, like release number or old integration/platform name, to the page in a [note](/developers/documentation/create_page/#html).
|
||||
|
||||
```text
|
||||
---
|
||||
...
|
||||
redirect_from: /getting-started/android/
|
||||
---
|
||||
```
|
||||
|
||||
Adding a redirect also applies if you move content around in the [documentation](https://www.home-assistant.io/docs/).
|
||||
|
||||
## Single vs. Double Quotation Marks
|
||||
|
||||
Use single quotes (`'`) for strings inside of a template. It is more obvious to escape a single quote when necessary (i.e. `name` is a possessive noun), because the single quotes that wrap the string are closer in position to the apostrophe inside the string. Use double quotes (`"`) outside of a template (unless it is a multi-line template, in which case outside quotes are not required).
|
||||
|
||||
### Examples
|
||||
|
||||
#### Double Quotes Outside, Single Quotes Inside (Valid)
|
||||
|
||||
```yaml
|
||||
automation:
|
||||
...
|
||||
action:
|
||||
- service: notify.notify
|
||||
data_template:
|
||||
message: "{% if trigger.to_state.name == 'Dale\'s Bedroom' %}Someone's in your base, killing your noobs!{% else %}It's just another door.{% endif %}"
|
||||
```
|
||||
|
||||
#### Single Quotes Outside, Double Quotes Inside (Invalid)
|
||||
|
||||
```yaml
|
||||
automation:
|
||||
...
|
||||
action:
|
||||
- service: notify.notify
|
||||
data_template:
|
||||
message: '{% if trigger.to_state.name == "Dale's Bedroom" %}Someone's in your base, killing your noobs!{% else %}It's just another door.{% endif %}'
|
||||
```
|
||||
|
||||
#### Multi-Line Template (Valid)
|
||||
|
||||
```yaml
|
||||
automation:
|
||||
...
|
||||
action:
|
||||
- service: notify.notify
|
||||
data_template:
|
||||
message: >-
|
||||
{% if trigger.to_state.name == 'Dale\'s Bedroom' %}
|
||||
Someone's in your base, killing your noobs!
|
||||
{% else %}
|
||||
It's just another door.
|
||||
{% endif %}
|
||||
```
|
188
website/versioned_docs/version-0.105.0/entity_cover.md
Normal file
188
website/versioned_docs/version-0.105.0/entity_cover.md
Normal file
@ -0,0 +1,188 @@
|
||||
---
|
||||
title: Cover Entity
|
||||
sidebar_label: Cover
|
||||
id: version-0.105.0-entity_cover
|
||||
original_id: entity_cover
|
||||
---
|
||||
|
||||
A cover entity is a device that controls an opening or cover, such as a garage door and window shade. Derive entity platforms from [`homeassistant.components.cover.CoverDevice`](https://github.com/home-assistant/home-assistant/blob/master/homeassistant/components/cover/__init__.py).
|
||||
|
||||
## Properties
|
||||
|
||||
> Properties should always only return information from memory and not do I/O (like network requests). Implement `update()` or `async_update()` to fetch data.
|
||||
|
||||
### Platform Properties (to be implemented by deriving platform classes)
|
||||
|
||||
| Name | Type | Default | Description
|
||||
| ---- | ---- | ------- | -----------
|
||||
| current_cover_position | int | None | The current position of cover where 0 means closed and 100 is fully open. Required with `SUPPORT_SET_POSITION`.
|
||||
| current_cover_tilt_position | int | None | The current tilt position of the cover where 0 means closed/no tilt and 100 means open/maximum tilt. Required with `SUPPORT_SET_TILT_POSITION`
|
||||
| is_opening | bool | None | If the cover is opening or not. Used to determine `state`.
|
||||
| is_closing | bool | None | If the cover is closing or not. Used to determine `state`.
|
||||
| is_closed | bool | `NotImplementedError()` | If the cover is closed or not. if the state is unknown, return `None`. Used to determine `state`.
|
||||
|
||||
### Entity Properties (base class properties which may be overridden)
|
||||
|
||||
| Name | Type | Default | Description
|
||||
| ---- | ---- | ------- | -----------
|
||||
| device_class | string | None | Describes the type/class of the cover. Must be `None` or one of the valid values from the table below.
|
||||
| supported_features | int (bitwise) | Value determined from `current_cover_position` and `current_cover_tilt_position` | Describes the supported features. See the related table below for details.
|
||||
|
||||
### Device Classes
|
||||
| Constant | Description
|
||||
|----------|-----------------------|
|
||||
| `DEVICE_CLASS_AWNING` | Control of an awning, such as an exterior retractible window, door, or patio cover.
|
||||
| `DEVICE_CLASS_BLIND` | Control of blinds, which are linked slats that expand or collapse to cover an opening or may be tilted to partially cover an opening, such as window blinds.
|
||||
| `DEVICE_CLASS_CURTAIN` | Control of curtains or drapes, which is often fabric hung above a window or door that can be drawn open.
|
||||
| `DEVICE_CLASS_DAMPER` | Control of a mechanical damper that reduces air flow, sound, or light.
|
||||
| `DEVICE_CLASS_DOOR` | Control of a door or gate that provides access to an area.
|
||||
| `DEVICE_CLASS_GARAGE` | Control of a garage door that provides access to a garage.
|
||||
| `DEVICE_CLASS_SHADE` | Control of shades, which are a continuous plane of material or connected cells that expanded or collapsed over an opening, such as window shades.
|
||||
| `DEVICE_CLASS_SHUTTER` | Control of shutters, which are linked slats that swing out/in to cover an opening or may be tilted to partially cover an opening, such as indoor or exterior window shutters.
|
||||
| `DEVICE_CLASS_WINDOW` | Control of a physical window that opens and closes or may tilt.
|
||||
|
||||
### States
|
||||
| Constant | Description
|
||||
|----------|------------------------|
|
||||
| `STATE_OPENING` | The cover is in the process of opening to reach a set position.
|
||||
| `STATE_OPEN` | The cover has reached the open position.
|
||||
| `STATE_CLOSING` | The cover is in the process of closing to reach a set position.
|
||||
| `STATE_CLOSED` | The cover has reach the closed position.
|
||||
|
||||
|
||||
### Supported Features
|
||||
|
||||
Supported features constants are combined using the bitwise or (`|`) operator.
|
||||
|
||||
| Constant | Description |
|
||||
|----------|--------------------------------------|
|
||||
| `SUPPORT_OPEN` | The cover supports being opened.
|
||||
| `SUPPORT_CLOSE` | The cover supports being closed.
|
||||
| `SUPPORT_SET_POSITION` | The cover supports moving to a specific position between opened and closed.
|
||||
| `SUPPORT_STOP` | The cover supports stopping the current action (open, close, set position)
|
||||
| `SUPPORT_OPEN_TILT` | The cover supports being tilting open.
|
||||
| `SUPPORT_CLOSE_TILT` | The cover supports being tilting closed.
|
||||
| `SUPPORT_SET_TILT_POSITION` | The cover supports moving to a specific tilt position between opened and closed.
|
||||
| `SUPPORT_STOP_TILT` | The cover supports stopping the current tilt action (open, close, set position)
|
||||
|
||||
## Methods
|
||||
|
||||
### Open cover
|
||||
|
||||
Only implement this method if the flag `SUPPORT_OPEN` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def open_cover(self, **kwargs):
|
||||
"""Open the cover."""
|
||||
|
||||
async def async_open_cover(self, **kwargs):
|
||||
"""Open the cover."""
|
||||
```
|
||||
|
||||
### Close cover
|
||||
|
||||
Only implement this method if the flag `SUPPORT_CLOSE` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def close_cover(self, **kwargs):
|
||||
"""Close cover."""
|
||||
|
||||
async def async_close_cover(self, **kwargs):
|
||||
"""Close cover."""
|
||||
```
|
||||
|
||||
### Set cover position
|
||||
|
||||
Only implement this method if the flag `SUPPORT_SET_POSITION` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def set_cover_position(self, **kwargs):
|
||||
"""Move the cover to a specific position."""
|
||||
|
||||
async def async_set_cover_position(self, **kwargs):
|
||||
"""Move the cover to a specific position."""
|
||||
```
|
||||
|
||||
### Stop cover
|
||||
|
||||
Only implement this method if the flag `SUPPORT_STOP` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def stop_cover(self, **kwargs):
|
||||
"""Stop the cover."""
|
||||
|
||||
async def async_stop_cover(self, **kwargs):
|
||||
"""Stop the cover."""
|
||||
```
|
||||
|
||||
### Open cover tilt
|
||||
|
||||
Only implement this method if the flag `SUPPORT_OPEN_TILT` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def open_cover_tilt(self, **kwargs):
|
||||
"""Open the cover tilt."""
|
||||
|
||||
async def async_open_cover_tilt(self, **kwargs):
|
||||
"""Open the cover tilt."""
|
||||
```
|
||||
|
||||
### Close cover tilt
|
||||
|
||||
Only implement this method if the flag `SUPPORT_CLOSE_TILT` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def close_cover_tilt(self, **kwargs):
|
||||
"""Close the cover tilt."""
|
||||
|
||||
async def async_close_cover_tilt(self, **kwargs):
|
||||
"""Close the cover tilt."""
|
||||
```
|
||||
|
||||
### Set cover tilt position
|
||||
|
||||
Only implement this method if the flag `SUPPORT_SET_TILT_POSITION` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def set_cover_tilt_position(self, **kwargs):
|
||||
"""Move the cover tilt to a specific position."""
|
||||
|
||||
async def async_set_cover_tilt_position(self, **kwargs):
|
||||
"""Move the cover tilt to a specific position."""
|
||||
```
|
||||
|
||||
### Stop cover tilt
|
||||
|
||||
Only implement this method if the flag `SUPPORT_STOP_TILT` is set.
|
||||
|
||||
```python
|
||||
class MyCover(CoverDevice):
|
||||
# Implement one of these methods.
|
||||
|
||||
def stop_cover_tilt(self, **kwargs):
|
||||
"""Stop the cover."""
|
||||
|
||||
async def async_stop_cover_tilt(self, **kwargs):
|
||||
"""Stop the cover."""
|
||||
```
|
114
website/versioned_docs/version-0.105.0/entity_index.md
Normal file
114
website/versioned_docs/version-0.105.0/entity_index.md
Normal file
@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Entity
|
||||
sidebar_label: Introduction
|
||||
id: version-0.105.0-entity_index
|
||||
original_id: entity_index
|
||||
---
|
||||
|
||||
Each device is represented in Home Assistant as an entity. An entity abstracts away the internal working of Home Assistant. As an integrator you don't have to worry about how services or the state machine work. Instead, you extend an entity class and implement the necessary properties and methods for the device type that you're integrating.
|
||||
|
||||
Below is an example switch entity that keeps track of their state in memory.
|
||||
|
||||
```python
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
|
||||
class MySwitch(SwitchDevice):
|
||||
def __init__(self):
|
||||
self._is_on = False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Name of the device."""
|
||||
return "My Switch"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""If the switch is currently on or off."""
|
||||
return self._is_on
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the switch on."""
|
||||
self._is_on = True
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the switch off."""
|
||||
self._is_on = False
|
||||
```
|
||||
|
||||
That's all there is to it to build a switch entity! Continue reading to learn more or check out the [video tutorial](https://youtu.be/Cfasc9EgbMU?t=737).
|
||||
|
||||
## Updating the entity
|
||||
|
||||
An entity represents a device. There are various strategies to keep your entity in sync with the state of the device, the most popular one being polling.
|
||||
|
||||
### Polling
|
||||
|
||||
With polling, Home Assistant will ask the entity from time to time (depending on the update interval of the component) to fetch the latest state. Home Assistant will poll an entity when the `should_poll` property returns `True` (the default value). You can either implement your update logic using `update()` or the async method `async_update()`. This method should fetch the latest state from the device and store it in an instance variable for the properties to return it.
|
||||
|
||||
### Subscribing to updates
|
||||
|
||||
When you subscribe to updates, your code is responsible for letting Home Assistant know that an update is available. Make sure you have the `should_poll` property return `False`.
|
||||
|
||||
Whenever you receive new state from your subscription, you can tell Home Assistant that an update is available by calling `schedule_update_ha_state()` or async callback `async_schedule_update_ha_state()`. Pass in the boolean `True` to the method if you want Home Assistant to call your update method before writing the update to Home Assistant.
|
||||
|
||||
## Generic properties
|
||||
|
||||
The entity base class has a few properties that are common among all entities in Home Assistant. These can be added to any entity regardless of the type. All these properties are optional and don't need to be implemented.
|
||||
|
||||
> Properties should always only return information from memory and not do I/O (like network requests). Implement `update()` or `async_update()` to fetch data.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ----------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| assumed_state | boolean | `False` | Return `True` if the state is based on our assumption instead of reading it from the device. |
|
||||
| available | boolean | `True` | Indicate if Home Assistant is able to read the state and control the underlying device. |
|
||||
| device_class | string | `None` | Extra classification of what the device is. Each domain specifies their own. Device classes can come with extra requirements for unit of measurement and supported features. |
|
||||
| device_state_attributes | dict | `None` | Extra information to store in the state machine. It needs to be information that further explains the state, it should not be static information like firmware version. See [below](entity_index.md#standard-attributes) for details of standard attributes. |
|
||||
| entity_picture | URL | `None` | Url of a picture to show for the entity. |
|
||||
| name | string | `None` | Name of the entity |
|
||||
| should_poll | boolean | `True` | Should Home Assistant check with the entity for an updated state. If set to `False`, entity will need to notify Home Assistant of new updates by calling one of the [schedule update methods](#methods). |
|
||||
| unique_id | string | `None` | A unique identifier for this entity. Needs to be unique within a platform (ie `light.hue`). Should not be configurable by the user or be changeable. [Learn more.](entity_registry_index.md#unique-id-requirements) |
|
||||
|
||||
## Advanced properties
|
||||
|
||||
The following properties are also available on entities. However, they are for advanced use only and should be used with caution.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------------------------- | ------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| force_update | boolean | `False` | Write each update to the state machine, even if the data is the same. Example use: when you are directly reading the value from a connected sensor instead of a cache. Use with caution, will spam the state machine. |
|
||||
| hidden | boolean | `False` | Indicate if the entity should not be shown on the frontend. Deprecated. Will be removed in 0.107.0 |
|
||||
| icon | icon | `None` | Icon to use in the frontend. Icons start with `mdi:` plus an [identifier](https://materialdesignicons.com/). You probably don't need this since Home Assistant already provides default icons for all devices. |
|
||||
| entity_registry_enabled_default | boolean | `True` | Indicate if the entity should be enabled or disabled when it is first added to the entity registry. |
|
||||
|
||||
## System properties
|
||||
|
||||
The following properties are used and controlled by Home Assistant, and should not be overridden by integrations.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| enabled | boolean | `True` | Indicate if entity is enabled in the entity registry. It also returns `True` if the platform doesn't support the entity registry. Disabled entities will not be added to Home Assistant. |
|
||||
|
||||
## Standard attributes
|
||||
|
||||
The following `device_state_attributes` are considered standard and should follow the convention below. The constant should be imported from `homeassistant/const.py`.
|
||||
|
||||
| Name | Type | Unit | Constant | Description |
|
||||
| ---------------- | ------- | ---- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| battery_charging | boolean | N/A | `ATTR_BATTERY_CHARGING` | Battery charging status of the entity, shown as a boolean `true` or `false`. If charging is not supported, then this attribute should not be created. |
|
||||
| battery_level | integer | % | `ATTR_BATTERY_LEVEL` | Battery level of the entity, shown as an integer percentage between 0-100. |
|
||||
|
||||
## Lifecycle hooks
|
||||
|
||||
Use these lifecycle hooks to execute code when certain events happen to the entity. All lifecycle hooks are async methods.
|
||||
|
||||
### `async_added_to_hass()`
|
||||
|
||||
Called when an entity has their entity_id and hass object assigned, before it is written to the state machine for the first time. Example uses: restore the state, subscribe to updates or set callback/dispatch function/listener.
|
||||
|
||||
### `async_will_remove_from_hass()`
|
||||
|
||||
Called when an entity is about to be removed from Home Assistant. Example use: disconnect from the server or unsubscribe from updates.
|
||||
|
||||
## Changing the entity model
|
||||
|
||||
If you want to add a new feature to an entity or any of its subtypes (light, switch, etc), you will need to propose it first in our [architecture repo](https://github.com/home-assistant/architecture/issues). Only additions will be considered that are common features among various vendors.
|
66
website/versioned_docs/version-0.105.0/entity_lock.md
Normal file
66
website/versioned_docs/version-0.105.0/entity_lock.md
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Lock Entity
|
||||
sidebar_label: Lock
|
||||
id: version-0.105.0-entity_lock
|
||||
original_id: entity_lock
|
||||
---
|
||||
|
||||
A lock entity is a device which is able to lock and unlock. Locking and unlocking can optionally be secured with a user code. Some locks also allow for opening of latches, this may also be secured with a user code.
|
||||
|
||||
## Properties
|
||||
|
||||
> Properties should always only return information from memory and not do I/O (like network requests). Implement `update()` or `async_update()` to fetch data.
|
||||
|
||||
| Name | Type | Default | Description
|
||||
| ---- | ---- | ------- | -----------
|
||||
| changed_by | string | None | Describes what the last change was triggered by.
|
||||
| code_format | string | None | Regex for code format or None if no code is required.
|
||||
| is_locked | bool | None | Indication of whether the lock is currently locked. Used to determine `state`.
|
||||
|
||||
### Supported Features
|
||||
|
||||
Supported features constants are combined using the bitwise or (`|`) operator.
|
||||
|
||||
| Constant | Description |
|
||||
|----------|--------------------------------------|
|
||||
| `SUPPORT_OPEN` | This lock supports opening the door latch.
|
||||
|
||||
## Methods
|
||||
|
||||
### Lock
|
||||
|
||||
```python
|
||||
class MyLock(LockDevice):
|
||||
|
||||
def lock(self, **kwargs):
|
||||
"""Lock all or specified locks. A code to lock the lock with may optionally be specified."""
|
||||
|
||||
async def async_lock(self, **kwargs):
|
||||
"""Lock all or specified locks. A code to lock the lock with may optionally be specified."""
|
||||
```
|
||||
|
||||
### Unlock
|
||||
|
||||
```python
|
||||
class MyLock(LockDevice):
|
||||
|
||||
def unlock(self, **kwargs):
|
||||
"""Unlock all or specified locks. A code to unlock the lock with may optionally be specified."""
|
||||
|
||||
async def async_unlock(self, **kwargs):
|
||||
"""Unlock all or specified locks. A code to unlock the lock with may optionally be specified."""
|
||||
```
|
||||
|
||||
### Open
|
||||
|
||||
Only implement this method if the flag `SUPPORT_OPEN` is set.
|
||||
|
||||
```python
|
||||
class MyLock(LockDevice):
|
||||
|
||||
def open(self, **kwargs):
|
||||
"""Open (unlatch) all or specified locks. A code to open the lock with may optionally be specified."""
|
||||
|
||||
async def async_open(self, **kwargs):
|
||||
"""Open (unlatch) all or specified locks. A code to open the lock with may optionally be specified."""
|
||||
```
|
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: Entity Registry and disabling entities
|
||||
sidebar_label: Disabling entities
|
||||
id: version-0.105.0-entity_registry_disabled_by
|
||||
original_id: entity_registry_disabled_by
|
||||
---
|
||||
|
||||
The entity registry tracks all entities with unique IDs. For each entity, the registry keeps track of options that impact how the entity interacts with the core. One of these options is `disabled_by`.
|
||||
|
||||
When `disabled_by` is set to a string value, the entity will not be added to Home Assistant when the integration passes it to `async_add_entities`.
|
||||
|
||||
## Integration Architecture
|
||||
|
||||
Integrations will need to make sure that they work correctly when their entities get disabled. If your integration is keeping references to the created entity objects, it should register those references only inside the entity's lifecycle method `async_added_to_hass`. This lifecycle method is only called if the entity is actually added to Home Assistant (and so it's not disabled).
|
||||
|
||||
Entity disabling works with entities provided via a config entry or via an entry in configuration.yaml. If your integration is set up via a config entry and supports [unloading](config_entries_index.md#unloading-entries), Home Assistant will be able to reload your integration after entities have been enabled/disabled to apply the changes without a restart.
|
||||
|
||||
## Users editing the entity registry
|
||||
|
||||
One way an entity can be disabled is by the user editing the entity registry via the UI. In this case, the `disabled_by` value will be set to `user`. This will only work with entities that are already registered.
|
||||
|
||||
## Integrations setting default value of disabled_by for new entity registry entries
|
||||
|
||||
As an integration you can control if your entity is enabled when it is first registered. This is controlled by the `entity_registry_enabled_default` property. It defaults to `True`, which means the entity will be enabled.
|
||||
|
||||
If the property returns `False`, the `disabled_by` value of the newly registered entity will be set to `integration`.
|
||||
|
||||
## Config entry system options setting default value of disabled_by for new entity registry entries
|
||||
|
||||
The user can also control how new entities that are related to a config entry are received by setting the system option `disable_new_entities` of a config entry to `True`. This can be done via the UI.
|
||||
|
||||
If an entity is getting registered and this system option is set to `True`, the `disabled_by` property will be initialized as `config_entry`.
|
||||
|
||||
If `disable_new_entities` is set to `True` and `entity_registry_enabled_default` returns `False`, the `disabled_by` value will be set to `integration`.
|
||||
|
||||
## Integrations offering options to control disabled_by
|
||||
|
||||
Some integrations will want to offer options to the user to control which entities are being added to Home Assistant. For example, the Unifi integration offers options to enable/disable wireless and wired clients.
|
||||
|
||||
Integrations can offer options to users either via [configuration.yaml](configuration_yaml_index) or using an [Options Flow](config_entries_options_flow_handler.md).
|
||||
|
||||
If this option is offered by integrations, you should not leverage the disabled_by property in the entity registry. Instead, if entities are disabled via a config options flow, remove them from the device and entity registry.
|
554
website/versioned_docs/version-0.105.0/external_api_rest.md
Normal file
554
website/versioned_docs/version-0.105.0/external_api_rest.md
Normal file
@ -0,0 +1,554 @@
|
||||
---
|
||||
title: REST API
|
||||
id: version-0.105.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`:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
```
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
```
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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 a state. You can create any state that you want, it does not have to be backed by an entity in Home Assistant.
|
||||
|
||||
> :info: NOTE: This endpoint sets the representation of a device within Home Asistant and will not communicate with the actual device. To communicate with the device, use the [POST /api/services/<domain>/<service>](#post-apiservicesltdomainltservice) endpoint.
|
||||
|
||||
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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ 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:
|
||||
|
||||
```shell
|
||||
$ curl -X POST -H "Authorization: Bearer ABCDEFGH" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"template": "It is {{ now() }}!"}' http://localhost:8123/api/template
|
||||
```
|
||||
|
||||
#### POST /api/config/core/check_config
|
||||
|
||||
Trigger a check of `configuration.yaml`. No additional data needs to be passed in with this request.
|
||||
|
||||
If the check is successful, the following will be returned:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"errors": null,
|
||||
"result": "valid"
|
||||
}
|
||||
```
|
||||
|
||||
If the check fails, the errors attribute in the object will list what caused the check to fail. For example:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"errors": "Integration not found: frontend:",
|
||||
"result": "invalid"
|
||||
}
|
||||
```
|
||||
|
||||
#### 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."
|
||||
}
|
||||
```
|
140
website/versioned_docs/version-0.105.0/frontend_data.md
Normal file
140
website/versioned_docs/version-0.105.0/frontend_data.md
Normal file
@ -0,0 +1,140 @@
|
||||
---
|
||||
title: Frontend data
|
||||
sidebar_label: Data
|
||||
id: version-0.105.0-frontend_data
|
||||
original_id: frontend_data
|
||||
---
|
||||
|
||||
The frontend passes a single `hass` object around. This object contains the latest state and allows you to send commands back to the server.
|
||||
|
||||
Whenever a state changes, a new version of the objects that changed are created. So you can easily see if something has changed by doing a strict equality check:
|
||||
|
||||
```js
|
||||
const changed = newVal !== oldVal;
|
||||
```
|
||||
|
||||
## Data
|
||||
|
||||
### `hass.states`
|
||||
|
||||
An object containing the states of all entities in Home Assistant. The key is the entity_id, the value is the state object.
|
||||
|
||||
```json
|
||||
{
|
||||
"sun.sun": {
|
||||
"entity_id": "sun.sun",
|
||||
"state": "above_horizon",
|
||||
"attributes": {
|
||||
"next_dawn": "2018-08-18T05:39:19+00:00",
|
||||
"next_dusk": "2018-08-17T18:28:52+00:00",
|
||||
"next_midnight": "2018-08-18T00:03:51+00:00",
|
||||
"next_noon": "2018-08-18T12:03:58+00:00",
|
||||
"next_rising": "2018-08-18T06:00:33+00:00",
|
||||
"next_setting": "2018-08-17T18:07:37+00:00",
|
||||
"elevation": 60.74,
|
||||
"azimuth": 297.69,
|
||||
"friendly_name": "Sun"
|
||||
},
|
||||
"last_changed": "2018-08-17T13:46:59.083836+00:00",
|
||||
"last_updated": "2018-08-17T13:49:30.378101+00:00",
|
||||
"context": {
|
||||
"id": "74c2b3b429c844f18e59669e4b41ec6f",
|
||||
"user_id": null
|
||||
},
|
||||
},
|
||||
"light.ceiling_lights": {
|
||||
"entity_id": "light.ceiling_lights",
|
||||
"state": "on",
|
||||
"attributes": {
|
||||
"min_mireds": 153,
|
||||
"max_mireds": 500,
|
||||
"brightness": 180,
|
||||
"color_temp": 380,
|
||||
"hs_color": [
|
||||
56,
|
||||
86
|
||||
],
|
||||
"rgb_color": [
|
||||
255,
|
||||
240,
|
||||
35
|
||||
],
|
||||
"xy_color": [
|
||||
0.459,
|
||||
0.496
|
||||
],
|
||||
"white_value": 200,
|
||||
"friendly_name": "Ceiling Lights",
|
||||
"supported_features": 151
|
||||
},
|
||||
"last_changed": "2018-08-17T13:46:59.129248+00:00",
|
||||
"last_updated": "2018-08-17T13:46:59.129248+00:00",
|
||||
"context": {
|
||||
"id": "2c6bbbbb66a84a9dae097b6ed6c93383",
|
||||
"user_id": null
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `hass.user`
|
||||
|
||||
The logged in user.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "758186e6a1854ee2896efbd593cb542c",
|
||||
"name": "Paulus",
|
||||
"is_owner": true,
|
||||
"is_admin": true,
|
||||
"credentials": [
|
||||
{
|
||||
"auth_provider_type": "homeassistant",
|
||||
"auth_provider_id": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
All methods starting with `call` are async methods. This means that they will return a `Promise` that will resolve with the result of the call.
|
||||
|
||||
### `hass.callService(domain, service, data)`
|
||||
|
||||
Call a service on the backend.
|
||||
|
||||
```js
|
||||
hass.callService('light', 'turn_on', {
|
||||
entity_id: 'light.kitchen'
|
||||
});
|
||||
```
|
||||
|
||||
### `hass.callWS(message)`
|
||||
|
||||
Call a WebSocket command on the backend.
|
||||
|
||||
```js
|
||||
this.hass.callWS({
|
||||
type: 'config/auth/create',
|
||||
name: 'Paulus',
|
||||
}).then(userResponse =>
|
||||
console.log("Created user", userResponse.user.id));
|
||||
```
|
||||
|
||||
### `hass.callApi(method, path, data)`
|
||||
|
||||
Call an API on the Home Assistant server. For example, if you want to fetch all Hass.io snapshots by issuing a GET request to `/api/hassio/snapshots`:
|
||||
|
||||
```js
|
||||
hass.callApi('get', 'hassio/snapshots')
|
||||
.then(snapshots => console.log('Received snapshots!', snapshots));
|
||||
```
|
||||
|
||||
If you need to pass in data, pass a third argument:
|
||||
|
||||
```js
|
||||
hass.callApi('delete', 'notify.html5', { subscription: 'abcdefgh' });
|
||||
```
|
||||
|
||||
_We're moving away from API calls and are migrating everything to `hass.callWS(message)` calls._
|
237
website/versioned_docs/version-0.105.0/hassio_addon_config.md
Normal file
237
website/versioned_docs/version-0.105.0/hassio_addon_config.md
Normal file
@ -0,0 +1,237 @@
|
||||
---
|
||||
title: Add-On Configuration
|
||||
id: version-0.105.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/
|
||||
apparmor.txt
|
||||
build.json
|
||||
CHANGELOG.md
|
||||
config.json
|
||||
DOC.md
|
||||
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.
|
||||
|
||||
All our Images have also [bashio][bashio] installed. It contains a set of commonly used operations and can be used to be included in add-ons to reduce code duplication across add-ons and therefore making it easier to develop and maintain add-ons.
|
||||
|
||||
When developing your script:
|
||||
|
||||
- `/data` is a volume for persistent storage.
|
||||
- `/data/options.json` contains the user configuration. You can use bashio or `jq` inside your shell script to parse this data.
|
||||
|
||||
```shell
|
||||
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.
|
||||
|
||||
[bashio]: https://github.com/hassio-addons/bashio
|
||||
|
||||
## Add-on Docker file
|
||||
|
||||
All add-ons are based on latest Alpine Linux. 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.
|
||||
|
||||
```dockerfile
|
||||
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 | string | 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`. If host-port is `null`, the mapping is disabled.
|
||||
| ports_description | dict | no | Network ports description mapping. Format is `"container-port/type": "description of this 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`
|
||||
| udev | bool | no | Default False. Set this True, if your container runs a udev process of its own.
|
||||
| auto_uart | bool | no | Default False. Auto mapping all UART/Serial device from host into add-on.
|
||||
| homeassistant | string | no | Pin a minimum required Home Assistant version for such Add-on. Value is a version string like `0.91.2`.
|
||||
| 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.
|
||||
| video | bool | no | Boolean. Mark this add-on touse internal an video system. All available devices will be mapped into addon.
|
||||
| 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.
|
||||
| ingress | bool | no | Enable the ingress feature for the Add-on
|
||||
| ingress_port | integer | no | Default `8099`. For Add-ons they run on host network, you can use `0` and read the port later on API.
|
||||
| ingress_entry | string | no | Modify the URL entry point from `/`.
|
||||
| panel_icon | string | no | Default: mdi:puzzle. MDI icon for the menu panel integration.
|
||||
| panel_title | string | no | Default add-on name, but can Modify with this options.
|
||||
| panel_admin | bool | no | Default True. Make menu entry only available with admin privileged.
|
||||
| snapshot_exclude | list | no | List of file/path with glob support they are excluded from snapshots.
|
||||
| advanced | bool | no | Default False. Make addon visible on simle mode or not.
|
||||
| stage | string | no | Default `stable`. Flag add-on with follow attribute: `stable`, `experimental`, `deprecated`
|
||||
|
||||
|
||||
### 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 / str(min,) / str(,max) / str(min,max)
|
||||
- bool
|
||||
- int / int(min,) / int(,max) / int(min,max)
|
||||
- float / float(min,) / float(,max) / float(min,max)
|
||||
- email
|
||||
- url
|
||||
- password
|
||||
- port
|
||||
- match(REGEX)
|
||||
- list(val1|val2|...)
|
||||
|
||||
## 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.
|
||||
|
||||
We provide a set of [Base-Images][hassio-base] which should cover a lot of needs. If you don't want use the Alpine based version or need a specific Image tag, feel free to pin this requirements for you build with `build_from` option.
|
||||
|
||||
[hassio-base]: https://github.com/home-assistant/hassio-base
|
@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Presenting your addon
|
||||
id: version-0.105.0-hassio_addon_presentation
|
||||
original_id: hassio_addon_presentation
|
||||
---
|
||||
|
||||
If you decide to share your add-on to the public, paying attention to details is recommended. Of course, your add-on should have a proper name and description, but Hass.io also gives you some other tools to present your add-on even nicer.
|
||||
|
||||
## Adding intro
|
||||
|
||||
This shows in add-on store and give the user a short instruction what the addon can.
|
||||
|
||||
This file containing the intro is usually referred to as the "README", which is generally published as the `README.md` file.
|
||||
|
||||
## Adding documentation
|
||||
|
||||
Good documentation helps the consumer of your add-on to understand its usage, explains configuration options, points users in the right direction in the case they have questions or issues, and contains the license under which the add-on was published.
|
||||
|
||||
This file containing the documentation is usually referred to as the "DOC", which is generally published as the `DOC.md` file.
|
||||
|
||||
## Add-on icon & logo
|
||||
|
||||
A picture is worth a thousand words. Therefore, your add-on can be improved by adding a proper image icon and logo. Those images are used when showing your add-on in the Home Assistant Hass.io panel and which will significantly improve the visual representation of your add-on.
|
||||
|
||||
Requirements for the logo of your add-on:
|
||||
|
||||
- The logo must be in the Portable Network Graphics format (`.png`).
|
||||
- The filename must be `logo.png`.
|
||||
- It is recommended to keep the logo size around 250x100px. You may choose to use a different size or aspect ratio as you seem fit for your add-on.
|
||||
|
||||
Requirements for the icon of your add-on:
|
||||
|
||||
- The icon must be in the Portable Network Graphics format (`.png`).
|
||||
- The filename must be `icon.png`.
|
||||
- The aspect ratio of the icon must be 1x1 (square).
|
||||
- It is recommended to use an icon size of 128x128px.
|
||||
|
||||
## Keeping a changelog
|
||||
|
||||
It is likely you are going to release newer versions of your add-on in the future. In case that happens, the users of your add-on would see an upgrade notice and probably want to know what changes were made in the latest version.
|
||||
|
||||
A changelog is a file which contains a curated, chronologically ordered list of notable changes for each version of your add-on and is generally published as the `CHANGELOG.md` file.
|
||||
|
||||
If you are in need of a guide on keeping a changelog, we would recommend checking the [keep a changelog](http://keepachangelog.com) website. They have developed a standard that is used by many opensource projects around the world.
|
||||
|
||||
In future versions of Hass.io, the `CHANGELOG.md` file will be displayed in the Home Assistant frontend.
|
||||
|
||||
## AppArmor
|
||||
|
||||
You can use own security profile for you Add-on with AppArmor. Default it is enabled and use the Docker default profile. Put `apparmor.txt` file into your Add-on folder and it will load this file as primary profile. Use the config options to set the name of that profile.
|
||||
|
||||
## Ingress
|
||||
|
||||
Ingress allow users to access the add-on web interface via the Home Assistant UI. Authentication is handled by Home Assistant, so neither the user nor the add-on developer will need to care about the security or port forwarding. Users love this feature, however it is not every time simple to implement for the add-on developer.
|
||||
|
||||
To add Ingress support, follow the following steps:
|
||||
- The add-on will need to provide the web interface on port `8099`. Make sure that the add-on accepts only connections from `172.30.32.2` on that port and that the connections are treated as authenticated.
|
||||
- Update add-on configuration and set `ingress: true`. Here it is also possible to configure the Ingress port (default 8099).
|
||||
- If you need to configure the application inside your add-on with the right path and port, query the add-on info API endpoint.
|
||||
- If the application doesn't support relative paths or you can't set a base url, you can use nginx filter to replace the URL with correct path.
|
||||
|
||||
Ingress API gateway supports the following:
|
||||
|
||||
* HTTP/1.x
|
||||
* Streaming content
|
||||
* Websockets
|
@ -0,0 +1,154 @@
|
||||
---
|
||||
title: Fetching Data
|
||||
id: version-0.105.0-integration_fetching_data
|
||||
original_id: integration_fetching_data
|
||||
---
|
||||
|
||||
Your integration will need to fetch data from an API to be able to provide this to Home Assistant. This API can be available over the web (local or cloud), sockets, serial ports exposed via USB sticks, etc.
|
||||
|
||||
# Push vs Poll
|
||||
|
||||
APIs come in many different shapes and forms but at its core they fall in two categories: push and poll.
|
||||
|
||||
With push, we subscribe to an API and we get notified by the API when new data is available. It pushes the changes to us. Push APIs are great because they consume less resources. When a change happens, we can get notified of a change and don't have to re-fetch all the data and find changes. Because entities can be disabled, you should make sure that your entity subscribes inside the `async_added_to_hass` callback and unsubscribes inside `async_will_remove_from_hass`.
|
||||
|
||||
With polling, we will fetch the latest data from the API at a specified interval. Your integration will then supply this data to its entity, which is written to Home Assistant.
|
||||
|
||||
Because polling is so common, Home Assistant by default assumes that your entity is based on polling. If this is not the case, return `False` from the `Entity.should_poll` property. When you disable polling, your integration will be responsible for calling one of the methods to indicate to Home Assistant that it's time to write the entity state to Home Assistant:
|
||||
|
||||
- If you are executing from within an async function and don't need your entity update method called, call `Entity.async_write_ha_state()`. This is an async callback that will write the state to the state machine within yielding to the event loop.
|
||||
- `Entity.schedule_update_ha_state(force_refresh=False)`/`Entity.async_schedule_update_ha_state(force_refresh=False)` will schedule an update of the entity. If `force_refresh` is set to `True`, Home Assistant will call your entities update method (`update()`/`async_update()`) prior to writing the state.
|
||||
|
||||
# Polling API endpoints
|
||||
|
||||
We're going to explain a few different API types here and the best way to integrate them in Home Assistant. Note that some integrations will encounter a combination of the ones below.
|
||||
|
||||
## Coordinated, single API poll for data for all entities
|
||||
|
||||
This API will have a single method to fetch data for all the entities that you have in Home Assistant. In this case we will want to have a single periodical poll on this endpoint, and then let entities know as soon as new data is available for them.
|
||||
|
||||
Home Assistant provides a DataUpdateCoordinator class to help you manage this as efficiently as possible.
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers import debounce, entity
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
# assuming API object stored here by __init__.py
|
||||
api = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
async def async_update_data():
|
||||
"""Fetch data from API endpoint.
|
||||
|
||||
This is the place to pre-process the data to lookup tables
|
||||
so entities can quickly look up their data.
|
||||
"""
|
||||
try:
|
||||
return await api.fetch_data()
|
||||
except ApiError:
|
||||
raise UpdateFailed
|
||||
|
||||
coordinator = DataUpdateCoordinator(
|
||||
hass,
|
||||
_LOGGER,
|
||||
# Name of the data. For logging purposes.
|
||||
name="sensor",
|
||||
update_method=async_update_data,
|
||||
# Polling interval. Will only be polled if there are subscribers.
|
||||
update_interval=timedelta(seconds=30),
|
||||
)
|
||||
|
||||
# Fetch initial data so we have data when entities subscribe
|
||||
await coordinator.async_refresh()
|
||||
|
||||
async_add_entities(MyEntity(coordinator, idx) for idx, ent
|
||||
in enumerate(coordinator.data))
|
||||
|
||||
|
||||
class MyEntity(entity.Entity):
|
||||
|
||||
def __init__(self, coordinator, idx):
|
||||
self.coordinator = coordinator
|
||||
self.idx = idx
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return entity state.
|
||||
|
||||
Example to show how we fetch data from coordinator.
|
||||
"""
|
||||
self.coordinator.data[self.idx]['state']
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No need to poll. Coordinator notifies entity of updates."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return if entity is available."""
|
||||
return not self.coordinator.failed_last_update
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""When entity is added to hass."""
|
||||
self.coordinator.async_add_listener(
|
||||
self.async_write_ha_state
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""When entity will be removed from hass."""
|
||||
self.coordinator.async_remove_listener(
|
||||
self.async_write_ha_state
|
||||
)
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the light on.
|
||||
|
||||
Example method how to request data updates.
|
||||
"""
|
||||
# Do the turning on.
|
||||
# ...
|
||||
|
||||
# Update the data
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_update(self):
|
||||
"""Update the entity.
|
||||
|
||||
Only used by the generic entity update service.
|
||||
"""
|
||||
await self.coordinator.async_request_refresh()
|
||||
```
|
||||
|
||||
## Separate polling for each individual entity
|
||||
|
||||
Some APIs will offer an endpoint per device. It sometimes won't be possible to map a device from your API to a single entity. If you create multiple entities from a single API device endpoint, please see the preivous section.
|
||||
|
||||
If you can map exactly one device endpoint to a single entity, you can fetch the data for this entity inside the `update()`/`async_update()` methods. Make sure polling is set to `True` and Home Assistant will call this method regularly.
|
||||
|
||||
If your entities need to fetch data before being written to Home Assistant for the first time, pass `True` to the `add_entities` method: `add_entities([MyEntity()], True)`.
|
||||
|
||||
You can control the polling interval for your integration by defining a `SCAN_INTERVAL` constant in your platform. Careful with setting this too low. It will take up resources in Home Assistant, can overwelm the device hosting the API or can get you blocked from cloud APIs.
|
||||
|
||||
```python
|
||||
from datetime import timedelta
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=5)
|
||||
```
|
||||
|
||||
# Request Parallelism
|
||||
|
||||
> This is an advanced topic.
|
||||
|
||||
Home Assistant has built-in logic to make sure that integrations do not hammer APIs and consume all available resources in Home Assistant. This logic is built around limiting the number of parallel requests. This logic is automatically used during service calls and entity updates.
|
||||
|
||||
Home Assistant controls the number of parallel updates (calls to `update()`) by maintaining a [semaphore](https://docs.python.org/3/library/asyncio-sync.html#asyncio.Semaphore) per integration. For example, if the semaphore allows 1 parallel connection, updates and service calls will wait if one is in progress. If the value is 0, the integration is itself responsible for limiting the number of parallel requests if necessary.
|
||||
|
||||
The default value for parallel requests for a platform is decided based on the first entity that is added to Home Assistant. It's 0 if the entity defines the `async_update` method, else it's 1. (this is a legacy decision)
|
||||
|
||||
Platforms can override the default by defining the `PARALLEL_UPDATES` constant in their platform (ie `rflink/light.py`).
|
@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Integration Quality Scale
|
||||
id: version-0.105.0-integration_quality_scale_index
|
||||
original_id: integration_quality_scale_index
|
||||
---
|
||||
|
||||
The Integration Quality Scale scores each integration based on the code quality and user experience. Each level of the quality scale consists of a list of requirements. If an integration matches all requirements, it's considered to have reached that level.
|
||||
|
||||
> Suggestions for changes can be done by creating an issue in the [architecture repo](https://github.com/home-assistant/architecture/issues/).
|
||||
|
||||
# No score
|
||||
|
||||
This integration passes the bare minimum requirements to become part of the index.
|
||||
|
||||
- Satisfy all requirements for [creating components](creating_component_code_review.md) and [creating platforms](creating_platform_code_review.md).
|
||||
- Configurable via `configuration.yaml`
|
||||
|
||||
# Silver 🥈
|
||||
|
||||
This integration is able to cope when things go wrong. It will not print any exceptions nor will it fill the log with retry attempts.
|
||||
|
||||
- Connection/configuration is handled via a component.
|
||||
- Set an appropriate `SCAN_INTERVAL` (if a polling integration)
|
||||
- Raise `PlatformNotReady` if unable to connect during platform setup (if appropriate)
|
||||
- Handles expiration of auth credentials. Refresh if possible or print correct error and fail setup. If based on a config entry, should trigger a new config entry flow to re-authorize.
|
||||
- Handles internet unavailable. Log a warning once when unavailable, log once when reconnected.
|
||||
- Handles device/service unavailable. Log a warning once when unavailable, log once when reconnected.
|
||||
- Set `available` property to `False` if appropriate ([docs](entity_index.md#generic-properties))
|
||||
- Entities have unique ID (if available) ([docs](entity_registry_index.md#unique-id-requirements))
|
||||
|
||||
# Gold 🥇
|
||||
|
||||
This is a solid integration that is able to survive poor conditions and can be configured via the user interface.
|
||||
|
||||
- Configurable via config entries.
|
||||
- Don't allow configuring already configured device/service (example: no 2 entries for same hub)
|
||||
- Tests for the config flow
|
||||
- Discoverable (if available)
|
||||
- Set unique ID in config flow (if available)
|
||||
- Entities have device info (if available) ([docs](device_registry_index.md#defining-devices))
|
||||
- Tests for fetching data from the integration and controlling it ([docs](development_testing.md))
|
||||
- Has a code owner ([docs](creating_integration_manifest.md#code-owners))
|
||||
- Entities only subscribe to updates inside `async_added_to_hass` and unsubscribe inside `async_will_remove_from_hass` ([docs](entity_index.md#lifecycle-hooks))
|
||||
- Entities have correct device classes where appropriate ([docs](entity_index.md#generic-properties))
|
||||
- Supports entities being disabled and leverages `Entity.entity_registry_enabled_default` to disable less popular entities ([docs](entity_index.md#advanced-properties))
|
||||
- If the device/service API can remove entities, the integration should make sure to clean up the entity and device registry.
|
||||
|
||||
# Platinum 🏆
|
||||
|
||||
Best of the best. The integration is completely async, meaning it's super fast. Integrations that reach platinum level will require approval by the code owner for each PR.
|
||||
|
||||
- Set appropriate `PARALLEL_UPDATES` constant
|
||||
- Support config entry unloading (called when config entry is removed)
|
||||
- Integration + dependency are async
|
||||
- Uses aiohttp and allows passing in websession (if making HTTP requests)
|
||||
|
||||
# Internal 🏠
|
||||
|
||||
Integrations which are part of Home Assistant are not rated but marked as **internal**.
|
183
website/versioned_sidebars/version-0.105.0-sidebars.json
Normal file
183
website/versioned_sidebars/version-0.105.0-sidebars.json
Normal file
@ -0,0 +1,183 @@
|
||||
{
|
||||
"version-0.105.0-Architecture": {
|
||||
"Architecture": [
|
||||
"version-0.105.0-architecture_index",
|
||||
"version-0.105.0-architecture_components",
|
||||
"version-0.105.0-architecture_entities",
|
||||
"version-0.105.0-architecture_hassio"
|
||||
],
|
||||
"Entities": [
|
||||
"version-0.105.0-entity_index",
|
||||
"version-0.105.0-entity_air_quality",
|
||||
"version-0.105.0-entity_alarm_control_panel",
|
||||
"version-0.105.0-entity_binary_sensor",
|
||||
"version-0.105.0-entity_climate",
|
||||
"version-0.105.0-entity_cover",
|
||||
"version-0.105.0-entity_fan",
|
||||
"version-0.105.0-entity_light",
|
||||
"version-0.105.0-entity_lock",
|
||||
"version-0.105.0-entity_media_player",
|
||||
"version-0.105.0-entity_remote",
|
||||
"version-0.105.0-entity_sensor",
|
||||
"version-0.105.0-entity_switch",
|
||||
"version-0.105.0-entity_vacuum",
|
||||
"version-0.105.0-entity_water_heater",
|
||||
"version-0.105.0-entity_weather"
|
||||
],
|
||||
"Authentication": [
|
||||
"version-0.105.0-auth_index",
|
||||
"version-0.105.0-auth_permissions",
|
||||
"version-0.105.0-auth_api",
|
||||
"version-0.105.0-auth_auth_provider",
|
||||
"version-0.105.0-auth_auth_module"
|
||||
],
|
||||
"Config Entries": [
|
||||
"version-0.105.0-config_entries_index"
|
||||
],
|
||||
"Data Entry Flow": [
|
||||
"version-0.105.0-data_entry_flow_index"
|
||||
],
|
||||
"Entity Registry": [
|
||||
"version-0.105.0-entity_registry_index",
|
||||
"version-0.105.0-entity_registry_disabled_by"
|
||||
],
|
||||
"Device Registry": [
|
||||
"version-0.105.0-device_registry_index"
|
||||
],
|
||||
"Area Registry": [
|
||||
"version-0.105.0-area_registry_index"
|
||||
]
|
||||
},
|
||||
"version-0.105.0-Extending Frontend": {
|
||||
"Frontend": [
|
||||
"version-0.105.0-frontend_index",
|
||||
"version-0.105.0-frontend_architecture",
|
||||
"version-0.105.0-frontend_development",
|
||||
"version-0.105.0-frontend_data",
|
||||
"version-0.105.0-frontend_external_auth",
|
||||
"version-0.105.0-frontend_external_bus"
|
||||
],
|
||||
"Extending the frontend": [
|
||||
"version-0.105.0-frontend_add_card",
|
||||
"version-0.105.0-frontend_add_more_info",
|
||||
"version-0.105.0-frontend_add_websocket_api"
|
||||
],
|
||||
"Custom UI": [
|
||||
"version-0.105.0-lovelace_custom_card",
|
||||
"version-0.105.0-frontend_creating_custom_panels"
|
||||
]
|
||||
},
|
||||
"version-0.105.0-Extending Home Assistant": {
|
||||
"Development Workflow": [
|
||||
"version-0.105.0-development_index",
|
||||
"version-0.105.0-development_environment",
|
||||
"version-0.105.0-development_submitting",
|
||||
"version-0.105.0-development_guidelines",
|
||||
"version-0.105.0-development_testing",
|
||||
"version-0.105.0-development_catching_up"
|
||||
],
|
||||
"Building Integrations": [
|
||||
"version-0.105.0-creating_integration_file_structure",
|
||||
"version-0.105.0-creating_integration_manifest",
|
||||
"version-0.105.0-creating_component_index",
|
||||
"version-0.105.0-config_entries_config_flow_handler",
|
||||
"version-0.105.0-config_entries_options_flow_handler",
|
||||
"version-0.105.0-configuration_yaml_index",
|
||||
"version-0.105.0-dev_101_services",
|
||||
"version-0.105.0-creating_platform_index",
|
||||
"version-0.105.0-creating_component_generic_discovery",
|
||||
"version-0.105.0-reproduce_state_index",
|
||||
"version-0.105.0-integration_fetching_data"
|
||||
],
|
||||
"Development Checklist": [
|
||||
"version-0.105.0-development_checklist",
|
||||
"version-0.105.0-creating_component_code_review",
|
||||
"version-0.105.0-creating_platform_code_review",
|
||||
"version-0.105.0-integration_quality_scale_index"
|
||||
],
|
||||
"Home Assistant Core 101": [
|
||||
"version-0.105.0-dev_101_index",
|
||||
"version-0.105.0-dev_101_hass",
|
||||
"version-0.105.0-dev_101_events",
|
||||
"version-0.105.0-dev_101_states",
|
||||
"version-0.105.0-dev_101_config"
|
||||
],
|
||||
"Device Automations": [
|
||||
"version-0.105.0-device_automation_index",
|
||||
"version-0.105.0-device_automation_trigger",
|
||||
"version-0.105.0-device_automation_condition",
|
||||
"version-0.105.0-device_automation_action"
|
||||
],
|
||||
"Misc": [
|
||||
"version-0.105.0-development_validation",
|
||||
"version-0.105.0-development_typing"
|
||||
]
|
||||
},
|
||||
"version-0.105.0-Misc": {
|
||||
"Introduction": [
|
||||
"version-0.105.0-misc"
|
||||
],
|
||||
"External API": [
|
||||
"version-0.105.0-external_api_rest",
|
||||
"version-0.105.0-external_api_rest_python",
|
||||
"version-0.105.0-external_api_websocket",
|
||||
"version-0.105.0-external_api_server_sent_events"
|
||||
],
|
||||
"Internationalization": [
|
||||
"version-0.105.0-internationalization_index",
|
||||
"version-0.105.0-internationalization_backend_localization",
|
||||
"version-0.105.0-internationalization_custom_component_localization",
|
||||
"version-0.105.0-internationalization_translation"
|
||||
],
|
||||
"Documentation": [
|
||||
"version-0.105.0-documentation_index",
|
||||
"version-0.105.0-documentation_standards",
|
||||
"version-0.105.0-documentation_create_page"
|
||||
],
|
||||
"Intents": [
|
||||
"version-0.105.0-intent_index",
|
||||
"version-0.105.0-intent_firing",
|
||||
"version-0.105.0-intent_handling",
|
||||
"version-0.105.0-intent_conversation",
|
||||
"version-0.105.0-intent_builtin"
|
||||
],
|
||||
"Native App Integration": [
|
||||
"version-0.105.0-app_integration_index",
|
||||
"version-0.105.0-app_integration_setup",
|
||||
"version-0.105.0-app_integration_sending_data",
|
||||
"version-0.105.0-app_integration_sensors",
|
||||
"version-0.105.0-app_integration_notifications",
|
||||
"version-0.105.0-app_integration_webview"
|
||||
],
|
||||
"Building a Python library": [
|
||||
"version-0.105.0-api_lib_index",
|
||||
"version-0.105.0-api_lib_auth",
|
||||
"version-0.105.0-api_lib_data_models"
|
||||
],
|
||||
"asyncio": [
|
||||
"version-0.105.0-asyncio_index",
|
||||
"version-0.105.0-asyncio_101",
|
||||
"version-0.105.0-asyncio_categorizing_functions",
|
||||
"version-0.105.0-asyncio_working_with_async"
|
||||
],
|
||||
"Hass.io": [
|
||||
"version-0.105.0-hassio_debugging",
|
||||
"version-0.105.0-hassio_hass"
|
||||
],
|
||||
"Hass.io Add-Ons": [
|
||||
"version-0.105.0-hassio_addon_index",
|
||||
"version-0.105.0-hassio_addon_tutorial",
|
||||
"version-0.105.0-hassio_addon_config",
|
||||
"version-0.105.0-hassio_addon_communication",
|
||||
"version-0.105.0-hassio_addon_testing",
|
||||
"version-0.105.0-hassio_addon_publishing",
|
||||
"version-0.105.0-hassio_addon_presentation",
|
||||
"version-0.105.0-hassio_addon_repository",
|
||||
"version-0.105.0-hassio_addon_security"
|
||||
],
|
||||
"Maintainer docs": [
|
||||
"version-0.105.0-maintenance",
|
||||
"version-0.105.0-releasing"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
[
|
||||
"0.105.0",
|
||||
"0.104.0",
|
||||
"0.103.0",
|
||||
"0.102.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user