More tweaks to developer docs

This commit is contained in:
Paulus Schoutsen 2016-04-16 23:00:45 -07:00
parent c5bc6c0cfb
commit d8c8cf4c8d
13 changed files with 272 additions and 149 deletions

View File

@ -337,3 +337,7 @@ ul.sidebar-menu a.active {
color: #000;
font-weight: bold;
}
a code {
color: #049cdb;
}

View File

@ -12,6 +12,23 @@
<li>{% active_link /developers/development_environment/ Setup Dev Environment %}</li>
</ul>
</li>
<li>
{% active_link /developers/add_new_platform/ Support a new device (as a platform) %}
<ul>
<li>{% active_link /developers/platform_example_sensor/ Example sensor platform %}</li>
<li>{% active_link /developers/platform_example_light/ Example light platform %}</li>
</ul>
</li>
<li>
{% active_link /developers/creating_components/ Adding a new component %}
<ul>
<li>{% active_link /developers/component_loading/ Loading components %}</li>
<li>{% active_link /developers/component_deps_and_reqs/ Requirements & Dependencies %}</li>
<li>{% active_link /developers/component_initialization/ Initialization %}</li>
<li>{% active_link /developers/component_events/ Handling events %}</li>
<li>{% active_link /developers/component_discovery/ Component Discovery %}</li>
</ul>
</li>
<li>
Frontend Development
<ul>
@ -20,14 +37,6 @@
<li>{% active_link /developers/frontend_add_more_info/ Add More Info Dialog %}</li>
</ul>
</li>
<li>
Extending Home Assistant
<ul>
<li>{% active_link /developers/creating_components/ Creating Components %}</li>
<li>{% active_link /developers/add_new_platform/ Adding Platform Support %}</li>
<li>{% active_link /developers/platform_discovery/ Platform Discovery %}</li>
</ul>
</li>
<li>
API
<ul>

View File

@ -9,16 +9,23 @@ sharing: true
footer: true
---
Components that interact with devices are structured in core- and platform logic. This allows the same logic to be used for different platforms.
Components that interact with devices are called Entity Components. They are structured in core- and platform logic. This allows the same logic to handle a light to be used by different brands.
For example, the built-in `switch` component consists of various platform in [`homeassistant/components/switch/`](https://github.com/home-assistant/home-assistant/tree/master/homeassistant/components/switch). The file `__init__.py` contains the core logic of all platform and the `vendor_name.py` files only the relevant platform code.
If you are planning to add support for a new type of device to an existing component, you can get away with only writing platform logic. Have a look at how the component works with other platforms and create a similar file for the platform that you would like to add.
If you are planning to add support for a new type of device to an existing component, you can get away with only writing platform logic. Have a look at how the component works with other platforms and create a similar file for the platform that you would like to add:
- [Example sensor platform](/developers/platform_example_sensor): hello world of platforms.
- [Example light platform](/developers/platform_example_light): showing best practices.
### {% linkable_title Interfacing with devices %}
One of the rules for Home Assistant is that platform logic should never interface directly with devices but use a third-party Python 3 library to do so. This way Home Assistant is able to share code with the Python community and we can keep the project maintainable.
To integrate the third-party library you create an Entity class for your device. Entities are Home Assistant's representation of lights, switches, sensors, etc. and are derived from the [Entity Abstract Class](https://github.com/home-assistant/home-assistant/blob/master/homeassistant/helpers/entity.py). This abstract class contains logic for integrating most standard features into your entities, such as visibility, entity IDs, updates, and much more.
### {% linkable_title Requirements and dependencies %}
Platforms can specify dependencies and requirements the same way as a component does.
```python
@ -26,75 +33,3 @@ REQUIREMENTS = ['some-package==2.0.0', 'some-other-package==2.5.0']
DEPENDENCIES = ['mqtt']
```
### {% linkable_title Platform example %}
Entities are Home Assistant's representation of lights, switches, sensors, etc. and are derived from the [Entity Abstract Class](https://github.com/home-assistant/home-assistant/blob/master/homeassistant/helpers/entity.py). This abstract class contains logic for integrating most standard features into your entities, such as visibility, entity IDs, updates, and many more.
This example is for adding support for the imaginary Awesome Lights.
```python
import logging
# Import the device class from the component that you want to support
from homeassistant.components.light import Light
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
# Home Assistant depends on 3rd party packages for API specific code.
REQUIREMENTS = ['awesome_lights==1.2.3']
_LOGGER = logging.getLogger(__name__)
setup_platform(hass, config, add_devices, discovery_info=None):
"""Initialize Awesome Light platform."""
import awesomelights
# Validate passed in config
host = config.get(CONF_HOST)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
if host is None or username is None or password is None:
_LOGGER.error('Invalid config. Expected %s, %s and %s',
CONF_HOST, CONF_USERNAME, CONF_PASSWORD)
return False
# Setup connection with devices/cloud
hub = awesomelights.Hub(host, username, password)
# Verify that passed in config works
if not hub.is_valid_login():
_LOGGER.error('Could not connect to AwesomeLight hub')
return False
# Add devices
add_devices(AwesomeLight(light) for light in hub.lights())
class AwesomeLight(Light):
"""Represents an AwesomeLight in Home Assistant."""
def __init__(self, light):
"""Initialize an AwesomeLight."""
self._light = light
def update(self):
"""Fetch new state data for this light.
This is the only method that should fetch new data for Home Assitant.
"""
self._light.update()
def brightness(self):
"""Brightness of the light.
This method is optional. Removing it indicates to Home Assistant
that brightness is not supported for this light.
"""
return self._light.brightness
def is_on(self):
"""If light is on."""
return self._light.is_on()
```

View File

@ -11,6 +11,11 @@ footer: true
Home Assistant can be extended by **components**. Each component is responsible for a specific domain within Home Assistant. Components can listen for or trigger events, offer services and maintain states. Components are written in Python and can do all the goodness that Python has to offer. Out of the box, Home Assistant offers a bunch of [built-in components]({{site_root}}/components/).
<p class='img'>
<img src='/images/architecture/component_interaction.png' alt='Diagram showing interaction between components and the Home Assistant core.'>
Diagram showing interaction between components and the Home Assistant core.
</p>
We can differentiate between two different types of components within Home Assistant.
#### {% linkable_title Components that interact with an Internet of Things domain %}

View File

@ -0,0 +1,26 @@
---
layout: page
title: "Requirements & Dependencies"
description: "Instructions how to define requirements and dependencies."
date: 2016-04-16 13:32
sidebar: true
comments: false
sharing: true
footer: true
---
Home Assistant allows components and platforms to specify their dependencies and requirements using the variables `DEPENDENCIES` and `REQUIREMENTS`. Both are lists that contain strings.
Dependencies are other Home Assistant components that should be setup before the platform is loaded. An example is the MQTT sensor component, which requires an active connection to an MQTT broker. If Home Assistant is unable to load and setup the MQTT component, it will not setup the MQTT sensor component.
```python
DEPENDENCIES = ['mqtt']
```
Requirements are Python libraries that you would normally install using `pip`. If Home Assistant is unable to install the requirements or verify it is installed, the component will fail to load.
Requirements is a list of strings. Each entry is a pip compatible string. For example, the media player Cast platform depends on the Python package PyChromecast v0.6.12:
```python
REQUIREMENTS = ['pychromecast==0.6.12']
```

View File

@ -1,7 +1,7 @@
---
layout: page
title: "Platform Discovery"
description: "How to make platform discovery work."
title: "Component Discovery"
description: "How to make component discovery work."
date: 2016-04-16 14:24 -07:00
sidebar: true
comments: false

View File

@ -0,0 +1,12 @@
---
layout: page
title: "Handling events"
description: "Instructions how to handle events with your component."
date: 2016-04-16 13:32
sidebar: true
comments: false
sharing: true
footer: true
---
Home Assistant has different ways of responding to events that occur in Home Assistant. These have been organized in [helper methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/helpers/event.py). Examples are `track_state_change`, `track_point_in_time`, `track_time_change`.

View File

@ -0,0 +1,36 @@
---
layout: page
title: "Initializing your components"
description: "Instructions how to handle initialization of your component."
date: 2016-04-16 13:32
sidebar: true
comments: false
sharing: true
footer: true
---
After loading, the bootstrapper will call `setup(hass, config)` method on the component to initialize it.
### {% linkable_title hass: the Home Assistant instance %}
The Home Assistant instance contains three objects to help you interact with the system.
| Object | Description |
| ------ | ----------- |
| `hass.config` | This is the core configuration of Home Assistant exposing location, temperature preferences and config directory path. [Details](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L687)
| `hass.states` | This is the StateMachine. It allows you to set states and track when they are changed. [See available methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L434). |
| `hass.bus` | This is the EventBus. It allows you to trigger and listen for events.<br>[See available methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L229). |
| `hass.services` | This is the ServiceRegistry. It allows you to register services.<br>[See available methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L568). |
### {% linkable_title config: User given configuration. %}
The `config` parameter is a dictionary containing the user supplied configuration. The keys of the dictionary are the component names and the value is another dictionary with the component configuration.
If your configuration file contains the following lines:
```yaml
example:
host: paulusschoutsen.nl
```
Then in the setup method of your component you will be able to refer to `config['example']['host']` to get the value `paulusschoutsen.nl`.

View File

@ -0,0 +1,25 @@
---
layout: page
title: "Loading your components"
description: "Instructions how to get your component loaded by Home Assistant."
date: 2016-04-16 13:32
sidebar: true
comments: false
sharing: true
footer: true
---
A component will be loaded on start if a section (ie. `light:`) for it exists in the config file. A component can also be loaded if another component is loaded that depends on it. When loading a component Home Assistant will check the following paths:
* `<config directory>/custom_components/<component name>`
* `homeassistant/components/<component name>` (built-in components)
Once loaded, a component will only be setup if all dependencies can be loaded and are able to setup. Keep an eye on the logs to see if your component could be loaded and initialized.
<p class='note warning'>
You can override a built-in component by having a component with the same name in your <code>config/custom_components</code> folder. This is not recommended and will probably break things!
</p>
<p class='note'>
Home Assistant will use the directory that contains your config file as the directory that holds your customizations. By default this is the <code>config</code> folder in your current work directory. You can use a different folder by running Home Assistant with the --config argument: <code>python3 homeassistant --config /YOUR/CONFIG/PATH/</code>.
</p>

View File

@ -9,74 +9,19 @@ sharing: true
footer: true
---
Home Assistant offers [built-in components]({{site_root}}/components/) but it is easy to build your own. If you are the kind of person that likes to learn from code rather then guide then head over to the [`config/custom_components`](https://github.com/home-assistant/home-assistant/tree/master/config/custom_components) folder in the repository for two example components. Or visit the [Custom Python Component Examples]({{site_root}}/cookbook/#custom-python-component-examples).
Alright, you're ready to make your first component. AWESOME. Don't worry, we've tried hard to keep it as easy as possible.
The first is [hello_world.py](https://github.com/home-assistant/home-assistant/blob/master/config/custom_components/hello_world.py) (this is similar to the [Basic State Setting Example](https://home-assistant.io/cookbook/python_component_basic_state/)), which is the classic "Hello World" example for Home Assistant. The second one is [example.py](https://github.com/home-assistant/home-assistant/blob/master/config/custom_components/example.py) which showcases various ways you can tap into Home Assistant to be notified when certain events occur.
### {% linkable_title Example component %}
If you want to load these components in Home Assistant, add the following lines to your `configuration.yaml` file:
Add `hello_state:` to your `configuration.yaml` file and create a file `<config_dir>/custom_components/hello_state.py` with the below code to test it locally.
```yaml
hello_world:
```python
DOMAIN = 'hello_state'
example:
target: TARGET_ENTITY
def setup(hass, config):
hass.states.set('hello.world', 'Paulus')
return True
```
`TARGET_ENTITY` should be one of your devices that can be turned on and off, ie a light or a switch. Example value could be `light.Ceiling` or `switch.AC` (if you have these devices with those names).
## {% linkable_title Loading components %}
A component will be loaded on start if a section (ie. `light:`) for it exists in the config file. A component can also be loaded if another component is loaded that depends on it. When loading a component Home Assistant will check the following paths:
* `<config directory>/custom_components/<component name>`
* `homeassistant/components/<component name>` (built-in components)
Once loaded, a component will only be setup if all dependencies can be loaded and are able to setup. Keep an eye on the logs to see if your component could be loaded and initialized.
<p class='note warning'>
You can override a built-in component by having a component with the same name in your <code>config/custom_components</code> folder. This is not recommended and will probably break things!
</p>
<p class='note'>
Home Assistant will use the directory that contains your config file as the directory that holds your customizations. By default this is the <code>config</code> folder in your current work directory. You can use a different folder by running Home Assistant with the --config argument: <code>python3 homeassistant --config /YOUR/CONFIG/PATH/</code>.
</p>
## {% linkable_title Dependencies %}
Home Assistant allows components and platforms to specify their dependencies and requirements using the variables `DEPENDENCIES` and `REQUIREMENTS`. Both are lists that contain strings.
Dependencies are other Home Assistant components that should be setup before the platform is loaded. An example is the MQTT sensor component, which requires an active connection to an MQTT broker. If Home Assistant is unable to load and setup the MQTT component, it will not setup the MQTT sensor component.
Requirements are Python libraries that you would normally install using `pip`. Each entry in a requirement list is a pip compatible string. For example, the media player Cast platform depends on the Python package PyChromecast thus `REQUIREMENTS = ['pychromecast==0.6.12']`. If Home Assistant is unable to install the package or verify it is installed, the component will fail to load.
## {% linkable_title Initializing components %}
After loading, the bootstrapper will call `setup(hass, config)` method on the component to initialize it.
### {% linkable_title `hass`: the Home Assistant instance %}
The Home Assistant instance contains three objects to help you interact with the system.
| Object | Description |
| ------ | ----------- |
| `hass.config` | This is the core configuration of Home Assistant exposing location, temperature preferences and config directory path. [Details](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L687)
| `hass.states` | This is the StateMachine. It allows you to set states and track when they are changed. [See available methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L434). |
| `hass.bus` | This is the EventBus. It allows you to trigger and listen for events.<br>[See available methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L229). |
| `hass.services` | This is the ServiceRegistry. It allows you to register services.<br>[See available methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/core.py#L568). |
### {% linkable_title `config`: User given configuration. %}
The `config` parameter is a dictionary containing the user supplied configuration. The keys of the dictionary are the component names and the value is another dictionary with the component configuration.
If your configuration file contains the following lines:
```yaml
example:
host: paulusschoutsen.nl
```
Then in the setup method of your component you will be able to refer to `config['example']['host']` to get the value `paulusschoutsen.nl`.
## {% linkable_title Responding to events %}
Home Assistant has different ways of responding to events that occur in Home Assistant. These have been organized in [helper methods](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/helpers/event.py). Examples are `track_state_change`, `track_point_in_time`, `track_time_change`.
For more examples, see the [Custom Python Component Examples](/cookbook/#custom-python-component-examples) on our examples page.

View File

@ -0,0 +1,77 @@
---
layout: page
title: "Example light platform"
description: "Minimum implementation of a Home Assistant platform."
date: 2016-04-16 14:24 -07:00
sidebar: true
comments: false
sharing: true
footer: true
---
This example is for adding support for the imaginary Awesome Lights. It shows the different best practices for developing a platform.
```python
import logging
# Import the device class from the component that you want to support
from homeassistant.components.light import Light
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
# Home Assistant depends on 3rd party packages for API specific code.
REQUIREMENTS = ['awesome_lights==1.2.3']
_LOGGER = logging.getLogger(__name__)
setup_platform(hass, config, add_devices, discovery_info=None):
"""Initialize Awesome Light platform."""
import awesomelights
# Validate passed in config
host = config.get(CONF_HOST)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
if host is None or username is None or password is None:
_LOGGER.error('Invalid config. Expected %s, %s and %s',
CONF_HOST, CONF_USERNAME, CONF_PASSWORD)
return False
# Setup connection with devices/cloud
hub = awesomelights.Hub(host, username, password)
# Verify that passed in config works
if not hub.is_valid_login():
_LOGGER.error('Could not connect to AwesomeLight hub')
return False
# Add devices
add_devices(AwesomeLight(light) for light in hub.lights())
class AwesomeLight(Light):
"""Represents an AwesomeLight in Home Assistant."""
def __init__(self, light):
"""Initialize an AwesomeLight."""
self._light = light
def update(self):
"""Fetch new state data for this light.
This is the only method that should fetch new data for Home Assitant.
"""
self._light.update()
def brightness(self):
"""Brightness of the light.
This method is optional. Removing it indicates to Home Assistant
that brightness is not supported for this light.
"""
return self._light.brightness
def is_on(self):
"""If light is on."""
return self._light.is_on()
```

View File

@ -0,0 +1,49 @@
---
layout: page
title: "Example sensor platform"
description: "Minimum implementation of a Home Assistant platform."
date: 2016-04-16 14:24 -07:00
sidebar: true
comments: false
sharing: true
footer: true
---
This is a minimum implementation of a platform for the sensor component.
### {% linkable_title Installation %}
Copy the code below and create it as a file in `<config_dir>/sensor/example.py`.
Add the following to your configuration.yaml:
```yaml
# Example configuration.yaml entry
sensor:
platform: example
```
### {% linkable_title Code %}
```python
from homeassistant.const import TEMP_CELCIUS
from homeassistant.helpers.entity import Entity
def setup_platform(hass, config, add_devices, discovery_info=None):
add_devices([ExampleSensor()])
class ExampleSensor(Entity):
@property
def name(self):
return 'Temperature'
@property
def state(self):
return 23
@property
def unit_of_measurement(self):
return TEMP_CELCIUS
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB