From d6fac22c850a5e59fe51eabdf48c43f9e67c3192 Mon Sep 17 00:00:00 2001 From: micw Date: Thu, 23 Mar 2017 22:55:44 +0100 Subject: [PATCH 01/38] Adding documentation of expire_after for mqtt sensor to expire outdated values (#2297) --- source/_components/sensor.mqtt.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/source/_components/sensor.mqtt.markdown b/source/_components/sensor.mqtt.markdown index 518d3444f09..793e7234429 100644 --- a/source/_components/sensor.mqtt.markdown +++ b/source/_components/sensor.mqtt.markdown @@ -31,6 +31,7 @@ Configuration variables: - **name** (*Optional*): The name of the sensor. Default is 'MQTT Sensor'. - **qos** (*Optional*): The maximum QoS level of the state topic. Default is 0. - **unit_of_measurement** (*Optional*): Defines the units of measurement of the sensor, if any. +- **expire_after** (*Optional*): Defines the number of seconds after the value expires if it's not updated. Default is 0 (=never expire). - **value_template** (*Optional*): Defines a [template](/topics/templating/) to extract a value from the payload. ## {% linkable_title Examples %} From 065a2d6bf4f5b0b5dc509b171ed211bcac575ca6 Mon Sep 17 00:00:00 2001 From: PetePriority Date: Fri, 24 Mar 2017 08:52:12 +0100 Subject: [PATCH 02/38] Added service description (#2319) --- source/_components/media_player.markdown | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/_components/media_player.markdown b/source/_components/media_player.markdown index 1850653639b..1148a5b78db 100644 --- a/source/_components/media_player.markdown +++ b/source/_components/media_player.markdown @@ -34,6 +34,15 @@ Available services: `turn_on`, `turn_off`, `toggle`, `volume_up`, `volume_down`, | `entity_id` | yes | Target a specific media player. Defaults to all. | | `volume_level` | no | Float for volume level | +#### {% linkable_title Service `media_player/volume_transition` %} + +| Service data attribute | Optional | Description | +|------------------------|----------|--------------------------------------------------| +| `entity_id` | yes | Target a specific media player. Defaults to all. | +| `volume_level` | no | Float for volume level | +| `transition` | no | Integer for transition time in seconds | + + #### {% linkable_title Service `media_player/media_seek` %} | Service data attribute | Optional | Description | From aa626f80b5dedc9b67de5464d256a91b9109b46e Mon Sep 17 00:00:00 2001 From: John Mihalic Date: Fri, 24 Mar 2017 16:06:48 -0400 Subject: [PATCH 03/38] Update Emby docs (#2274) * Update Emby docs * Make SSL and port configuration more clear * Variable clarifications. --- source/_components/media_player.emby.markdown | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/_components/media_player.emby.markdown b/source/_components/media_player.emby.markdown index 89f2c9605d5..ca77cbde1a3 100644 --- a/source/_components/media_player.emby.markdown +++ b/source/_components/media_player.emby.markdown @@ -10,7 +10,7 @@ footer: true logo: emby.png ha_category: Media Player ha_release: "0.32" -ha_iot_class: "Local Polling" +ha_iot_class: "Local Push" --- @@ -28,7 +28,8 @@ media_player: Configuration variables: -- **host** (*Required*): The host name or address of the device that is running Emby. +- **host** (*Optional*): The host name or address of the device that is running Emby. Defaults to ```localhost```. - **api_key** (*Required*): The api-key you would like home-assistant to use to authenticate. -- **ssl** (*Optional*): True if you want to connect with https. Be sure to set the port also. -- **port** (*Optional*): The port number. Defaults to 8096. +- **ssl** (*Optional*): True if you want to connect with https/wss. Your SSL certificate must be valid. Default is False. +- **port** (*Optional*): The port number. Defaults to 8096 with SSL set to False and 8920 with SSL set to True. +- **auto_hide** (*Optional*): True if you want to automatically hide devices that are unavailable from the Home Assistant Interface. Defaults to False. From 9640fafe21817b728d896fe4d86ae04374fec5d2 Mon Sep 17 00:00:00 2001 From: Thibault Cohen Date: Fri, 24 Mar 2017 16:18:56 -0400 Subject: [PATCH 04/38] Update Honeywell US documentation (#2057) --- source/_components/climate.honeywell.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/_components/climate.honeywell.markdown b/source/_components/climate.honeywell.markdown index 1b7a7465360..f57ecebc223 100644 --- a/source/_components/climate.honeywell.markdown +++ b/source/_components/climate.honeywell.markdown @@ -31,6 +31,8 @@ Configuration variables: - **username** (*Required*): The username of an user with access. - **password** (*Required*): The password for your given admin account. -- **away_temperature** (*Optional*): Heating setpoint when away mode is on. If omitted it defaults to 16.0 deg C. - **region** (*Optional*): Region identifier (either 'eu' or 'us'). Defaults to 'eu' if not provided. - **scan_interval**(*Optional*): Scan interval is expressed in seconds. Recommended value of 600 seconds. Default value is 120 seconds. Omitting scan_interval may result in too-frequent polling and cause you to rate-limited by Honeywell. +- **away_temperature** (*Optional*) (*only for eu region*): Heating setpoint when away mode is on. If omitted it defaults to 16.0 deg C. +- **cool_away_temperature** (*Optional*) (*only for us region*): Cooling setpoint when away mode is on. If omitted it defaults to 30.0 deg C. +- **heat_away_temperature** (*Optional*) (*only for us region*): Heating setpoint when away mode is on. If omitted it defaults to 16.0 deg C. From 3e06754c1451e0afb092d06cf929940bf45d27e6 Mon Sep 17 00:00:00 2001 From: Teemu R Date: Sun, 26 Mar 2017 10:55:48 +0200 Subject: [PATCH 05/38] Update switch.tplink.markdown (#2335) --- source/_components/switch.tplink.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/source/_components/switch.tplink.markdown b/source/_components/switch.tplink.markdown index 9af82a469d3..f54235fede7 100644 --- a/source/_components/switch.tplink.markdown +++ b/source/_components/switch.tplink.markdown @@ -19,6 +19,7 @@ The `tplink` switch platform allows you to control the state of your [TPLink sma Supported units: - HS100 +- HS105 - HS110 - HS200 From f45ea8261dc475f84b54b841cb57b2c58ec6558f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 26 Mar 2017 15:49:21 +0200 Subject: [PATCH 06/38] Add switch example and list of supported devices (#2312) --- source/_docs/mqtt/discovery.markdown | 33 +++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/source/_docs/mqtt/discovery.markdown b/source/_docs/mqtt/discovery.markdown index 1932e30cc9f..bcff437f8e6 100644 --- a/source/_docs/mqtt/discovery.markdown +++ b/source/_docs/mqtt/discovery.markdown @@ -11,7 +11,15 @@ logo: mqtt.png redirect_from: /components/mqtt/#discovery --- -The discovery of MQTT devices will enable one to use MQTT devices with only minimal configuration effort on the side of Home Assistant. The configuration is done on the device itself and the topic used by the device. Similar to the [HTTP binary sensor](/components/binary_sensor.http/) and the [HTTP sensor](/components/sensor.http/). Currently, binary sensors, lights and sensors are supported. A discovery binary sensor or sensor will load the `mqtt` platform. For discovered light components the JSON payload can contain a `platform` attribute with one of `mqtt`, `mqtt_json` or `mqtt_template` defined. If no `platform` attribute is defined then `mqtt` is used. +The discovery of MQTT devices will enable one to use MQTT devices with only minimal configuration effort on the side of Home Assistant. The configuration is done on the device itself and the topic used by the device. Similar to the [HTTP binary sensor](/components/binary_sensor.http/) and the [HTTP sensor](/components/sensor.http/). + +Supported by MQTT discovery: + +- [Binary sensors](/components/binary_sensor.mqtt/) +- [Lights](/components/light.mqtt/) +- [Sensors](/components/sensor.mqtt/) +- [Switches](/components/switch.mqtt/) + To enable MQTT discovery, add the following to your `configuration.yaml` file: @@ -34,13 +42,13 @@ The discovery topic need to follow a specific format: - ``: One of the supported components, eg. `binary_sensor`. - ``: The ID of the device. This will become the `entity_id` in Home Assistant. -- ``: The topic `config` or `state` which defines the current action. +- `<>`: The topic `config` or `state` which defines the current action. -The payload will be checked like an entry in your `configuration.yaml` file if a new device is added. This means that missing variables will be filled with the platform's default values. +The payload will be checked like an entry in your `configuration.yaml` file if a new device is added. This means that missing variables will be filled with the platform's default values. All configuration variables which are *required* must be present in the initial payload send to `/config`. -### {% linkable_title Example %} +### {% linkable_title Examples %} -A motion detection device which can be represented by a [binary sensor](/components/binary_sensor.mqtt/) for your garden would sent its configuration as JSON payload to the Configuration topic. After the first message to `config`, then the MQTT messages sent to the State topic will update the state in Home Assistant. +A motion detection device which can be represented by a [binary sensor](/components/binary_sensor.mqtt/) for your garden would sent its configuration as JSON payload to the Configuration topic. After the first message to `config`, then the MQTT messages sent to the state topic will update the state in Home Assistant. - Configuration topic: `homeassistant/binary_sensor/garden/config` - State topic: `homeassistant/binary_sensor/garden/state` @@ -57,3 +65,18 @@ Update the state. $ mosquitto_pub -h 127.0.0.1 -p 1883 -t "homeassistant/binary_sensor/garden/state" -m ON ``` +Setting up a switch is similar but requires a `command_topic` as mentionend in the [MQTT switch documentation](/components/switch.mqtt/). + +- Configuration topic: `homeassistant/switch/irrigation/config` +- State topic: `homeassistant/switch/irrigation/state` +- Payload: `{"name": "garden", "command_topic": "homeassistant/switch/irrigation/set"}` + +```bash +$ mosquitto_pub -h 127.0.0.1 -p 1883 -t "homeassistant/switch/irrigation/config" \ + -m '{"name": "garden", "command_topic": "homeassistant/switch/irrigation/set"}' +``` +Set the state. + +```bash +$ mosquitto_pub -h 127.0.0.1 -p 1883 -t "homeassistant/switch/irrigation/set" -m ON +``` From 52f426b7fc8edb2e8e71afe800e62717bd2021fb Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 26 Mar 2017 15:53:10 +0200 Subject: [PATCH 07/38] Add unit of measurement (#2337) --- source/_components/sensor.random.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/source/_components/sensor.random.markdown b/source/_components/sensor.random.markdown index fe73e81f66d..44bdfad4fa8 100644 --- a/source/_components/sensor.random.markdown +++ b/source/_components/sensor.random.markdown @@ -29,4 +29,5 @@ Configuration variables: - **name** (*Optional*): Name of the sensor to use in the frontend. Defaults to `Random Sensor`. - **minimum** (*Optional*): Lower limit for the values. Defaults to `0`. - **maximum** (*Optional*): Upper limit for the values. Defaults to `20`. +- **unit_of_measurement** (*Optional*): Defines the units of measurement of the sensor, if any. From 090d7dd3b0f1280d63e0891c26da42d5e0420d1f Mon Sep 17 00:00:00 2001 From: David Straub Date: Sun, 26 Mar 2017 19:07:20 +0200 Subject: [PATCH 08/38] Documentation for new MVG sensor (#2311) * Add MVG logo * Add documentation for MVG sensor --- source/_components/sensor.mvglive.markdown | 66 +++++++++++++++++++++ source/images/supported_brands/mvg.png | Bin 0 -> 24280 bytes 2 files changed, 66 insertions(+) create mode 100644 source/_components/sensor.mvglive.markdown create mode 100644 source/images/supported_brands/mvg.png diff --git a/source/_components/sensor.mvglive.markdown b/source/_components/sensor.mvglive.markdown new file mode 100644 index 00000000000..2d7aec46b8c --- /dev/null +++ b/source/_components/sensor.mvglive.markdown @@ -0,0 +1,66 @@ +--- +layout: page +title: "MVG" +description: "Instructions how to integrate Munich public transport departure times into Home Assistant." +date: 2017-03-21 20:00 +sidebar: true +comments: false +sharing: true +footer: true +logo: mvg.png +ha_category: Transport +ha_release: 0.41 +ha_iot_class: "Cloud Polling" +--- + + +The `mvglive` sensor will give you the departure time of the next bus, tram, subway, or train at the next station or stop in the Munich public transport network. Additional details such as the line number and destination are present in the attributes. + +To enable this sensor, add the following lines to your `configuration.yaml` file: + +```yaml +# Example configuration.yaml entry +sensor: + - platform: mvglive + station: STATION_OR_STOP +``` + +Configuration variables: + + - **station** (*Required*): Name of the stop or station. Visit [the MVG live web site](http://www.mvg-live.de) to find valid names. + - **destination** (*Optional*): Name of the line's final destination to display only connections ending there. + - **line** (*Optional*): Online display connections from this line, e.g. `'U6'`, `'S2'`. + - **offset** (*Optional*): Do not display connections departing sooner than this number of minutes (defaults to 0). Useful if you are a couple of minutes away from the stop. + - **bus** (*Optional*): If 'False', do not display bus connections + - **tram** (*Optional*): If 'False', do not display tram connections + - **ubahn** (*Optional*): If 'False', do not display U-Bahn (subway) connections + - **sbahn** (*Optional*): If 'False', do not display S-Bahn (suburban train) connections + +## {% linkable_title Examples %} + +### {% linkable_title Full configuration %} + +The example below shows a full configuration using the 'line' argument. + +```yaml +# Example configuration.yml entry +sensor: + - platform: mvglive + station: Marienplatz + line: U6 + offset: 5 + destination: Garching-Forschungszentrum +``` + +Another example showing all bus connections at the main station. + +```yaml +# Example configuration.yml entry +sensor: + - platform: mvglive + station: Hauptbahnhof + offset: 2 + sbahn: False + ubahn: False + tram: False +``` diff --git a/source/images/supported_brands/mvg.png b/source/images/supported_brands/mvg.png new file mode 100644 index 0000000000000000000000000000000000000000..8d9edec78d4493fe22184f1a6c347d70c511b1b3 GIT binary patch literal 24280 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 literal 0 HcmV?d00001 From e4491462b1a0e06b8f9cd54032febc439e8e412f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 16 Mar 2017 07:52:27 +0100 Subject: [PATCH 09/38] Update ha_release --- source/_components/binary_sensor.workday.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/_components/binary_sensor.workday.markdown b/source/_components/binary_sensor.workday.markdown index e7d729b88b6..0fd40be6057 100644 --- a/source/_components/binary_sensor.workday.markdown +++ b/source/_components/binary_sensor.workday.markdown @@ -15,6 +15,8 @@ ha_release: 0.41 The `workday` binary sensor indicates, whether the current day is a workday or not. It allows specifying, which days of the week counts as workdays and also uses the python module [holidays](https://pypi.python.org/pypi/holidays) to incorporate information about region-specific public holidays. +To enable the `workday` sensor in your installation, add the following to your `configuration.yaml` file: + ```yaml # Example configuation.yaml entry binary_sensor: @@ -32,8 +34,8 @@ Configuration variables: Days are specified as follows: `mon`, `tue`, `wed`, `thu`, `fri`, `sat`, `sun`. The keyword `holiday` is used for public holidays identified by the holidays module. - Example usage for automation: + ```yaml automation: alias: Turn on heater on workdays From 9ad153b42fa2ff3ac2ae66650c6095dc6d406a01 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 26 Mar 2017 19:08:53 +0200 Subject: [PATCH 10/38] Update ha_release --- source/_components/sensor.mvglive.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/_components/sensor.mvglive.markdown b/source/_components/sensor.mvglive.markdown index 2d7aec46b8c..5d461ad19e3 100644 --- a/source/_components/sensor.mvglive.markdown +++ b/source/_components/sensor.mvglive.markdown @@ -9,7 +9,7 @@ sharing: true footer: true logo: mvg.png ha_category: Transport -ha_release: 0.41 +ha_release: 0.42 ha_iot_class: "Cloud Polling" --- From 7286ed203cf4f13b5679b80b74e01ccf7abaa120 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 26 Mar 2017 19:09:27 +0200 Subject: [PATCH 11/38] Update for 0.42 --- source/_components/ha.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/_components/ha.markdown b/source/_components/ha.markdown index a9afd2719ca..5a31db5ebbc 100644 --- a/source/_components/ha.markdown +++ b/source/_components/ha.markdown @@ -1,6 +1,6 @@ --- layout: page -title: "Home Assistant 0.41" +title: "Home Assistant 0.42" description: "" date: 2016-12-16 17:00 sidebar: true @@ -9,7 +9,7 @@ sharing: true footer: true logo: home-assistant.png ha_category: Other -ha_release: 0.41 +ha_release: 0.42 --- Details about the latest release can always be found at: From 2459f599bc6262047c9b6416734480dae2a0aeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Gro=C3=9F?= Date: Sun, 26 Mar 2017 19:44:39 +0200 Subject: [PATCH 12/38] Clarify hash in Google Calendar search term (#2305) Relates to https://github.com/home-assistant/home-assistant/issues/6670 --- source/_components/calendar.google.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/_components/calendar.google.markdown b/source/_components/calendar.google.markdown index e57f182091e..658dae1f2bc 100644 --- a/source/_components/calendar.google.markdown +++ b/source/_components/calendar.google.markdown @@ -95,7 +95,7 @@ From this we will end up with the binary sensors `calendar.test_unimportant` and But what if you only wanted it to toggle based on all events? Just leave out the *search* parameter. -**Note**: If you use a `#` sign for search then wrap it up. It's better to be safe! +**Note**: If you use a `#` sign for `search` then wrap the whole search term in quotes. Otherwise everything following the hash sign would be considered a YAML comment. ### {% linkable_title Sensor attributes %} From 96dc21ad3ae2ae4f7f7bed65806d5ca400a9e057 Mon Sep 17 00:00:00 2001 From: John Mihalic Date: Mon, 27 Mar 2017 08:01:09 -0400 Subject: [PATCH 13/38] Update hikvision docs for NVR support (#2340) --- .../binary_sensor.hikvision.markdown | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/source/_components/binary_sensor.hikvision.markdown b/source/_components/binary_sensor.hikvision.markdown index 8dcbcb2f668..72dbd613c1d 100644 --- a/source/_components/binary_sensor.hikvision.markdown +++ b/source/_components/binary_sensor.hikvision.markdown @@ -13,9 +13,9 @@ ha_release: 0.35 ha_iot_class: "Local Push" --- -The Hikvision Binary Sensor is a platform that parses the event stream of a [Hikvision IP Camera](http://www.hikvision.com/) and presents the camera events to Home Assistant as binary sensors with either an "off" or "on" state. +The Hikvision Binary Sensor is a platform that parses the event stream of a [Hikvision IP Camera or NVR](http://www.hikvision.com/) and presents the camera/nvr events to Home Assistant as binary sensors with either an "off" or "on" state. -The platform will automatically add all sensors to Home Assistant that are configured within the camera interface to "Notify the surveillance center" as a trigger. If you would like to hide a sensor type you can do so by either unchecking "Notify the surveillance center" in the camera configuration or by using the "ignored" customize option detailed below. +The platform will automatically add all sensors to Home Assistant that are configured within the camera/nvr interface to "Notify the surveillance center" as a trigger. If you would like to hide a sensor type you can do so by either unchecking "Notify the surveillance center" in the camera configuration or by using the "ignored" customize option detailed below. For example, if you configure a camera with the name "Front Porch" that has motion detection and line crossing events enabled to notify the surveillance center the following binary sensors will be added to Home Assistant: @@ -24,7 +24,16 @@ binary_sensor.front_porch_motion binary_sensor.front_port_line_crossing ``` -This platform should work with all Hikvision cameras, and has been confirmed to work with the following models: +When used with a NVR device the sensors will be appeneded with the channel number they represent. For example, if you configure an NVR with the name "Home" that supports 2 cameras with motion detection and line crossing events enabled to notify the surveillance center the following binary sensors will be added to Home Assistant: + +``` +binary_sensor.home_motion_1 +binary_sensor.home_motion_2 +binary_sensor.home_line_crossing_1 +binary_sensor.home_line_crossing_2 +``` + +This platform should work with all Hikvision cameras and nvrs, and has been confirmed to work with the following models: - DS-2CD3132-I - DS-2CD2232-I5 - DS-2CD2032-I @@ -55,7 +64,6 @@ Configuration options for a Hikvision Sensor: Supported sensor/event types are: - Motion -- IO Trigger - Line Crossing - Field Detection - Video Loss @@ -70,9 +78,10 @@ Supported sensor/event types are: - Bad Video - PIR Alarm - Face Detection +- Scene Change Detection -Example of a configuration in your `configuration.yaml` that utilizes the customize options: +Example of a configuration in your `configuration.yaml` that utilizes the customize options for a camera: ```yaml binary_sensor: @@ -83,8 +92,25 @@ binary_sensor: username: user password: pass customize: - sensor_name_1: + motion: delay: 30 - sensor_name_2: + line_crossing: + ignored: True +``` + +Example of a configuration in your `configuration.yaml` that utilizes the customize options for a nvr: + +```yaml +binary_sensor: + platform: hikvision + host: 192.168.X.X + port: 80 + ssl: False + username: user + password: pass + customize: + motion_1: + delay: 30 + field_detection_2: ignored: True ``` From 51ca0c4d7785bbfb7042ea6b9415d12de2f4961f Mon Sep 17 00:00:00 2001 From: John Arild Berentsen Date: Wed, 29 Mar 2017 18:52:50 +0200 Subject: [PATCH 14/38] Update z-wave.markdown (#2321) * Update z-wave.markdown * Update z-wave.markdown * Update z-wave.markdown Update for #6832 --- source/_docs/z-wave.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/source/_docs/z-wave.markdown b/source/_docs/z-wave.markdown index eaf3e07f995..054652db65c 100644 --- a/source/_docs/z-wave.markdown +++ b/source/_docs/z-wave.markdown @@ -85,6 +85,7 @@ Configuration variables: - **ignored** (*Optional*): Ignore this entity completely. It won't be shown in the Web Interface and no events are generated for it. - **refresh_value** (*Optional*): Enable refreshing of the node value. Only the light component uses this. Defaults to False. - **delay** (*Optional*): Specify the delay for refreshing of node value. Only the light component uses this. Defaults to 2 seconds. + - **invert_openclose_buttons** (*Optional*): Inverts function of the open and close buttons for the cover domain. Defaults to False - **debug** (*Optional*): Print verbose z-wave info to log. Defaults to False. To find the path of your Z-Wave USB stick or module, run: From 8c8b44b64439cb0bc57508f41b8b97ec267ec552 Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Thu, 30 Mar 2017 00:51:22 -0700 Subject: [PATCH 15/38] Added documentation changes for ZM external trigger (#2350) Signed-off-by: Andrey Petrov --- source/_components/switch.zoneminder.markdown | 17 +++++++++++++++++ source/_components/zoneminder.markdown | 1 + 2 files changed, 18 insertions(+) diff --git a/source/_components/switch.zoneminder.markdown b/source/_components/switch.zoneminder.markdown index e9312a7ca09..51f7aa5d23f 100644 --- a/source/_components/switch.zoneminder.markdown +++ b/source/_components/switch.zoneminder.markdown @@ -34,6 +34,23 @@ Configuration variables: - **command_on** (*Required*): The function you want the camera to run when turned on. - **command_off** (*Required*): The function you want the camera to run when turned off. +External trigger mode: + +Zoneminder supports "External Trigger", where recording is triggered out-of-band (not with ZM's built-in motion detector). +This is useful if your camera takes a while to 'warmup' and you use some external sensor like PIR motion detector. +In this case camera can be kept in 'Nodect' state so it is warm and ready to capture. Once external trigger is activated camera starts recording immediately. +This way you will not lose any frames and actually see how your S.W.A.T team deals with the intruder stepped into your nuclear facility. + +Configuration variables: + +- **ext_trigger_enable** (*Optional*): Enable external trigger switch. This will create 'trigger' switch for each of your monitors. +- **ext_trigger_time** (*Optional*): How long ZM is to record once switch is triggered. +- **ext_trigger_cause** (*Optional*): Text that will appear as 'cause' in ZM event log. + +Please note: +* If you use trigger mode, it is recommended to keep camera in 'Nodect' state, so set both **command_on** and **command_off** to Nodect. +* Make sure OPT_TRIGGER is enabled in ZM +* If your trigger source can generate "no motion" event, you may want to set **ext_trigger_time** to some large value.

The default functions installed by ZoneMinder are: None, Monitor, Modect, Record, Mocord, Nodect. diff --git a/source/_components/zoneminder.markdown b/source/_components/zoneminder.markdown index bec7f12ffdb..650cbf90f4b 100644 --- a/source/_components/zoneminder.markdown +++ b/source/_components/zoneminder.markdown @@ -28,6 +28,7 @@ Configuration variables: - **ssl** (*Optional*): Set to `True` if your ZoneMinder installation is using SSL. Default to `False`. - **username** (*Optional*): Your ZoneMinder username. - **password** (*Optional*): Your ZoneMinder password. Required if `OPT_USE_AUTH` is enabled in ZM. +- **trigger_port** (*Optional*): ZM's external trigger port. Default is 6802 ### {% linkable_title Full configuration %} From 8da0dfa74f8f26c79c112e47314849b8ba7f971f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 31 Mar 2017 08:56:44 -0700 Subject: [PATCH 16/38] Revert "Added documentation changes for ZM external trigger (#2350)" (#2359) This reverts commit 8c8b44b64439cb0bc57508f41b8b97ec267ec552. --- source/_components/switch.zoneminder.markdown | 17 ----------------- source/_components/zoneminder.markdown | 1 - 2 files changed, 18 deletions(-) diff --git a/source/_components/switch.zoneminder.markdown b/source/_components/switch.zoneminder.markdown index 51f7aa5d23f..e9312a7ca09 100644 --- a/source/_components/switch.zoneminder.markdown +++ b/source/_components/switch.zoneminder.markdown @@ -34,23 +34,6 @@ Configuration variables: - **command_on** (*Required*): The function you want the camera to run when turned on. - **command_off** (*Required*): The function you want the camera to run when turned off. -External trigger mode: - -Zoneminder supports "External Trigger", where recording is triggered out-of-band (not with ZM's built-in motion detector). -This is useful if your camera takes a while to 'warmup' and you use some external sensor like PIR motion detector. -In this case camera can be kept in 'Nodect' state so it is warm and ready to capture. Once external trigger is activated camera starts recording immediately. -This way you will not lose any frames and actually see how your S.W.A.T team deals with the intruder stepped into your nuclear facility. - -Configuration variables: - -- **ext_trigger_enable** (*Optional*): Enable external trigger switch. This will create 'trigger' switch for each of your monitors. -- **ext_trigger_time** (*Optional*): How long ZM is to record once switch is triggered. -- **ext_trigger_cause** (*Optional*): Text that will appear as 'cause' in ZM event log. - -Please note: -* If you use trigger mode, it is recommended to keep camera in 'Nodect' state, so set both **command_on** and **command_off** to Nodect. -* Make sure OPT_TRIGGER is enabled in ZM -* If your trigger source can generate "no motion" event, you may want to set **ext_trigger_time** to some large value.

The default functions installed by ZoneMinder are: None, Monitor, Modect, Record, Mocord, Nodect. diff --git a/source/_components/zoneminder.markdown b/source/_components/zoneminder.markdown index 650cbf90f4b..bec7f12ffdb 100644 --- a/source/_components/zoneminder.markdown +++ b/source/_components/zoneminder.markdown @@ -28,7 +28,6 @@ Configuration variables: - **ssl** (*Optional*): Set to `True` if your ZoneMinder installation is using SSL. Default to `False`. - **username** (*Optional*): Your ZoneMinder username. - **password** (*Optional*): Your ZoneMinder password. Required if `OPT_USE_AUTH` is enabled in ZM. -- **trigger_port** (*Optional*): ZM's external trigger port. Default is 6802 ### {% linkable_title Full configuration %} From 175f6129b9bc5d3984730853035f4991be5b8c1b Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Fri, 31 Mar 2017 19:29:07 +0200 Subject: [PATCH 17/38] Remove references to deprecated `new_devices_group` (#2355) * Remove `new_devices_group` references. * Remove `new_devices_groups` references. * Document automatic_add flag. * Document automatic_add for sensor. * Document replacement for removed new_devices_group * Document replacement for removed new_devices_group. --- source/_components/light.rflink.markdown | 15 ++------------- source/_components/sensor.rflink.markdown | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/source/_components/light.rflink.markdown b/source/_components/light.rflink.markdown index a015d11a2ab..e6cd27975b4 100644 --- a/source/_components/light.rflink.markdown +++ b/source/_components/light.rflink.markdown @@ -18,17 +18,6 @@ First you have to set up your [rflink hub](/components/rflink/). After configuring the RFLink hub lights will be automatically discovered and added. -New/unknown lights can be assigned to a default group automatically by specifying the `new_devices_group` option with a group name. If the group doesn't exist it will be created. - -For example: - -```yaml -# Example configuration.yaml entry -sensor: - platform: rflink - new_devices_group: "New Rflink Lights" -``` - RFLink switch/light ID's are composed of: protocol, id, switch. For example: `newkaku_0000c6c2_1`. Once the ID of a light is known it can be used to configure the light in HA, for example to add it to a different group, hide it or configure a nice name. @@ -49,8 +38,8 @@ light: Configuration variables: +- **automatic_add** (*Optional*): Automatically add new/unconfigured devices to HA if detected (default: True). - **devices** (*Optional*): A list of devices with their name to use in the frontend. -- **new_devices_group** (*Optional*): Create group to add new/unknown devices to. - **device_defaults**: (*Optional*) - **fire_event** (*Optional*): Set default `fire_event` for Rflink switch devices (see below). - **signal_repetitions** (*Optional*): Set default `signal_repetitions` for Rflink switch devices (see below). @@ -101,7 +90,7 @@ By default new lights are assigned the `switchable` type. Protocol supporting di Lights are added automatically when the RFLink gateway intercepts a wireless command in the ether. To prevent cluttering the frontend use any of these methods: -- Configure a `new_devices_group` for lights and optionally add it to a different `view`. +- Disable automatically adding of unconfigured new sensors (set `automatic_add` to `false`). - Hide unwanted devices using [customizations](/getting-started/customizing-devices/) - [Ignore devices on a platform level](/components/rflink/#ignoring-devices) diff --git a/source/_components/sensor.rflink.markdown b/source/_components/sensor.rflink.markdown index 759e51c8ed3..ab94b7c92b2 100644 --- a/source/_components/sensor.rflink.markdown +++ b/source/_components/sensor.rflink.markdown @@ -18,17 +18,6 @@ First you have to set up your [rflink hub](/components/rflink/). After configuring the RFLink hub sensors will be automatically discovered and added. -New/unknown sensors can be assigned to a default group automatically by specifying the `new_devices_group` option with a group name. If the group doesn't exist it will be created. - -For example: - -```yaml -# Example configuration.yaml entry -sensor: - platform: rflink - new_devices_group: "New RFLink Sensors" -``` - RFLink sensor ID's are composed of: protocol, id and type (optional). For example: `alectov1_0334_temp`. Some sensors emit multiple types of data. Each will be created as its own Once the ID of a sensor is known it can be used to configure the sensor in HA, for example to add it to a different group, hide it or configure a nice name. @@ -47,8 +36,8 @@ sensor: Configuration variables: +- **automatic_add** (*Optional*): Automatically add new/unconfigured devices to HA if detected (default: True). - **devices** (*Optional*): A list of devices with their name to use in the frontend. -- **new_devices_group** (*Optional*): Create group to add new/unknown devices to. Device configuration variables: @@ -61,7 +50,7 @@ Device configuration variables: Sensors are added automatically when the RFLink gateway intercepts a wireless command in the ether. To prevent cluttering the frontend use any of these methods: -- Configure a `new_devices_group` for sensors and optionally add it to a different `view`. +- Disable automatically adding of unconfigured new sensors (set `automatic_add` to `false`). - Hide unwanted devices using [customizations](/getting-started/customizing-devices/) - [Ignore devices on a platform level](/components/rflink/#ignoring-devices) From 119d0f94613305111c4060ba7023236874e52420 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Fri, 31 Mar 2017 19:32:23 +0200 Subject: [PATCH 18/38] Linkable reference for rflink debug logging. (#2354) --- source/_components/rflink.markdown | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/source/_components/rflink.markdown b/source/_components/rflink.markdown index 80af235945b..ddbc650e759 100644 --- a/source/_components/rflink.markdown +++ b/source/_components/rflink.markdown @@ -121,3 +121,27 @@ If you find a device is recognized differently, with different protocols or the - The platform implementions take care of creating new devices (if enabled) for unsees incoming packet id's. - Device entities take care of matching to the packet ID, interpreting and performing actions based on the packet contents. Common entitiy logic is maintained in this main component. +### {% linkable_title Debug logging %} + +For debugging purposes or context when investigating issues you can enable debug logging for Rflink with the following config snippet: + +```yaml +logger: + default: error + logs: + rflink: debug + homeassistant.components.rflink: debug +``` + +This will give you output looking like this: + +``` +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] received data: 20;00;Nod +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] received data: o RadioFrequencyLink - R +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] received data: FLink Gateway V1.1 - R45 +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] received data: ; +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] got packet: 20;00;Nodo RadioFrequencyLink - RFLink Gateway V1.1 - R45; +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] decoded packet: {'firmware': 'RFLink Gateway', 'revision': '45', 'node': 'gateway', 'protocol': 'unknown', 'hardware': 'Nodo RadioFrequencyLink', 'version': '1.1'} +17-03-07 20:12:05 DEBUG (MainThread) [rflink.protocol] got event: {'version': '1.1', 'firmware': 'RFLink Gateway', 'revision': '45', 'hardware': 'Nodo RadioFrequencyLink', 'id': 'rflink'} +17-03-07 20:12:05 DEBUG (MainThread) [homeassistant.components.rflink] event of type unknown: {'version': '1.1', 'firmware': 'RFLink Gateway', 'revision': '45', 'hardware': 'Nodo RadioFrequencyLink', 'id': 'rflink'} +``` From 03c579af7b98715960e015266fa4f6f8d69a7540 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 31 Mar 2017 14:53:18 -0400 Subject: [PATCH 19/38] Added documentation for Ring binary sensor (#2231) --- .../_components/binary_sensor.ring.markdown | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 source/_components/binary_sensor.ring.markdown diff --git a/source/_components/binary_sensor.ring.markdown b/source/_components/binary_sensor.ring.markdown new file mode 100644 index 00000000000..2b6e75db388 --- /dev/null +++ b/source/_components/binary_sensor.ring.markdown @@ -0,0 +1,38 @@ +--- +layout: page +title: "Ring" +description: "Instructions on how to integrate your Ring.com devices within Home Assistant." +date: 2017-03-10 10:00 +sidebar: true +comments: false +sharing: true +footer: true +logo: ring.png +ha_category: Binary Sensor +ha_release: 0.40 +--- + +The `ring` binary sensor allows you to integrate your [Ring.com](https://ring.com/) devices in Home Assistant. + +Currently only doorbells are supported by this sensor. + +To enable device linked in your [Ring.com](https://ring.com/) account, add the following to your `configuration.yaml` file: + +```yaml +# Example configuration.yaml entry +binary_sensor: + - platform: ring + username: USERNAME + password: PASSWORD + monitored_conditions: + - ding + - motion +``` + +Configuration variables: + +- **username** (*Required*): The username for accessing your Ring account. +- **password** (*Required*): The password for accessing your Ring account. +- **monitored_conditions** array (*Required*): Conditions to display in the frontend. The following conditions can be monitored. + - **ding**: Return a boolean value when the doorbell button was pressed. + - **motion**: Return a boolean value when the a moviment was detected by the Ring doorbell. From 527a888af8ed52903d83f9d2ad4690520df1020d Mon Sep 17 00:00:00 2001 From: Anubhaw Arya Date: Fri, 31 Mar 2017 12:20:08 -0700 Subject: [PATCH 20/38] Lockitron page (#2339) * Lockitron page * Configuration variables instead of service data attributes --- .gitignore | 2 ++ source/_components/lock.lockitron.markdown | 30 +++++++++++++++++++ source/images/supported_brands/lockitron.png | Bin 0 -> 2506 bytes 3 files changed, 32 insertions(+) create mode 100644 source/_components/lock.lockitron.markdown create mode 100644 source/images/supported_brands/lockitron.png diff --git a/.gitignore b/.gitignore index bc734ac2e59..ec8690ad29c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ source/stylesheets/screen.css vendor node_modules source/.jekyll-metadata +*.iml +.idea/ \ No newline at end of file diff --git a/source/_components/lock.lockitron.markdown b/source/_components/lock.lockitron.markdown new file mode 100644 index 00000000000..c26a16be5f8 --- /dev/null +++ b/source/_components/lock.lockitron.markdown @@ -0,0 +1,30 @@ +--- +layout: page +title: "Lockitron Lock" +description: "Instructions how to integrate Lockitron locks into Home Assistant." +date: 2017-03-24 00:00 +sidebar: true +comments: false +sharing: true +footer: true +logo: lockitron.png +ha_category: Lock +ha_iot_class: "Cloud Polling" +ha_release: "0.42" +--- + +The `lockitron` platform allows you to control your [Lockitron](https://lockitron.com/) lock from within Home Assistant. +In order to get the correct `access_token` and `id`, log on to their [developer page](https://api.lockitron.com/), create a new app, and get the access_token they give you. +Then, call the retrieve all locks function on the page and get the id of your lock (make sure you get your lock's id and not the virtual lock they create for you). + +```yaml +lock: + - platform: lockitron + access_token: asdf + id: fdsa +``` + +| Configuration variables| Optional | Description | +| ---------------------- | -------- | ----------- | +| `access_token` | no | The security token provided by Lockitron to lock and unlock your lock +| `id` | no | The lock id given by Lockitron (should be a GUID) \ No newline at end of file diff --git a/source/images/supported_brands/lockitron.png b/source/images/supported_brands/lockitron.png new file mode 100644 index 0000000000000000000000000000000000000000..93237dbf13134ed3cc62d389fed1fd93aff37ae6 GIT binary patch literal 2506 zcmbW3XE+;*8pqS>q*M>B7;&iL)QH4hEe=tX6sb}qwPHnU#Syj2QKL;zJw|P*S))x5 zBQdHPQnRQPqQ@vDMtYFi*S+8F$9vxo@BjbdeV^z3@PB^Kn`8~Y#m_6o3jhH4&CN_~ z0e};zWAAb9%yI8;aX=r7C>G{`MfiJSLtTT=03#27H?)-bLsu`fE!x#1ERccL2LR6d znVT5h#Z9vFjsj=3f${ZPdj?nlD76}3Ycymu&YM;(1wZ|_!jrp#wkNEO3S(1wr7p9J zbapy|46E)K_)QF`%}u<@bBWH_Y~592kdN>9KP%o}_=NhC!!@ArK67ggN9->2-KXdm zvU-&!J0i`YET>NG*A~+1(Ke?50H6xMuzCl63E(h10WyBx7G2m4m^&TtnyROY7b%8} z002)oCjlbQ0-8TO)jT zJfIT3eoTrFsVY(q?TQGsyzPgL6bg0%&729u%=R83t*7ftye19D>XLG)(-d7*wWrsi;Wli0)EaJ}?_F$*g<17-E@^Lz%Oqm{UJtf0bI+@o4WIV3 z*xqHoeuoNr*<|yPdv7p=i+PKbpw=9=y?{w9e)5v04fLq3O6$4fdH94Xh~URp&}|Pg z6Y|VF)rY~jn$>)`g}K8r<=6GqwefRnmE9!h;ze|$fBqaO$J7TyljhE~Tw?X~v2=>} zINLn+&k?&>I!hK~Oiawome3gNLDOpW{*v_JD?@qUTeR_3AnkEgIV!GkUD1uEB>+nF zP33GWS&|DH!NqjukBA33fA)jsl)X_oW&}(d@v$U%%F4v1&O#mK10tm4R`%1GWTmpG z+2&NBzoLuRkKZl@31zTUGY`w_zY)_mjaaGnW%ucMQxP?W6Op*ytjPp#|fguN5o zP6P%F6MKDABgG|eN3##tTc1wCR0sPc{$3wG)K)k(7;ybau%a5rnHg?8+Abn7p+v_pLIqha3tmVel|)o zuGPj8v+hZ;sAk3j?sgGAj{T~?n<8MQ{G(3^9Eyx@F~lk?hUo7E39lmTEIhB^su@jN z*MJl(xEqx!hovh4Gb=4wOo5X<;hU)i?_TKt0=Bvl=cw4Ck<#Av=|ic~VobhC_8Yzj z^D073%Q8nT-~ks*1j6|X1VO%ka1|rz^y$&)eq~7f-eP($#NSfCEaUssZxa{Ra}vlc z211B(I}rs$kaIkPUEh&@J*S$1xyU#&Qgk zV`V1-rr+0D)*q3ALJE|gaxy@n>C2sCbDqdBpHy(MU!_A}h$f0@e>yTc!$TS00Q#wW z{g1*1-Uv~*H_ZWI#1A;dY^1WH6keYNrtcZ3+VyY$W#`F+AV+vrSpg|BPOdcII)}{I zm^8@JvJ?TT7@lA1Lp&DdIYv{UsLiQkN_C|v?2Z=OuHMz+_7&)RW=HPRCzCMyVH`wl`0vQwcx~P13 zIAq*1UrO~S8u$2_wOL4PirX&{ZJWLIuRn}?RQs8d(w86Xrxh7>!#kIPX8*#i4Pv@R zm+nW9Z~d6AZvbq)_++}okuM zvQwE+9tZVfRHiI@IZi-xTN-Q*ULXazey~ogv2-UQVw%?jCmVzCpDv4yf zuSzxs}rYCkuVUBWz45UvGYy(v6X3& zX1bthS7%rv<~i8n%V~NJP{lNtr1`a5D?aeP=!V+RyAM;Hj_GW7>0Yq0f7W5ma)V01 zv*VZwMbLIHX$Mba|8unA;i0S8Xzhxco)(j7y8A`k>m|@xD;D}~i)12FvV2wN+6r#* z{8T1EP;z9E5|_qhq>wZhb5B7?>Cmp$B<`efm5|W-t*>O1o=4^@@~^>?S$mF7bM_qG(Gfu3!vi{v7enGEH^A%y{`UQZFEd0Ud8t+&QRok`*SufADx2$To#ht>gD}a P|GjGtgPYX+?h^YialpLt literal 0 HcmV?d00001 From e60798da1198f009fdcb4426ae66af4441f1e3e9 Mon Sep 17 00:00:00 2001 From: Nick Sabinske Date: Fri, 31 Mar 2017 15:27:33 -0400 Subject: [PATCH 21/38] Update light.limitlessled.markdown (#2329) Addressing home-assistant/home-assistant#6382 For pull request https://github.com/quadportnick/home-assistant/commit/22c0787971c20a832a13a668dee38ff9b0c269a0 --- source/_components/light.limitlessled.markdown | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/_components/light.limitlessled.markdown b/source/_components/light.limitlessled.markdown index 400a4c64d69..114da888784 100644 --- a/source/_components/light.limitlessled.markdown +++ b/source/_components/light.limitlessled.markdown @@ -35,10 +35,12 @@ light: type: rgbw name: Bathroom - host: 192.168.1.11 - bridge_led: True groups: - number: 1 name: Living Room & Hall + - number: 1 + type: bridge-led + name: Bridge Light ``` Configuration variables: @@ -47,11 +49,10 @@ Configuration variables: - **host** (*Required*): IP address of the device, eg. `192.168.1.32` - **version** (*Optional*): Bridge version (default is `6`). Don't use if you aren't sure. - **port** (*Optional*): Bridge port. Defaults to 5987. - - **bridge_led** (*Optional*): If True, the bridge led can be controlled. (Only supported for newer bridges with integrated led) - **groups** array (*Required*): The list of available groups. - - **number** (*Required*): Group number (`1`-`4`). Corresponds to the group number on the remote. + - **number** (*Required*): Group number (`1`-`4`). Corresponds to the group number on the remote. These numbers may overlap only if the type is different. - **name** (*Required*): Any name you'd like. Must be unique among all configured groups. - - **type** (*Optional*): Type of group. Choose either `rgbww`, `rgbw` or `white`. `rgbw` is the default if you don't specify this entry. + - **type** (*Optional*): Type of group. Choose either `rgbww`, `rgbw`, `white`, or `bridge-led`. `rgbw` is the default if you don't specify this entry. Use `bridge-led` to control the built-in LED of newer WiFi bridges. ### {% linkable_title Properties %} From 28c12b7438f0810ee4dea35518c2b6c3ccdbba40 Mon Sep 17 00:00:00 2001 From: Dan Ports Date: Fri, 31 Mar 2017 12:28:31 -0700 Subject: [PATCH 22/38] Add documentation for Lyft sensor (#2304) --- source/_components/sensor.lyft.markdown | 61 ++++++++++++++++++++++++ source/images/supported_brands/lyft.png | Bin 0 -> 36518 bytes 2 files changed, 61 insertions(+) create mode 100644 source/_components/sensor.lyft.markdown create mode 100644 source/images/supported_brands/lyft.png diff --git a/source/_components/sensor.lyft.markdown b/source/_components/sensor.lyft.markdown new file mode 100644 index 00000000000..a54970ed890 --- /dev/null +++ b/source/_components/sensor.lyft.markdown @@ -0,0 +1,61 @@ +--- +layout: page +title: "Lyft" +description: "How to integrate Lyft in Home Assistant" +date: 2017-03-19 21:05 +sidebar: true +comments: false +sharing: true +footer: true +logo: lyft.png +ha_category: Transport +ha_iot_class: "Cloud Polling" +ha_release: 0.41 +--- + + +The `lyft` sensor will give you time and price estimates for all available [Lyft](https://lyft.com) products at the given `start_latitude` and `start_longitude`.The `ATTRIBUTES` are used to provide extra information about products, such as vehicle capacity and fare rates. If an `end_latitude` and `end_longitude` are specified, a price estimate will also be provided. One sensor will be created for each product at the given `start` location, for pickup time. A second sensor for each product, for estimated price, will be created if a destination is specified. The sensor is powered by the official Lyft [API](https://developer.lyft.com/reference/). + + +You must create an application [here](https://www.lyft.com/developers/manage) to obtain a `client_id` and `client_secret`. + +To enable this sensor, add the following lines to your `configuration.yaml` file: + +```yaml +# Example configuration.yaml entry +sensor: + - platform: lyft + client_id: [...] + client_secret: [...] + start_latitude: 37.8116380 + start_longitude: -122.2648050 + end_latitude: 37.615223 + end_longitude: -122.389977 +``` + +Configuration variables: + +- **client_id** (*Required*): A client id obtained from [developer.lyft.com](https://developer.lyft.com) after [creating an app](https://www.lyft.com/developers/manage). +- **client_secret** (*Required*) A client secret obtained from [developer.lyft.com](https://developer.lyft.com) after [creating an app](https://www.lyft.com/developers/manage). +- **start_latitude** (*Required*): The starting latitude for a trip. +- **start_longitude** (*Required*): The starting longitude for a trip. +- **end_latitude** (*Optional*): The ending latitude for a trip. While `end_latitude` is optional, providing an `end_latitude`/`end_longitude` allows price estimates as well as time. +- **end_longitude** (*Optional*): The ending longitude for a trip. While `end_longitude` is optional, providing an `end_latitude`/`end_longitude` allows price estimates as well as time. +- **product_ids** (*Optional*): A list of Lyft product IDs. + +A full configuration entry could look like the sample below: + +```yaml +# Example configuration.yaml entry +sensor: + - platform: lyft + client_id: [...] + client_secret: [...] + start_latitude: 37.8116380 + start_longitude: -122.2648050 + end_latitude: 37.615223 + end_longitude: -122.389977 + product_ids: + - 'lyft' + - 'lyft_plus' +``` diff --git a/source/images/supported_brands/lyft.png b/source/images/supported_brands/lyft.png new file mode 100644 index 0000000000000000000000000000000000000000..b4fcb7367db5a1344c03c67faa2bee89535090f5 GIT binary patch literal 36518 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 bvZ2(@&#c;z;`ul94(maz{{9?o>p%Vvi22_6 literal 0 HcmV?d00001 From 8da09abe691acf9161eadbdc2a4f27ffa5278432 Mon Sep 17 00:00:00 2001 From: Marc Forth Date: Fri, 31 Mar 2017 21:24:52 +0100 Subject: [PATCH 23/38] Added SSL guide to cookbook (#2269) * Screenshot for SSL_guide * SSL Guide 2 files - SSL guide and a screenshot The SSL guide is a comprehensive guide for the novice to get an external connection with SSL certificate and auto-renews where possible, with various notes for other eventualities. * Update SSL guide.md Additions and corrections. --- source/_cookbook/SSL guide.md | 575 +++++++++++++++++++++++++++ source/images/screenshots/ip-set.jpg | Bin 0 -> 93489 bytes 2 files changed, 575 insertions(+) create mode 100644 source/_cookbook/SSL guide.md create mode 100644 source/images/screenshots/ip-set.jpg diff --git a/source/_cookbook/SSL guide.md b/source/_cookbook/SSL guide.md new file mode 100644 index 00000000000..7d6a304a6f6 --- /dev/null +++ b/source/_cookbook/SSL guide.md @@ -0,0 +1,575 @@ +--- +layout: page +title: "Remote Access with SSL via LetsEncrypt" +description: "A guide to remotely accessing HA and securing the connection with an SSL certificate from LetsEncrypt" +date: 2017-03-16 17:00 +sidebar: true +comments: false +sharing: true +footer: true +ha_category: Infrastructure +--- + +

+Before exposing your HA instance to the outside world it is ESSENTIAL that you have set a password following the advice on the [http](https://home-assistant.io/docs/configuration/basic/) page. +

+ + +This guide was added by mf_social on 16/03/2017 and was valid at the time of writing. This guide makes the following assumptions: + + * You can access your HA instance across your local network, and access the device that it is on via SSH from your local network. + * You know the internal IP address of your router and can access your router's configuration pages. + * You have already set up a password for your HA instance, following the advice on this page: [http](https://home-assistant.io/docs/configuration/basic/) + * You want to access your HA instance when you are away from home (ie, not connected to your local network) and secure it with an SSL certificate. + * You have a basic understanding of the phrases I have used so far. + * You are not currently running anything on port 80 on your network (you'd know if you were). + * If you are not using HA on a debian/raspian/hassbian system you will be able to convert any of the terminology I use in to the correct syntax for your system. + * You understand that this is a 'guide' covering the general application of these things to the general masses and there are things outside of the scope of it, and it does not cover every eventuality (although I have made some notes where people may stumble). Also, I have used some turns of phrase to make it easier to understand for the novice reader which people of advanced knowledge may say is innacurate. My goal here is to get you through this guide with a satisfactory outcome and have a decent understanding of what you are doing and why, not to teach you advanced internet communication protocols. + * Each step presumes you have fully completed the previous step succesfully, so if you did an earlier step following a different guide, please ensure that you have not missed anything out that may affect the step you have jumped to, and ensure that you adapt any commands to take in to account different file placements from other guides. + +Steps we will take: + +0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding +1 - Set your device to have a static IP address +2 - Set up port forwarding without SSL and test connection +3 - Set up a DuckDNS account +4 - Obtain an ssl certificate from LetsEncrypt +5 - Check the incoming conection +6 - Clean up port forwards +7 - Set up a sensor to monitor the expiry date of the certificate +8 - Set up an automatic renewal of the SSL certificate. +9 - Set up an alert to warn us if something went wrong. + +#### {% linkable_title 0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding %} + +An IP address is a bit like a phone number. When you access your HA instance you type something similar to 192.168.0.200:8123 in to your address bar of your browser. The bit before the colon is the IP address (in this case 192.168.0.200) and the bit after is the port number (in this case 8123). When you SSH in to the device running HA you will use the same IP address, and you will use port 22. You may not be aware that you are using port 22, but if you are using Putty look in the box next to where you type the IP address, you will see that it has already selected port 22 for you. + +So, if an IP address is like a phone number, a port number is like an extension number. An analogy would be if you phone your local doctors on 192-1680-200 and the receptionist answers, you ask to speak to Dr Smith and she will put you through to extension 8123, which is the phone Dr Smith is sitting at. The doctors surgery is the device your HA is running on, Dr Smith is your HA. Thusly, your HA instance is 'waiting for your call' on port 8123, at the device IP 192.168.0.200 . + +Now, to speak to the outside world your connection goes through a router. Your router will have two IP addresses. One is the internal network number, most likely 192.168.0.1 in my example, and an external IP address that incoming traffic is sent to. In the example of calling the doctors, the external IP is your telephone number's area code. + +So, when we want to connect to our HA instance from outside our network we will need to call the correct extension number, at the correct phone number, in the correct area code. + +We will be looking for a system to run like this (in this example I will pretend our exernal IP is 12.12.12.12): + +```text +Outside world -> 12.12.12.12:8123 -> your router -> 192.168.0.200:8123 +``` +Sounds simple? It really is except for two small, but easy to overcome, complications: + + * IP addresses are often dynamically allocated, so they can change. + * Because of the way the internet works you cannot chain IP addresses together to get from where you are, to where you want to go. + +To get around the issue of changing IP addresses we must remember that there are two IP addresses affected. Your external one (which we will 'call' to get on to your network from the internet) and your internal one (192.168.0.200 in the example I am currently using). + +So, we can use a static IP to ensure that whenever our device running HA connects to our router it always uses the same address. This way our internal IP never changes. This is covered in step 1 below. + +We then have no control over our external IP, as our Service Provider will give us a new one at random intervals. To fix this we will use a service called DuckDNS which will give us a name for our connection (something like examplehome.duckdns.org) and behind the scenes will continue to update your external IP. So no matter how many times the IP address changes, typing examplehome.duckdns.org in to our browser will convert to the correct, up-to-date, IP address. This is covered in step 3 below. + +To get around the issue of not being able to chain the IP addresses together (I can't say I want to call 12:12:12:12 and be put through to 192.168.0.200, and then be put through to extension 8123) we use port forwarding. Port forwarding is the process of telling your router which device to allow the outside connection to speak to. In the doctors surgery example, port forwarding is the receptionist. This takes a call from outside, and forwards it to the correct extension number inside. It is important to note that port forwarding can forward an incoming request for one port to a different port on your internal network if you so choose, and we wil be doing this later on. The end result being that when we have our SSL certificate our incoming call will be requesting port 443 (because that is the SSL port, like the SSH port is always 22), but our port forwarding rule will forward this to our HA instance on port 8123. When this guide is completed we will run something like this: + +```text +Outside world -> https://examplehome.duckdns.org -> 12.12.12.12:443 -> your router -> 192.168.0.200:8123 +``` +So, let's make it happen... + +#### {% linkable_title 1 - set your device to have a static IP address %} + +Whenever a device is connected to a network it has an IP address. This IP address is often dynamically assigned to the device on connection. This means there are occasions where the IP address you use to access HA, or SSH in to the device running HA, may change. Setting a static IP address means that the device will always be on the same address. + +SSH in to your system running HA and login. + +Type the following command to list your network interfaces: + +```bash +$ ifconfig +``` + +You will receive an ouput similar to the image here... + +![alt tag](https://github.com/home-assistant/home-assistant.github.io/tree/current/source/images/screenshots/ip-set.jpg) + +Make a note of the interface name and the IP address you are currently on. (In the picture it is the wireless connection that is highlighted, but with your setup it may be the wired one (eth0 or similar), make sure you get the correct information. + +Then type the following command to open the text file that controls your network connection: + +```bash +$ sudo nano /etc/dhcpcd.conf +``` + +At the bottom of the file add the following lines: + +```text +interface wlan0 <----- or the interface you just wrote down. + +static ip_address=192.168.0.200/24 <---- the IP address you just wrote down with a '/24' at the end +static routers=192.168.0.1 <---- Your router's IP address +static domain_name_servers=192.168.0.1 <---- Your router's IP address +``` + +It is important to note that the first three bits of your static IP address and your router's IP address should be the same, eg: + +```text +Router: 192.168.0.1 + +Yes +HA IP: 192.168.0.200 + +No +HA IP: 192.175.96.200 +``` + +Press Ctrl + x to close the editor, pressing Y to save the changes when prompted + +Reboot your pi: + +```bash +$ sudo reboot +``` + +When it comes back up check that you can SSH in to it again on the IP address you wrote down. + +Make sure HA is running and access it via the local network by typing the IP address and port number in to the browser: + +```text +http://192.168.0.200:8123. +``` + +All working? Hooray! You now have a static IP. This will now always be your internal IP address for your HA device. This will be known as YOUR-HA-IP for the rest of this guide. + + + +#### {% linkable_title 2 - set up port forwarding without SSL and test connection %} + +Log in to your router's configuration pages and find the port forwarding options. This bit is hard to write a guide for because each router has a different way of presenting these options. Searching google for "port forwarding" and the name of your router may help. When you find it you will likely have options similar to: + +Service name - Port Range - Local IP - Local Port - Protocol + +You may also have other options (like 'source IP'), these can usually be left blank or in their default state. + +Set the port forwarding to: + +```text +Service name - ha_test +Port Range - 8123 +Local IP - YOUR-HA-IP +Local Port - 8123 +Protocol - Both +``` + +Then save the change. On my router you have to fill these values in, then press an 'add' button to add the new rule to the list, then save the changes. All routers have a different interface, but you must ensure that these rules are saved at this point. If you are unsure, you can reboot the router and log back in, if the rule is present it was saved, if not, it wasn't! + +Once you have saved this rule, go to your browser, and go to: + +```text +https://whatismyipaddress.com/ +``` + +This will tell you your current external IP address + +Type the external IP address in to the url bar with http:// in front and :8123 after like so (12.12.12.12 is my example!): + +```text +http://12.12.12.12:8123 +``` + +Can you see your HA instance? Awesome! If not, your router may not support ' loopback' - try the next step anyway and if that works, and this one still doesn't, just remember that you cannot use loopback, so will have to use internal addresses when you're on your home network. More on this later on if it's relevant to you. + +Just to verify this isn't some kind of witchcraft that is actually using your internal network, pick up your phone, disconnect it from your wifi so that you are on your mobile data and not connected to the home network, put the same url in the browser on your phone. + +Can you see it now, from a device that is definitely not connected to your local network? Excellent! You now have a remotely accesible HA instance. + +But what if your external IP changes? Plus, remembering all those numbers is pretty hard, isn't it? Read on to get yourself set up with a word-based URL at DuckDNS that will track any changes to your IP address so you don't have to stress anymore... + +#### {% linkable_title 3 - Set up a DuckDNS account %} + +Open your browser and go to duckdns.org. + +Sign in and create an account using one of the id validation options in the top right corner. + +In the domains section pick a name for your subdomain, this can be anything you like, and click add domain. + +The URL you will be using later to access your HA instance from outside will be the subdomain you picked, followed by duckdns.org . For our example we will say our URL is examplehome.duckdns.org + +On the top left of duckdns.org select the install option. Then pick your operating system from the list. In our example we will use a raspberry pi. In the dropdown box select the url you just created. + +Duckdns.org will now generate personalised instructions for you to follow so that your device can update their website every time your IP address changes. Carefully follow the instructions given on duckdns.org to set up your device. + +At the end of the instructions DuckDNS will suggest you set up port forwarding. No need, we have already done this in step 2. + +What you have now done is set up DuckDNS so that whenever you type examplehome.duckdns.org in to your browser it will convert that to your router's external IP address. Your external IP address will always be up to date because your device running HA will update DuckDNS every time it changes. + +Now type your new URL in to your address bar on your browser with port 8123 on the end: + +```text +http://examplehome.duckdns.org:8123 +``` + +What now happens behind the scenes is this: + +- DuckDNS receives the request and forwards the request to your router's external IP address (which has been kept up to date by your device running HA) +- Your router receives the request on port 8123 and checks the port forwarding rules +- It finds the rule you created in step 2 and forwards the request to your HA instance +- Your browser displays your HA instance frontend. + +Did it work? Super! + +You now have a remotely accesible HA instance that has a text-based URL and will not drop out if your service provider changes your IP. But, it is only as secure as the password you set, which can be snooped during your session by a malicious hacker with relative ease. So we need to set up some encryption with SSL, read on to find out how. + +#### {% linkable_title 4 - Obtain an ssl certificate from LetsEncrypt %} + +First we need to set up another port forward like we did in step 2. Set your new rule to: + +```text +Service name - ha_letsencrypt +Port Range - 80 +Local IP - YOUR-HA-IP +Local Port - 80 +Protocol - Both +``` + +Remember to save the new rule. + +

+In cases where your ISP blocks port 80 you will need to change the port forward options to forward port 443 from outside to port 443 on your HA device. Please note that this will limit your options for automatically renewing the certificate, but this is a limitation because of your ISP setup and there is not a lot we can do about it! +

+ +now SSH in to the device your HA is running on. + + +

+If you're running the 'standard' setup on a raspberry pi the chances are you just logged in as the 'pi' user. If not, you may have logged in as the HA user. There are commands below that require the HA user to be on the sudoers list. If you are not using the 'standard' pi setup it is presumed you will know how to get your HA user on the sudoers list before continuing. If you are running the 'standard' pi setup, from your 'pi' user issue the following command (where is the HA user): + +```bash +$ sudo adduser sudo +``` + +

+ +If you did not already log in as the user that currently runs HA, change to that user (usually hass or homeassistant - you may have used a command similar to this in the past): + +```bash +$ su -s /bin/bash hass +``` + +Make sure you are in the home directory for the HA user: + +```bash +$ cd +``` + +We will now make a directory for the certbot software, download it and give it the correct permissions: + +```text +$ mkdir certbot +$ cd certbot/ +$ wget https://dl.eff.org/certbot-auto +$ chmod a+x certbot-auto +``` + +Now we will run the certbot program to get our ssl certificate. You will need to include your email address and your duckDNS url in the appropriate places: + +```text +$ ./certbot-auto certonly --standalone --preferred-challenges http-01 --email your@email.address -d examplehome.duckdns.org +``` + +Once the program has run it will generate a certificate and other files and place them in a folder `/etc/letsencrypt/` . + +Confirm this file has been populated: + +```bash +$ ls /etc/letsencrypt/live/ +``` + +This should show a folder named exactly after your DuckDNS url. + +Our HA user needs access to files within the letsencrypt folder, so issue the following commands to change the permissions. + +```bash +$ sudo chmod 755 /etc/letsencrypt/live/ +$ sudo chmod 755 /etc/letsencrypt/archive/ +``` + +Did all of that go without a hitch? Wahoo! Your LetsEncrypt certificate is now ready to be used with home assistant. Move to step 5 to put it all together... + +#### {% linkable_title 5 - check the incoming conection %} + +

+Following on from Step 4 your SSH will still be in the certbot folder. If you edit your configuration files over SSH you will need to change to your homeassistant folder: + +```bash +$ cd ~/.homeassistant +``` + +If you use samba shares to edit your files you can exit your SSH now. +

+ +If during step 4 you had to use port 443 instead of port 80 to generate your certificate, you should delete that rule now. + +Go to your router's configuration pages and set up a new port forwarding rule, thus: + +```text +Service name - ha_ssl +Port Range - 443 +Local IP - YOUR-HA-IP +Local Port - 8123 +Protocol - Both +``` + +Remember to save the rule changes. + +Now edit your configuration.yaml file to reflect the SSL entries and your base URL (changing the examplehome subdomain to yours): + +```yaml +http: + api_password: YOUR_PASSWORD + ssl_certificate: /etc/letsencrypt/live/examplehome.duckdns.org/fullchain.pem + ssl_key: /etc/letsencrypt/live/examplehome.duckdns.org/privkey.pem + base_url: examplehome.duckdns.org +``` + +You may wish to set up other options for the http component at this point, these extra options are beyond the scope of this guide but can be found on the http component page here: [http](https://home-assistant.io/components/http/) + +Save the changes to configuration.yaml. Restart HA. + +In step 3 we accessed our HA from the outside world with our DuckDNS URL and our port number. We are going to use a slightly different URL this time. + +```text +https://examplehome.duckdns.org +``` + +Note the S after http, and that no port number is added. This is because https will use port 443 automatically, and we have already set up our port forward to redirect this request to our HA instance on port 8123. + +You should now be able to see your HA instance via your DuckDNS URL, and importantly note that your browser shows the connection as secure. + +You will now NO LONGER be able to access your HA via your old internal IP address in the way you previously have. Your default way to access your HA instance, even from inside your house, is to use your DuckDNS URL. + +In cases where you need to access via the local network only (which should be few and far between) you can access it with the following URL (note the added S after http): + +```text +https://YOUR-HA-IP:8123 +``` + +...and accepting the browsers warning that you are connecting to an insecure site. This warning occurs because your certificate expects your incoming connection to come via your DuckDNS URL. It does not mean that your device has suddenly become insecure. + +Some cases such as this are where your router does not allow 'loopback' or where there is a problem with incoming connections due to technical failure. In these cases you can still use your internal connection and ignore the warnings. + +If you were previously using a webapp on your phone/tablet to access your HA you should delete the old one and create a new one with the new address. The old one will no longer work as it is not keyed to your new, secure URL. Instructions for creating your new webapp can be found here: + +```text +https://home-assistant.io/docs/frontend/mobile/ +``` + +All done? Accessing your HA from across the world with your DuckDNS URL and a lovely secure logo on your browser? Ace! Now lets clean up our port forwards so that we are only exposing the parts of our network that are absolutely neccesary to the outside world.... + +#### {% linkable_title 6 - Clean up port forwards %} + +In step 2 we created a port forwarding rule called ha_test. This opens port 8123 to the world, and is no longer neccessary. + +Go to your router's configuration pages and delete the ha_test rule. + +You should now have two rules in relation to HA for your port forwards, named: + +```text +ha_ssl and ha_letsencrypt +``` + +If you have any more for HA you should delete them now. If you only have ha_ssl this is probably because during step 4 you had to use port 443 instead of port 80, so we deleted the rule during step 5. + +You are now part of one of two groups: + + * If you have BOTH rules you are able to set up auto renewals of you certificates. + * If you only have one, you will have to manually change the rule when you want to update your certificate, and then change it back afterwards. + +Please remember whether you are a ONE-RULE person or a BOTH-RULE person for step 8! + +LetsEncrypt certificates only last for 90 days. When they have less than 30 days left they can be renewed. Renewal is a simple process. + +Move on to step 7 to see how to monitor your certificates expiry date, and be ready to renew your certificate when the time comes... + +#### {% linkable_title 7 - Set up a sensor to monitor the expiry date of the certificate %} + +Setting a sensor to read the number of days left on your SSL certificate before it expires is not required, but it has the following advantages: + + * You can physically see how long you have left, pleasing your inner control freak + * You can set automations based on the number of days left + * You can set alerts to notify you if your certificate has not been renewed and is coming close to expiry. + * If you cannot set up automatic renewals due to your ISP blocking port 80, you will have timely reminders to complete the process manually. + +If you do not wish to set up a sensor you can skip straight to step 8 to learn how to update your certificates. + +The sensor will rely on a command line program that needs to be installed on your device running HA. SSH in to the device and run the following commands: + +```bash +$ sudo apt-get update +$ sudo apt-get install ssl-cert-check +``` + +

+In cases where, for whatever reason, apt-get installing is not appropriate for your installation you can fetch the ssl-cert-check script from `http://prefetch.net/code/ssl-cert-check` bearing in mind that you will have to modify the command in the sensor code below to run the script from wherever you put it, modify permission if neccessary and so on. +

+ +To set up a senor add the following to your configuration.yaml (remembering to correct the URL for your DuckDNS): + +```yaml +sensor: + - platform: command_line + name: SSL cert expiry + unit_of_measurement: days + scan_interval: 10800 + command: "ssl-cert-check -b -c /etc/letsencrypt/live/examplehome.duckdns.org/cert.pem | awk '{ print $NF }'" +``` + +Save the configuration.yaml. Restart HA. + +On your default_view you should now see a sensor badge containing your number of days until expiry. If you've been following this guide from the start and have not taken any breaks in between, this should be 89 or 90. The sensor will update every 3 hours. You can place this reading on a card using groups, or hide it using customize. These topics are outside of the scope of this guide, but information can be found on their respective components pages: [Group](https://home-assistant.io/components/group/) and [Customize](https://home-assistant.io/docs/configuration/customizing-devices/) + +Got your sensor up and running and where you want it? Top drawer! Nearly there, now move on to the final steps to ensure that you're never without a secure connection in the future. + +#### {% linkable_title 8 - Set up an automatic renewal of the SSL certificate. %} + +The certbot program we downloaded in step 4 contains a script that will renew your certificate. The script will only obtain a new certificate if the current one has less than 30 days left on it, so running the script more often than is actually needed will not cause any harm. + +If you are a ONE-RULE person (from step 6) you cannot 'automatically' renew your certificates because you will need to change your port forwarding rules before the renewal takes place, and change it back again afterwards. + +When you are within 30 days of your certificate's expiry date (you can use the sensor reading from step 7 to tell you this) you will need to complete the following steps: + + * Go to your router's configuration pages and edit your port forwarding rule to + +```text +Service name - ha_ssl +Port Range - 443 +Local IP - YOUR-HA-IP +Local Port - 443 +Protocol - Both +``` + + * Save the rule + * SSH in to your device running HA. + * Change to your HA user (command similar to): + +```bash +$ su - s /bin/bash hass +``` + + * Change to your certbot folder + +```bash +$ cd ~/certbot/ +``` + + * Run the renewal command + +```bash +$ ./certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 +``` + + * Once succesfully completed, change your port forwarding rule back to + +```text +Service name - ha_ssl +Port Range - 443 +Local IP - YOUR-HA-IP +Local Port - 8123 +Protocol - Both +``` + + * Save the rule + + + +If you are a BOTH-RULE person, you have a number of options at this point. + +#######Option 1: +Your certificate can be renewed as a 'cron job' - cron jobs are background tasks run by the computer at specified intervals (and are totally independant of HA). Defining cron is outside of the scope of this guide but you will have had dealings with crontab when setting up DuckDNS in step 3 + +To set a cron job to run the script at regular intervals: + + * SSH in to your device running HA. + * Change to your HA user (command similar to_: + +```bash +$ su - s /bin/bash hass +``` + + * Open the crontab: + +```bash +$ crontab -e +``` + + * Scroll to the bottom of the file and paste in the following line + +```text +30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log +``` + * Save the file and exit + + +#######Option 2: +You can set an automation in HA to run the certbot renewal script. + +Add the following sections to your configuration.yaml + +```yaml +shell_command: + renew_ssl: ./certbot/certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 + +automation + - alias: 'Auto Renew SSL Cert' + trigger: + platform: numeric_state + entity_id: sensor.ssl_cert_expiry + below: 29 + action: + service: shell_command.renew_ssl +``` + +#######Option 3: +You can manually update the certificate when your certificate is less than 30 days to expiry. + +To manually update: + + * SSH in to your device running HA. + * Change to your HA user (command similar to_: + +```bash +$ su - s /bin/bash hass +``` + + * Change to your certbot folder + +```bash +$ cd ~/certbot/ +``` + + * Run the renewal command + +```bash +$ ./certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 +``` + +So, now were all set up. We have our secured, remotely accesible HA instance and we're on track for keeping our certificates up to date. But what if something goes wrong? What if the automation didn't fire? What if the cron job forgot to run? What if the dog ate my homework? Read on to set up an alert so you can be notified in plenty of time if you need to step in and sort out any failures... + +#### {% linkable_title 9 - Set up an alert to warn us if something went wrong. %} + +We set up our automatic renewal of our certificates and whatever method we used the certificate should be renewed on or around 30 days before it expires. But what if a week later it still hasn't been? This alert will go off if the expiry time on the certificate gets down to 21 days. This will give you 3 weeks to fix the problem, get your new certificate installed and get another 90 days of secure HA connections in play. + +In your configuration.yaml add the following automation, adding your preferred notification platform where appropriate: + +```yaml +automation: + - alias: 'SSL expiry notification' + trigger: + platform: numeric_state + entity_id: sensor.ssl_cert_expiry + below: 21 + action: + service: notify.[your_notification_preference] + data: + message: 'Warning - SSL certificate expires in 21 days and has not been automatically renewed' +``` + +If you receive this warning notification, follow the steps for a manual update from step 8. Any error messages received at that point can be googled and resolved. If the manual update goes without a hitch there may be something wrong with your chosen method for automatic updates, and you can start troubleshooting from there. + +So, that's it. We've taken a HA instance that was only reachable on the local network, made it accessible from the internet, secured it, and set up a system to ensure that it always stays secure. Well done, go and treat yourself to a cookie! diff --git a/source/images/screenshots/ip-set.jpg b/source/images/screenshots/ip-set.jpg new file mode 100644 index 0000000000000000000000000000000000000000..78dd64b119d87fff0345112d5d66ebe695406d30 GIT binary patch literal 93489 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
rcO5DkDrDUsE?la*i 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 literal 0 HcmV?d00001 From 72d5b67b240b16ea7da57cf99594f1747e816e4e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 31 Mar 2017 22:29:26 +0200 Subject: [PATCH 24/38] Fix file name and location --- .../ecosystem/certificates/lets_encrypt.markdown} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename source/{_cookbook/SSL guide.md => _docs/ecosystem/certificates/lets_encrypt.markdown} (100%) diff --git a/source/_cookbook/SSL guide.md b/source/_docs/ecosystem/certificates/lets_encrypt.markdown similarity index 100% rename from source/_cookbook/SSL guide.md rename to source/_docs/ecosystem/certificates/lets_encrypt.markdown From 4eb8f9a142119480f0694a21e63d4a9f0f818c9e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 31 Mar 2017 22:56:42 +0200 Subject: [PATCH 25/38] Format and style, add to menu --- .../certificates/lets_encrypt.markdown | 1144 ++++++++--------- source/_includes/asides/docs_navigation.html | 1 + 2 files changed, 570 insertions(+), 575 deletions(-) diff --git a/source/_docs/ecosystem/certificates/lets_encrypt.markdown b/source/_docs/ecosystem/certificates/lets_encrypt.markdown index 7d6a304a6f6..aaac97c67ea 100644 --- a/source/_docs/ecosystem/certificates/lets_encrypt.markdown +++ b/source/_docs/ecosystem/certificates/lets_encrypt.markdown @@ -1,575 +1,569 @@ ---- -layout: page -title: "Remote Access with SSL via LetsEncrypt" -description: "A guide to remotely accessing HA and securing the connection with an SSL certificate from LetsEncrypt" -date: 2017-03-16 17:00 -sidebar: true -comments: false -sharing: true -footer: true -ha_category: Infrastructure ---- - -

-Before exposing your HA instance to the outside world it is ESSENTIAL that you have set a password following the advice on the [http](https://home-assistant.io/docs/configuration/basic/) page. -

- - -This guide was added by mf_social on 16/03/2017 and was valid at the time of writing. This guide makes the following assumptions: - - * You can access your HA instance across your local network, and access the device that it is on via SSH from your local network. - * You know the internal IP address of your router and can access your router's configuration pages. - * You have already set up a password for your HA instance, following the advice on this page: [http](https://home-assistant.io/docs/configuration/basic/) - * You want to access your HA instance when you are away from home (ie, not connected to your local network) and secure it with an SSL certificate. - * You have a basic understanding of the phrases I have used so far. - * You are not currently running anything on port 80 on your network (you'd know if you were). - * If you are not using HA on a debian/raspian/hassbian system you will be able to convert any of the terminology I use in to the correct syntax for your system. - * You understand that this is a 'guide' covering the general application of these things to the general masses and there are things outside of the scope of it, and it does not cover every eventuality (although I have made some notes where people may stumble). Also, I have used some turns of phrase to make it easier to understand for the novice reader which people of advanced knowledge may say is innacurate. My goal here is to get you through this guide with a satisfactory outcome and have a decent understanding of what you are doing and why, not to teach you advanced internet communication protocols. - * Each step presumes you have fully completed the previous step succesfully, so if you did an earlier step following a different guide, please ensure that you have not missed anything out that may affect the step you have jumped to, and ensure that you adapt any commands to take in to account different file placements from other guides. - -Steps we will take: - -0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding -1 - Set your device to have a static IP address -2 - Set up port forwarding without SSL and test connection -3 - Set up a DuckDNS account -4 - Obtain an ssl certificate from LetsEncrypt -5 - Check the incoming conection -6 - Clean up port forwards -7 - Set up a sensor to monitor the expiry date of the certificate -8 - Set up an automatic renewal of the SSL certificate. -9 - Set up an alert to warn us if something went wrong. - -#### {% linkable_title 0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding %} - -An IP address is a bit like a phone number. When you access your HA instance you type something similar to 192.168.0.200:8123 in to your address bar of your browser. The bit before the colon is the IP address (in this case 192.168.0.200) and the bit after is the port number (in this case 8123). When you SSH in to the device running HA you will use the same IP address, and you will use port 22. You may not be aware that you are using port 22, but if you are using Putty look in the box next to where you type the IP address, you will see that it has already selected port 22 for you. - -So, if an IP address is like a phone number, a port number is like an extension number. An analogy would be if you phone your local doctors on 192-1680-200 and the receptionist answers, you ask to speak to Dr Smith and she will put you through to extension 8123, which is the phone Dr Smith is sitting at. The doctors surgery is the device your HA is running on, Dr Smith is your HA. Thusly, your HA instance is 'waiting for your call' on port 8123, at the device IP 192.168.0.200 . - -Now, to speak to the outside world your connection goes through a router. Your router will have two IP addresses. One is the internal network number, most likely 192.168.0.1 in my example, and an external IP address that incoming traffic is sent to. In the example of calling the doctors, the external IP is your telephone number's area code. - -So, when we want to connect to our HA instance from outside our network we will need to call the correct extension number, at the correct phone number, in the correct area code. - -We will be looking for a system to run like this (in this example I will pretend our exernal IP is 12.12.12.12): - -```text -Outside world -> 12.12.12.12:8123 -> your router -> 192.168.0.200:8123 -``` -Sounds simple? It really is except for two small, but easy to overcome, complications: - - * IP addresses are often dynamically allocated, so they can change. - * Because of the way the internet works you cannot chain IP addresses together to get from where you are, to where you want to go. - -To get around the issue of changing IP addresses we must remember that there are two IP addresses affected. Your external one (which we will 'call' to get on to your network from the internet) and your internal one (192.168.0.200 in the example I am currently using). - -So, we can use a static IP to ensure that whenever our device running HA connects to our router it always uses the same address. This way our internal IP never changes. This is covered in step 1 below. - -We then have no control over our external IP, as our Service Provider will give us a new one at random intervals. To fix this we will use a service called DuckDNS which will give us a name for our connection (something like examplehome.duckdns.org) and behind the scenes will continue to update your external IP. So no matter how many times the IP address changes, typing examplehome.duckdns.org in to our browser will convert to the correct, up-to-date, IP address. This is covered in step 3 below. - -To get around the issue of not being able to chain the IP addresses together (I can't say I want to call 12:12:12:12 and be put through to 192.168.0.200, and then be put through to extension 8123) we use port forwarding. Port forwarding is the process of telling your router which device to allow the outside connection to speak to. In the doctors surgery example, port forwarding is the receptionist. This takes a call from outside, and forwards it to the correct extension number inside. It is important to note that port forwarding can forward an incoming request for one port to a different port on your internal network if you so choose, and we wil be doing this later on. The end result being that when we have our SSL certificate our incoming call will be requesting port 443 (because that is the SSL port, like the SSH port is always 22), but our port forwarding rule will forward this to our HA instance on port 8123. When this guide is completed we will run something like this: - -```text -Outside world -> https://examplehome.duckdns.org -> 12.12.12.12:443 -> your router -> 192.168.0.200:8123 -``` -So, let's make it happen... - -#### {% linkable_title 1 - set your device to have a static IP address %} - -Whenever a device is connected to a network it has an IP address. This IP address is often dynamically assigned to the device on connection. This means there are occasions where the IP address you use to access HA, or SSH in to the device running HA, may change. Setting a static IP address means that the device will always be on the same address. - -SSH in to your system running HA and login. - -Type the following command to list your network interfaces: - -```bash -$ ifconfig -``` - -You will receive an ouput similar to the image here... - -![alt tag](https://github.com/home-assistant/home-assistant.github.io/tree/current/source/images/screenshots/ip-set.jpg) - -Make a note of the interface name and the IP address you are currently on. (In the picture it is the wireless connection that is highlighted, but with your setup it may be the wired one (eth0 or similar), make sure you get the correct information. - -Then type the following command to open the text file that controls your network connection: - -```bash -$ sudo nano /etc/dhcpcd.conf -``` - -At the bottom of the file add the following lines: - -```text -interface wlan0 <----- or the interface you just wrote down. - -static ip_address=192.168.0.200/24 <---- the IP address you just wrote down with a '/24' at the end -static routers=192.168.0.1 <---- Your router's IP address -static domain_name_servers=192.168.0.1 <---- Your router's IP address -``` - -It is important to note that the first three bits of your static IP address and your router's IP address should be the same, eg: - -```text -Router: 192.168.0.1 - -Yes -HA IP: 192.168.0.200 - -No -HA IP: 192.175.96.200 -``` - -Press Ctrl + x to close the editor, pressing Y to save the changes when prompted - -Reboot your pi: - -```bash -$ sudo reboot -``` - -When it comes back up check that you can SSH in to it again on the IP address you wrote down. - -Make sure HA is running and access it via the local network by typing the IP address and port number in to the browser: - -```text -http://192.168.0.200:8123. -``` - -All working? Hooray! You now have a static IP. This will now always be your internal IP address for your HA device. This will be known as YOUR-HA-IP for the rest of this guide. - - - -#### {% linkable_title 2 - set up port forwarding without SSL and test connection %} - -Log in to your router's configuration pages and find the port forwarding options. This bit is hard to write a guide for because each router has a different way of presenting these options. Searching google for "port forwarding" and the name of your router may help. When you find it you will likely have options similar to: - -Service name - Port Range - Local IP - Local Port - Protocol - -You may also have other options (like 'source IP'), these can usually be left blank or in their default state. - -Set the port forwarding to: - -```text -Service name - ha_test -Port Range - 8123 -Local IP - YOUR-HA-IP -Local Port - 8123 -Protocol - Both -``` - -Then save the change. On my router you have to fill these values in, then press an 'add' button to add the new rule to the list, then save the changes. All routers have a different interface, but you must ensure that these rules are saved at this point. If you are unsure, you can reboot the router and log back in, if the rule is present it was saved, if not, it wasn't! - -Once you have saved this rule, go to your browser, and go to: - -```text -https://whatismyipaddress.com/ -``` - -This will tell you your current external IP address - -Type the external IP address in to the url bar with http:// in front and :8123 after like so (12.12.12.12 is my example!): - -```text -http://12.12.12.12:8123 -``` - -Can you see your HA instance? Awesome! If not, your router may not support ' loopback' - try the next step anyway and if that works, and this one still doesn't, just remember that you cannot use loopback, so will have to use internal addresses when you're on your home network. More on this later on if it's relevant to you. - -Just to verify this isn't some kind of witchcraft that is actually using your internal network, pick up your phone, disconnect it from your wifi so that you are on your mobile data and not connected to the home network, put the same url in the browser on your phone. - -Can you see it now, from a device that is definitely not connected to your local network? Excellent! You now have a remotely accesible HA instance. - -But what if your external IP changes? Plus, remembering all those numbers is pretty hard, isn't it? Read on to get yourself set up with a word-based URL at DuckDNS that will track any changes to your IP address so you don't have to stress anymore... - -#### {% linkable_title 3 - Set up a DuckDNS account %} - -Open your browser and go to duckdns.org. - -Sign in and create an account using one of the id validation options in the top right corner. - -In the domains section pick a name for your subdomain, this can be anything you like, and click add domain. - -The URL you will be using later to access your HA instance from outside will be the subdomain you picked, followed by duckdns.org . For our example we will say our URL is examplehome.duckdns.org - -On the top left of duckdns.org select the install option. Then pick your operating system from the list. In our example we will use a raspberry pi. In the dropdown box select the url you just created. - -Duckdns.org will now generate personalised instructions for you to follow so that your device can update their website every time your IP address changes. Carefully follow the instructions given on duckdns.org to set up your device. - -At the end of the instructions DuckDNS will suggest you set up port forwarding. No need, we have already done this in step 2. - -What you have now done is set up DuckDNS so that whenever you type examplehome.duckdns.org in to your browser it will convert that to your router's external IP address. Your external IP address will always be up to date because your device running HA will update DuckDNS every time it changes. - -Now type your new URL in to your address bar on your browser with port 8123 on the end: - -```text -http://examplehome.duckdns.org:8123 -``` - -What now happens behind the scenes is this: - -- DuckDNS receives the request and forwards the request to your router's external IP address (which has been kept up to date by your device running HA) -- Your router receives the request on port 8123 and checks the port forwarding rules -- It finds the rule you created in step 2 and forwards the request to your HA instance -- Your browser displays your HA instance frontend. - -Did it work? Super! - -You now have a remotely accesible HA instance that has a text-based URL and will not drop out if your service provider changes your IP. But, it is only as secure as the password you set, which can be snooped during your session by a malicious hacker with relative ease. So we need to set up some encryption with SSL, read on to find out how. - -#### {% linkable_title 4 - Obtain an ssl certificate from LetsEncrypt %} - -First we need to set up another port forward like we did in step 2. Set your new rule to: - -```text -Service name - ha_letsencrypt -Port Range - 80 -Local IP - YOUR-HA-IP -Local Port - 80 -Protocol - Both -``` - -Remember to save the new rule. - -

-In cases where your ISP blocks port 80 you will need to change the port forward options to forward port 443 from outside to port 443 on your HA device. Please note that this will limit your options for automatically renewing the certificate, but this is a limitation because of your ISP setup and there is not a lot we can do about it! -

- -now SSH in to the device your HA is running on. - - -

-If you're running the 'standard' setup on a raspberry pi the chances are you just logged in as the 'pi' user. If not, you may have logged in as the HA user. There are commands below that require the HA user to be on the sudoers list. If you are not using the 'standard' pi setup it is presumed you will know how to get your HA user on the sudoers list before continuing. If you are running the 'standard' pi setup, from your 'pi' user issue the following command (where is the HA user): - -```bash -$ sudo adduser sudo -``` - -

- -If you did not already log in as the user that currently runs HA, change to that user (usually hass or homeassistant - you may have used a command similar to this in the past): - -```bash -$ su -s /bin/bash hass -``` - -Make sure you are in the home directory for the HA user: - -```bash -$ cd -``` - -We will now make a directory for the certbot software, download it and give it the correct permissions: - -```text -$ mkdir certbot -$ cd certbot/ -$ wget https://dl.eff.org/certbot-auto -$ chmod a+x certbot-auto -``` - -Now we will run the certbot program to get our ssl certificate. You will need to include your email address and your duckDNS url in the appropriate places: - -```text -$ ./certbot-auto certonly --standalone --preferred-challenges http-01 --email your@email.address -d examplehome.duckdns.org -``` - -Once the program has run it will generate a certificate and other files and place them in a folder `/etc/letsencrypt/` . - -Confirm this file has been populated: - -```bash -$ ls /etc/letsencrypt/live/ -``` - -This should show a folder named exactly after your DuckDNS url. - -Our HA user needs access to files within the letsencrypt folder, so issue the following commands to change the permissions. - -```bash -$ sudo chmod 755 /etc/letsencrypt/live/ -$ sudo chmod 755 /etc/letsencrypt/archive/ -``` - -Did all of that go without a hitch? Wahoo! Your LetsEncrypt certificate is now ready to be used with home assistant. Move to step 5 to put it all together... - -#### {% linkable_title 5 - check the incoming conection %} - -

-Following on from Step 4 your SSH will still be in the certbot folder. If you edit your configuration files over SSH you will need to change to your homeassistant folder: - -```bash -$ cd ~/.homeassistant -``` - -If you use samba shares to edit your files you can exit your SSH now. -

- -If during step 4 you had to use port 443 instead of port 80 to generate your certificate, you should delete that rule now. - -Go to your router's configuration pages and set up a new port forwarding rule, thus: - -```text -Service name - ha_ssl -Port Range - 443 -Local IP - YOUR-HA-IP -Local Port - 8123 -Protocol - Both -``` - -Remember to save the rule changes. - -Now edit your configuration.yaml file to reflect the SSL entries and your base URL (changing the examplehome subdomain to yours): - -```yaml -http: - api_password: YOUR_PASSWORD - ssl_certificate: /etc/letsencrypt/live/examplehome.duckdns.org/fullchain.pem - ssl_key: /etc/letsencrypt/live/examplehome.duckdns.org/privkey.pem - base_url: examplehome.duckdns.org -``` - -You may wish to set up other options for the http component at this point, these extra options are beyond the scope of this guide but can be found on the http component page here: [http](https://home-assistant.io/components/http/) - -Save the changes to configuration.yaml. Restart HA. - -In step 3 we accessed our HA from the outside world with our DuckDNS URL and our port number. We are going to use a slightly different URL this time. - -```text -https://examplehome.duckdns.org -``` - -Note the S after http, and that no port number is added. This is because https will use port 443 automatically, and we have already set up our port forward to redirect this request to our HA instance on port 8123. - -You should now be able to see your HA instance via your DuckDNS URL, and importantly note that your browser shows the connection as secure. - -You will now NO LONGER be able to access your HA via your old internal IP address in the way you previously have. Your default way to access your HA instance, even from inside your house, is to use your DuckDNS URL. - -In cases where you need to access via the local network only (which should be few and far between) you can access it with the following URL (note the added S after http): - -```text -https://YOUR-HA-IP:8123 -``` - -...and accepting the browsers warning that you are connecting to an insecure site. This warning occurs because your certificate expects your incoming connection to come via your DuckDNS URL. It does not mean that your device has suddenly become insecure. - -Some cases such as this are where your router does not allow 'loopback' or where there is a problem with incoming connections due to technical failure. In these cases you can still use your internal connection and ignore the warnings. - -If you were previously using a webapp on your phone/tablet to access your HA you should delete the old one and create a new one with the new address. The old one will no longer work as it is not keyed to your new, secure URL. Instructions for creating your new webapp can be found here: - -```text -https://home-assistant.io/docs/frontend/mobile/ -``` - -All done? Accessing your HA from across the world with your DuckDNS URL and a lovely secure logo on your browser? Ace! Now lets clean up our port forwards so that we are only exposing the parts of our network that are absolutely neccesary to the outside world.... - -#### {% linkable_title 6 - Clean up port forwards %} - -In step 2 we created a port forwarding rule called ha_test. This opens port 8123 to the world, and is no longer neccessary. - -Go to your router's configuration pages and delete the ha_test rule. - -You should now have two rules in relation to HA for your port forwards, named: - -```text -ha_ssl and ha_letsencrypt -``` - -If you have any more for HA you should delete them now. If you only have ha_ssl this is probably because during step 4 you had to use port 443 instead of port 80, so we deleted the rule during step 5. - -You are now part of one of two groups: - - * If you have BOTH rules you are able to set up auto renewals of you certificates. - * If you only have one, you will have to manually change the rule when you want to update your certificate, and then change it back afterwards. - -Please remember whether you are a ONE-RULE person or a BOTH-RULE person for step 8! - -LetsEncrypt certificates only last for 90 days. When they have less than 30 days left they can be renewed. Renewal is a simple process. - -Move on to step 7 to see how to monitor your certificates expiry date, and be ready to renew your certificate when the time comes... - -#### {% linkable_title 7 - Set up a sensor to monitor the expiry date of the certificate %} - -Setting a sensor to read the number of days left on your SSL certificate before it expires is not required, but it has the following advantages: - - * You can physically see how long you have left, pleasing your inner control freak - * You can set automations based on the number of days left - * You can set alerts to notify you if your certificate has not been renewed and is coming close to expiry. - * If you cannot set up automatic renewals due to your ISP blocking port 80, you will have timely reminders to complete the process manually. - -If you do not wish to set up a sensor you can skip straight to step 8 to learn how to update your certificates. - -The sensor will rely on a command line program that needs to be installed on your device running HA. SSH in to the device and run the following commands: - -```bash -$ sudo apt-get update -$ sudo apt-get install ssl-cert-check -``` - -

-In cases where, for whatever reason, apt-get installing is not appropriate for your installation you can fetch the ssl-cert-check script from `http://prefetch.net/code/ssl-cert-check` bearing in mind that you will have to modify the command in the sensor code below to run the script from wherever you put it, modify permission if neccessary and so on. -

- -To set up a senor add the following to your configuration.yaml (remembering to correct the URL for your DuckDNS): - -```yaml -sensor: - - platform: command_line - name: SSL cert expiry - unit_of_measurement: days - scan_interval: 10800 - command: "ssl-cert-check -b -c /etc/letsencrypt/live/examplehome.duckdns.org/cert.pem | awk '{ print $NF }'" -``` - -Save the configuration.yaml. Restart HA. - -On your default_view you should now see a sensor badge containing your number of days until expiry. If you've been following this guide from the start and have not taken any breaks in between, this should be 89 or 90. The sensor will update every 3 hours. You can place this reading on a card using groups, or hide it using customize. These topics are outside of the scope of this guide, but information can be found on their respective components pages: [Group](https://home-assistant.io/components/group/) and [Customize](https://home-assistant.io/docs/configuration/customizing-devices/) - -Got your sensor up and running and where you want it? Top drawer! Nearly there, now move on to the final steps to ensure that you're never without a secure connection in the future. - -#### {% linkable_title 8 - Set up an automatic renewal of the SSL certificate. %} - -The certbot program we downloaded in step 4 contains a script that will renew your certificate. The script will only obtain a new certificate if the current one has less than 30 days left on it, so running the script more often than is actually needed will not cause any harm. - -If you are a ONE-RULE person (from step 6) you cannot 'automatically' renew your certificates because you will need to change your port forwarding rules before the renewal takes place, and change it back again afterwards. - -When you are within 30 days of your certificate's expiry date (you can use the sensor reading from step 7 to tell you this) you will need to complete the following steps: - - * Go to your router's configuration pages and edit your port forwarding rule to - -```text -Service name - ha_ssl -Port Range - 443 -Local IP - YOUR-HA-IP -Local Port - 443 -Protocol - Both -``` - - * Save the rule - * SSH in to your device running HA. - * Change to your HA user (command similar to): - -```bash -$ su - s /bin/bash hass -``` - - * Change to your certbot folder - -```bash -$ cd ~/certbot/ -``` - - * Run the renewal command - -```bash -$ ./certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 -``` - - * Once succesfully completed, change your port forwarding rule back to - -```text -Service name - ha_ssl -Port Range - 443 -Local IP - YOUR-HA-IP -Local Port - 8123 -Protocol - Both -``` - - * Save the rule - - - -If you are a BOTH-RULE person, you have a number of options at this point. - -#######Option 1: -Your certificate can be renewed as a 'cron job' - cron jobs are background tasks run by the computer at specified intervals (and are totally independant of HA). Defining cron is outside of the scope of this guide but you will have had dealings with crontab when setting up DuckDNS in step 3 - -To set a cron job to run the script at regular intervals: - - * SSH in to your device running HA. - * Change to your HA user (command similar to_: - -```bash -$ su - s /bin/bash hass -``` - - * Open the crontab: - -```bash -$ crontab -e -``` - - * Scroll to the bottom of the file and paste in the following line - -```text -30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log -``` - * Save the file and exit - - -#######Option 2: -You can set an automation in HA to run the certbot renewal script. - -Add the following sections to your configuration.yaml - -```yaml -shell_command: - renew_ssl: ./certbot/certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 - -automation - - alias: 'Auto Renew SSL Cert' - trigger: - platform: numeric_state - entity_id: sensor.ssl_cert_expiry - below: 29 - action: - service: shell_command.renew_ssl -``` - -#######Option 3: -You can manually update the certificate when your certificate is less than 30 days to expiry. - -To manually update: - - * SSH in to your device running HA. - * Change to your HA user (command similar to_: - -```bash -$ su - s /bin/bash hass -``` - - * Change to your certbot folder - -```bash -$ cd ~/certbot/ -``` - - * Run the renewal command - -```bash -$ ./certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 -``` - -So, now were all set up. We have our secured, remotely accesible HA instance and we're on track for keeping our certificates up to date. But what if something goes wrong? What if the automation didn't fire? What if the cron job forgot to run? What if the dog ate my homework? Read on to set up an alert so you can be notified in plenty of time if you need to step in and sort out any failures... - -#### {% linkable_title 9 - Set up an alert to warn us if something went wrong. %} - -We set up our automatic renewal of our certificates and whatever method we used the certificate should be renewed on or around 30 days before it expires. But what if a week later it still hasn't been? This alert will go off if the expiry time on the certificate gets down to 21 days. This will give you 3 weeks to fix the problem, get your new certificate installed and get another 90 days of secure HA connections in play. - -In your configuration.yaml add the following automation, adding your preferred notification platform where appropriate: - -```yaml -automation: - - alias: 'SSL expiry notification' - trigger: - platform: numeric_state - entity_id: sensor.ssl_cert_expiry - below: 21 - action: - service: notify.[your_notification_preference] - data: - message: 'Warning - SSL certificate expires in 21 days and has not been automatically renewed' -``` - -If you receive this warning notification, follow the steps for a manual update from step 8. Any error messages received at that point can be googled and resolved. If the manual update goes without a hitch there may be something wrong with your chosen method for automatic updates, and you can start troubleshooting from there. - -So, that's it. We've taken a HA instance that was only reachable on the local network, made it accessible from the internet, secured it, and set up a system to ensure that it always stays secure. Well done, go and treat yourself to a cookie! +--- +layout: page +title: "Remote Access with TLS/SSL via Let's Encrypt" +description: "A guide to remotely accessing Home Assistant and securing the connection with an SSL certificate from Let's Encrypt" +date: 2017-03-16 17:00 +sidebar: true +comments: false +sharing: true +footer: true +--- + +

+Before exposing your Home Aassistant instance to the outside world it is ESSENTIAL that you have set a password following the advice on the [http](https://home-assistant.io/docs/configuration/basic/) page. +

+ + +This guide was added by mf_social on 16/03/2017 and was valid at the time of writing. This guide makes the following assumptions: + + * You can access your Home Assistant instance across your local network, and access the device that it is on via SSH from your local network. + * You know the internal IP address of your router and can access your router's configuration pages. + * You have already set up a password for your Home Assistant instance, following the advice on this page: [http](https://home-assistant.io/docs/configuration/basic/) + * You want to access your Home Assistant instance when you are away from home (ie, not connected to your local network) and secure it with an TLS/SSL certificate. + * You have a basic understanding of the phrases I have used so far. + * You are not currently running anything on port 80 on your network (you'd know if you were). + * If you are not using Home Assistant on a Debian/Raspian/Hassbian system you will be able to convert any of the terminology I use in to the correct syntax for your system. + * You understand that this is a 'guide' covering the general application of these things to the general masses and there are things outside of the scope of it, and it does not cover every eventuality (although I have made some notes where people may stumble). Also, I have used some turns of phrase to make it easier to understand for the novice reader which people of advanced knowledge may say is innacurate. My goal here is to get you through this guide with a satisfactory outcome and have a decent understanding of what you are doing and why, not to teach you advanced internet communication protocols. + * Each step presumes you have fully completed the previous step succesfully, so if you did an earlier step following a different guide, please ensure that you have not missed anything out that may affect the step you have jumped to, and ensure that you adapt any commands to take in to account different file placements from other guides. + +Steps we will take: + +0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding +1 - Set your device to have a static IP address +2 - Set up port forwarding without TLS/SSL and test connection +3 - Set up a DuckDNS account +4 - Obtain a TLS/SSL certificate from Let's Encrypt +5 - Check the incoming conection +6 - Clean up port forwards +7 - Set up a sensor to monitor the expiry date of the certificate +8 - Set up an automatic renewal of the TLS/SSL certificate +9 - Set up an alert to warn us if something went wrong + +### {% linkable_title 0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding %} + +An IP address is a bit like a phone number. When you access your Home Assistant instance you type something similar to 192.168.0.200:8123 in to your address bar of your browser. The bit before the colon is the IP address (in this case 192.168.0.200) and the bit after is the port number (in this case 8123). When you SSH in to the device running Home Assistant you will use the same IP address, and you will use port 22. You may not be aware that you are using port 22, but if you are using Putty look in the box next to where you type the IP address, you will see that it has already selected port 22 for you. + +So, if an IP address is like a phone number, a port number is like an extension number. An analogy would be if you phone your local doctors on 192-1680-200 and the receptionist answers, you ask to speak to Dr. Smith and she will put you through to extension 8123, which is the phone Dr. Smith is sitting at. The doctors surgery is the device your Home Assistant is running on, Dr. Smith is your Home Assistant. Thusly, your Home Assistant instance is 'waiting for your call' on port 8123, at the device IP 192.168.0.200 . + +Now, to speak to the outside world your connection goes through a router. Your router will have two IP addresses. One is the internal network number, most likely 192.168.0.1 in my example, and an external IP address that incoming traffic is sent to. In the example of calling the doctors, the external IP is your telephone number's area code. + +So, when we want to connect to our Home Assistant instance from outside our network we will need to call the correct extension number, at the correct phone number, in the correct area code. + +We will be looking for a system to run like this (in this example I will pretend our exernal IP is 12.12.12.12): + +```text +Outside world -> 12.12.12.12:8123 -> your router -> 192.168.0.200:8123 +``` +Sounds simple? It really is except for two small, but easy to overcome, complications: + + * IP addresses are often dynamically allocated, so they can change. + * Because of the way the internet works you cannot chain IP addresses together to get from where you are, to where you want to go. + +To get around the issue of changing IP addresses we must remember that there are two IP addresses affected. Your external one (which we will 'call' to get on to your network from the internet) and your internal one (192.168.0.200 in the example I am currently using). + +So, we can use a static IP to ensure that whenever our device running Home Assistant connects to our router it always uses the same address. This way our internal IP never changes. This is covered in step 1 below. + +We then have no control over our external IP, as our Service Provider will give us a new one at random intervals. To fix this we will use a service called DuckDNS which will give us a name for our connection (something like examplehome.duckdns.org) and behind the scenes will continue to update your external IP. So no matter how many times the IP address changes, typing examplehome.duckdns.org in to our browser will convert to the correct, up-to-date, IP address. This is covered in step 3 below. + +To get around the issue of not being able to chain the IP addresses together (I can't say I want to call 12:12:12:12 and be put through to 192.168.0.200, and then be put through to extension 8123) we use port forwarding. Port forwarding is the process of telling your router which device to allow the outside connection to speak to. In the doctors surgery example, port forwarding is the receptionist. This takes a call from outside, and forwards it to the correct extension number inside. It is important to note that port forwarding can forward an incoming request for one port to a different port on your internal network if you so choose, and we wil be doing this later on. The end result being that when we have our SSL certificate our incoming call will be requesting port 443 (because that is the SSL port, like the SSH port is always 22), but our port forwarding rule will forward this to our HA instance on port 8123. When this guide is completed we will run something like this: + +```text +Outside world -> https://examplehome.duckdns.org -> 12.12.12.12:443 -> your router -> 192.168.0.200:8123 +``` +So, let's make it happen... + +### {% linkable_title 1 - Set your device to have a static IP address %} + +Whenever a device is connected to a network it has an IP address. This IP address is often dynamically assigned to the device on connection. This means there are occasions where the IP address you use to access Home Assistant, or SSH in to the device running Home Assistant, may change. Setting a static IP address means that the device will always be on the same address. + +SSH in to your system running Home Assistant and login. + +Type the following command to list your network interfaces: + +```bash +$ ifconfig +``` + +You will receive an ouput similar to the image below: + +![alt tag](https://github.com/home-assistant/home-assistant.github.io/tree/current/source/images/screenshots/ip-set.jpg) + +Make a note of the interface name and the IP address you are currently on. In the picture it is the wireless connection that is highlighted, but with your setup it may be the wired one (eth0 or similar), make sure you get the correct information. + +Then type the following command to open the text file that controls your network connection: + +```bash +$ sudo nano /etc/dhcpcd.conf +``` + +At the bottom of the file add the following lines: + +```text +interface wlan0 <----- or the interface you just wrote down. + +static ip_address=192.168.0.200/24 <---- the IP address you just wrote down with a '/24' at the end +static routers=192.168.0.1 <---- Your router's IP address +static domain_name_servers=192.168.0.1 <---- Your router's IP address +``` + +It is important to note that the first three bits of your static IP address and your router's IP address should be the same, eg: + +```text +Router: 192.168.0.1 + +Yes +HA IP: 192.168.0.200 + +No +HA IP: 192.175.96.200 +``` + +Press Ctrl + x to close the editor, pressing Y to save the changes when prompted. + +Reboot your Pi: + +```bash +$ sudo reboot +``` + +When it comes back up check that you can SSH in to it again on the IP address you wrote down. + +Make sure Home Assisstant is running and access it via the local network by typing the IP address and port number in to the browser: + +```text +http://192.168.0.200:8123. +``` + +All working? Hooray! You now have a static IP. This will now always be your internal IP address for your Home Assistant device. This will be known as YOUR-HA-IP for the rest of this guide. + +### {% linkable_title 2 - Set up port forwarding without SSL and test connection %} + +Log in to your router's configuration pages and find the port forwarding options. This bit is hard to write a guide for because each router has a different way of presenting these options. Searching google for "port forwarding" and the name of your router may help. When you find it you will likely have options similar to: + +Service name - Port Range - Local IP - Local Port - Protocol + +You may also have other options (like 'source IP'), these can usually be left blank or in their default state. + +Set the port forwarding to: + +```text +Service name - ha_test +Port Range - 8123 +Local IP - YOUR-HA-IP +Local Port - 8123 +Protocol - Both +``` + +Then save the change. On my router you have to fill these values in, then press an 'add' button to add the new rule to the list, then save the changes. All routers have a different interface, but you must ensure that these rules are saved at this point. If you are unsure, you can reboot the router and log back in, if the rule is present it was saved, if not, it wasn't! + +Once you have saved this rule, go to your browser, and go to: + +```text +https://whatismyipaddress.com/ +``` + +This will tell you your current external IP address + +Type the external IP address in to the url bar with http:// in front and :8123 after like so (12.12.12.12 is my example!): + +```text +http://12.12.12.12:8123 +``` + +Can you see your Home Assisstant instance? If not, your router may not support 'loopback' - try the next step anyway and if that works, and this one still doesn't, just remember that you cannot use loopback, so will have to use internal addresses when you're on your home network. More on this later on if it's relevant to you. + +Just to verify this isn't some kind of witchcraft that is actually using your internal network, pick up your phone, disconnect it from your wifi so that you are on your mobile data and not connected to the home network, put the same URL in the browser on your phone. + +Can you see it now, from a device that is definitely not connected to your local network? Excellent! You now have a remotely accesible Home Assistant instance. + +But what if your external IP changes? Plus, remembering all those numbers is pretty hard, isn't it? Read on to get yourself set up with a word-based URL at DuckDNS that will track any changes to your IP address so you don't have to stress anymore. + +### {% linkable_title 3 - Set up a DuckDNS account %} + +Open your browser and go to https://duckdns.org. + +Sign in and create an account using one of the id validation options in the top right corner. + +In the domains section pick a name for your subdomain, this can be anything you like, and click add domain. + +The URL you will be using later to access your Home Assistant instance from outside will be the subdomain you picked, followed by duckdns.org . For our example we will say our URL is examplehome.duckdns.org + +On the top left of duckdns.org select the install option. Then pick your operating system from the list. In our example we will use a Raspberry Pi. In the dropdown box select the url you just created. + +Duckdns.org will now generate personalised instructions for you to follow so that your device can update their website every time your IP address changes. Carefully follow the instructions given on duckdns.org to set up your device. + +At the end of the instructions DuckDNS will suggest you set up port forwarding. No need, we have already done this in step 2. + +What you have now done is set up DuckDNS so that whenever you type examplehome.duckdns.org in to your browser it will convert that to your router's external IP address. Your external IP address will always be up to date because your device running Home Assistant will update DuckDNS every time it changes. + +Now type your new URL in to your address bar on your browser with port 8123 on the end: + +```text +http://examplehome.duckdns.org:8123 +``` + +What now happens behind the scenes is this: + +- DuckDNS receives the request and forwards the request to your router's external IP address (which has been kept up to date by your device running Home Assisstant) +- Your router receives the request on port 8123 and checks the port forwarding rules +- It finds the rule you created in step 2 and forwards the request to your HA instance +- Your browser displays your Home Assisstant instance frontend. + +Did it work? Super! + +You now have a remotely accesible Home Assistant instance that has a text-based URL and will not drop out if your service provider changes your IP. But, it is only as secure as the password you set, which can be snooped during your session by a malicious hacker with relative ease. So we need to set up some encryption with SSL, read on to find out how. + +### {% linkable_title 4 - Obtain an TLS/SSL certificate from Let's Encrypt %} + +First we need to set up another port forward like we did in step 2. Set your new rule to: + +```text +Service name - ha_letsencrypt +Port Range - 80 +Local IP - YOUR-HA-IP +Local Port - 80 +Protocol - Both +``` + +Remember to save the new rule. + +

+In cases where your ISP blocks port 80 you will need to change the port forward options to forward port 443 from outside to port 443 on your Home Assistant device. Please note that this will limit your options for automatically renewing the certificate, but this is a limitation because of your ISP setup and there is not a lot we can do about it! +

+ +now SSH in to the device your Home Assistant is running on. + +

+If you're running the 'standard' setup on a Raspberry Pi the chances are you just logged in as the 'pi' user. If not, you may have logged in as the Home Assistant user. There are commands below that require the Home Assistant user to be on the `sudoers` list. If you are not using the 'standard' pi setup it is presumed you will know how to get your Home Assistant user on the `sudoers` list before continuing. If you are running the 'standard' pi setup, from your 'pi' user issue the following command (where is the Home Assistant user): + +```bash +$ sudo adduser sudo +``` + +

+ +If you did not already log in as the user that currently runs Home Assistant, change to that user (usually `hass` or `homeassistant` - you may have used a command similar to this in the past): + +```bash +$ su -s /bin/bash hass +``` + +Make sure you are in the home directory for the HA user: + +```bash +$ cd +``` + +We will now make a directory for the certbot software, download it and give it the correct permissions: + +```text +$ mkdir certbot +$ cd certbot/ +$ wget https://dl.eff.org/certbot-auto +$ chmod a+x certbot-auto +``` + +Now we will run the certbot program to get our ssl certificate. You will need to include your email address and your DuckDNS url in the appropriate places: + +```text +$ ./certbot-auto certonly --standalone --preferred-challenges http-01 --email your@email.address -d examplehome.duckdns.org +``` + +Once the program has run it will generate a certificate and other files and place them in a folder `/etc/letsencrypt/` . + +Confirm this file has been populated: + +```bash +$ ls /etc/letsencrypt/live/ +``` + +This should show a folder named exactly after your DuckDNS url. + +Our Home Assistant user needs access to files within the letsencrypt folder, so issue the following commands to change the permissions. + +```bash +$ sudo chmod 755 /etc/letsencrypt/live/ +$ sudo chmod 755 /etc/letsencrypt/archive/ +``` + +Did all of that go without a hitch? Wahoo! Your Let's Encrypt certificate is now ready to be used with Home Assistant. Move to step 5 to put it all together + +### {% linkable_title 5 - Check the incoming conection %} + +

+Following on from Step 4 your SSH will still be in the certbot folder. If you edit your configuration files over SSH you will need to change to your `homeassistant` folder: + +```bash +$ cd ~/.homeassistant +``` + +If you use samba shares to edit your files you can exit your SSH now. +

+ +If during step 4 you had to use port 443 instead of port 80 to generate your certificate, you should delete that rule now. + +Go to your router's configuration pages and set up a new port forwarding rule, thus: + +```text +Service name - ha_ssl +Port Range - 443 +Local IP - YOUR-HA-IP +Local Port - 8123 +Protocol - Both +``` + +Remember to save the rule changes. + +Now edit your configuration.yaml file to reflect the SSL entries and your base URL (changing the `examplehome` subdomain to yours): + +```yaml +http: + api_password: YOUR_PASSWORD + ssl_certificate: /etc/letsencrypt/live/examplehome.duckdns.org/fullchain.pem + ssl_key: /etc/letsencrypt/live/examplehome.duckdns.org/privkey.pem + base_url: examplehome.duckdns.org +``` + +You may wish to set up other options for the [http](https://home-assistant.io/components/http/) component at this point, these extra options are beyond the scope of this guide. + +Save the changes to configuration.yaml. Restart Home Assistant. + +In step 3 we accessed our Home Assistant from the outside world with our DuckDNS URL and our port number. We are going to use a slightly different URL this time. + +```text +https://examplehome.duckdns.org +``` + +Note the S after http, and that no port number is added. This is because https will use port 443 automatically, and we have already set up our port forward to redirect this request to our Home Assistant instance on port 8123. + +You should now be able to see your Home Assistant instance via your DuckDNS URL, and importantly note that your browser shows the connection as secure. + +You will now NO LONGER be able to access your Home Assistant via your old internal IP address in the way you previously have. Your default way to access your Home Assistant instance, even from inside your house, is to use your DuckDNS URL. + +In cases where you need to access via the local network only (which should be few and far between) you can access it with the following URL (note the added **S** after http): + +```text +https://YOUR-HA-IP:8123 +``` + +and accepting the browsers warning that you are connecting to an insecure site. This warning occurs because your certificate expects your incoming connection to come via your DuckDNS URL. It does not mean that your device has suddenly become insecure. + +Some cases such as this are where your router does not allow 'loopback' or where there is a problem with incoming connections due to technical failure. In these cases you can still use your internal connection and ignore the warnings. + +If you were previously using a webapp on your phone/tablet to access your Home Assistant you should delete the old one and create a new one with the new address. The old one will no longer work as it is not keyed to your new, secure URL. Instructions for creating your new webapp can be found here: + +```text +https://home-assistant.io/docs/frontend/mobile/ +``` + +All done? Accessing your Home Assistant from across the world with your DuckDNS URL and a lovely secure logo on your browser? Ace! Now let's clean up our port forwards so that we are only exposing the parts of our network that are absolutely neccesary to the outside world. + +### {% linkable_title 6 - Clean up port forwards %} + +In step 2 we created a port forwarding rule called `ha_test`. This opens port 8123 to the world, and is no longer neccessary. + +Go to your router's configuration pages and delete the `ha_test` rule. + +You should now have two rules in relation to Home Assistant for your port forwards, named: + +```text +ha_ssl and ha_letsencrypt +``` + +If you have any more for Home Assistant you should delete them now. If you only have `ha_ssl` this is probably because during step 4 you had to use port 443 instead of port 80, so we deleted the rule during step 5. + +You are now part of one of two groups: + + * If you have BOTH rules you are able to set up auto renewals of you certificates. + * If you only have one, you will have to manually change the rule when you want to update your certificate, and then change it back afterwards. + +Please remember whether you are a ONE-RULE person or a BOTH-RULE person for step 8! + +Let's Encrypt certificates only last for 90 days. When they have less than 30 days left they can be renewed. Renewal is a simple process. + +Move on to step 7 to see how to monitor your certificates expiry date, and be ready to renew your certificate when the time comes. + +#### {% linkable_title 7 - Set up a sensor to monitor the expiry date of the certificate %} + +Setting a sensor to read the number of days left on your TLS/SSL certificate before it expires is not required, but it has the following advantages: + + * You can physically see how long you have left, pleasing your inner control freak + * You can set automations based on the number of days left + * You can set alerts to notify you if your certificate has not been renewed and is coming close to expiry. + * If you cannot set up automatic renewals due to your ISP blocking port 80, you will have timely reminders to complete the process manually. + +If you do not wish to set up a sensor you can skip straight to step 8 to learn how to update your certificates. + +The sensor will rely on a command line program that needs to be installed on your device running Home Assistant. SSH in to the device and run the following commands: + +```bash +$ sudo apt-get update +$ sudo apt-get install ssl-cert-check +``` + +

+In cases where, for whatever reason, apt-get installing is not appropriate for your installation you can fetch the ssl-cert-check script from `http://prefetch.net/code/ssl-cert-check` bearing in mind that you will have to modify the command in the sensor code below to run the script from wherever you put it, modify permission if neccessary and so on. +

+ +To set up a senor add the following to your `configuration.yaml` (remembering to correct the URL for your DuckDNS): + +```yaml +sensor: + - platform: command_line + name: SSL cert expiry + unit_of_measurement: days + scan_interval: 10800 + command: "ssl-cert-check -b -c /etc/letsencrypt/live/examplehome.duckdns.org/cert.pem | awk '{ print $NF }'" +``` + +Save the configuration.yaml. Restart Home Assistant. + +On your default_view you should now see a sensor badge containing your number of days until expiry. If you've been following this guide from the start and have not taken any breaks in between, this should be 89 or 90. The sensor will update every 3 hours. You can place this reading on a card using groups, or hide it using customize. These topics are outside of the scope of this guide, but information can be found on their respective components pages: [Group](/components/group/) and [Customize](/docs/configuration/customizing-devices/) + +Got your sensor up and running and where you want it? Top drawer! Nearly there, now move on to the final steps to ensure that you're never without a secure connection in the future. + +### {% linkable_title 8 - Set up an automatic renewal of the TLS/SSL certificate. %} + +The certbot program we downloaded in step 4 contains a script that will renew your certificate. The script will only obtain a new certificate if the current one has less than 30 days left on it, so running the script more often than is actually needed will not cause any harm. + +If you are a ONE-RULE person (from step 6) you cannot 'automatically' renew your certificates because you will need to change your port forwarding rules before the renewal takes place, and change it back again afterwards. + +When you are within 30 days of your certificate's expiry date (you can use the sensor reading from step 7 to tell you this) you will need to complete the following steps: + + * Go to your router's configuration pages and edit your port forwarding rule to + +```text +Service name - ha_ssl +Port Range - 443 +Local IP - YOUR-HA-IP +Local Port - 443 +Protocol - Both +``` + + * Save the rule + * SSH in to your device running HA. + * Change to your HA user (command similar to): + +```bash +$ su - s /bin/bash hass +``` + + * Change to your certbot folder + +```bash +$ cd ~/certbot/ +``` + + * Run the renewal command + +```bash +$ ./certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 +``` + + * Once succesfully completed, change your port forwarding rule back to + +```text +Service name - ha_ssl +Port Range - 443 +Local IP - YOUR-HA-IP +Local Port - 8123 +Protocol - Both +``` + + * Save the rule + +If you are a BOTH-RULE person, you have a number of options at this point. + +#### Option 1: +Your certificate can be renewed as a 'cron job' - cron jobs are background tasks run by the computer at specified intervals (and are totally independant of Home Assistant). Defining cron is outside of the scope of this guide but you will have had dealings with `crontab` when setting up DuckDNS in step 3 + +To set a cron job to run the script at regular intervals: + + * SSH in to your device running Home Assistant. + * Change to your Home Assistant user (command similar to): + +```bash +$ su - s /bin/bash hass +``` + + * Open the crontab: + +```bash +$ crontab -e +``` + + * Scroll to the bottom of the file and paste in the following line + +```text +30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log +``` + * Save the file and exit + + +#### Option 2: +You can set an automation in Home Assistant to run the certbot renewal script. + +Add the following sections to your configuration.yaml + +```yaml +shell_command: + renew_ssl: ./certbot/certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 + +automation + - alias: 'Auto Renew SSL Cert' + trigger: + platform: numeric_state + entity_id: sensor.ssl_cert_expiry + below: 29 + action: + service: shell_command.renew_ssl +``` + +#### Option 3: +You can manually update the certificate when your certificate is less than 30 days to expiry. + +To manually update: + + * SSH in to your device running Home Assistant. + * Change to your Home Assistant user (command similar to): + +```bash +$ su - s /bin/bash hass +``` + + * Change to your certbot folder + +```bash +$ cd ~/certbot/ +``` + + * Run the renewal command + +```bash +$ ./certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 +``` + +So, now were all set up. We have our secured, remotely accesible HA instance and we're on track for keeping our certificates up to date. But what if something goes wrong? What if the automation didn't fire? What if the cron job forgot to run? What if the dog ate my homework? Read on to set up an alert so you can be notified in plenty of time if you need to step in and sort out any failures. + +### {% linkable_title 9 - Set up an alert to warn us if something went wrong. %} + +We set up our automatic renewal of our certificates and whatever method we used the certificate should be renewed on or around 30 days before it expires. But what if a week later it still hasn't been? This alert will go off if the expiry time on the certificate gets down to 21 days. This will give you 3 weeks to fix the problem, get your new certificate installed and get another 90 days of secure Home Assistant connections in play. + +In your `configuration.yaml` add the following automation, adding your preferred notification platform where appropriate: + +```yaml +automation: + - alias: 'SSL expiry notification' + trigger: + platform: numeric_state + entity_id: sensor.ssl_cert_expiry + below: 21 + action: + service: notify.[your_notification_preference] + data: + message: 'Warning - SSL certificate expires in 21 days and has not been automatically renewed' +``` + +If you receive this warning notification, follow the steps for a manual update from step 8. Any error messages received at that point can be googled and resolved. If the manual update goes without a hitch there may be something wrong with your chosen method for automatic updates, and you can start troubleshooting from there. + +So, that's it. We've taken a Home Assistant instance that was only reachable on the local network, made it accessible from the internet, secured it, and set up a system to ensure that it always stays secure. Well done, go and treat yourself to a cookie! diff --git a/source/_includes/asides/docs_navigation.html b/source/_includes/asides/docs_navigation.html index 08f26f379f0..d71c8929a24 100644 --- a/source/_includes/asides/docs_navigation.html +++ b/source/_includes/asides/docs_navigation.html @@ -190,6 +190,7 @@
  • {% active_link /docs/ecosystem/certificates/tls_self_signed_certificate/ Self-signed certificate %}
  • {% active_link /docs/ecosystem/certificates/tls_domain_certificate/ Certificate domain owners %}
  • +
  • {% active_link /docs/ecosystem/certificates/lets_encrypt/ Let's Encrypt (detailed) %}
  • {% active_link /docs/ecosystem/scenegen/ scenegen %}
  • From 06f2f03dcbdf3b2cc88d9f088cbd03a6c9814a34 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Sat, 1 Apr 2017 06:38:43 -0400 Subject: [PATCH 26/38] Updated Ring component documentation (#2366) * Updated Ring component documentation * Add reference to sub pages --- .../_components/binary_sensor.ring.markdown | 18 ++++------ source/_components/ring.markdown | 33 +++++++++++++++++++ source/_components/sensor.ring.markdown | 17 ++++++---- 3 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 source/_components/ring.markdown diff --git a/source/_components/binary_sensor.ring.markdown b/source/_components/binary_sensor.ring.markdown index 2b6e75db388..fdf0010de8e 100644 --- a/source/_components/binary_sensor.ring.markdown +++ b/source/_components/binary_sensor.ring.markdown @@ -2,28 +2,24 @@ layout: page title: "Ring" description: "Instructions on how to integrate your Ring.com devices within Home Assistant." -date: 2017-03-10 10:00 +date: 2017-04-01 10:00 sidebar: true comments: false sharing: true footer: true logo: ring.png ha_category: Binary Sensor -ha_release: 0.40 +ha_release: 0.42 --- -The `ring` binary sensor allows you to integrate your [Ring.com](https://ring.com/) devices in Home Assistant. +To get your [Ring.com](https://ring.com/) binary sensors working within Home Assistant, please follow the instructions for the general [Ring component](/components/ring). -Currently only doorbells are supported by this sensor. - -To enable device linked in your [Ring.com](https://ring.com/) account, add the following to your `configuration.yaml` file: +Once you have enabled the [Ring component](/components/ring), add the following to your `configuration.yaml` file: ```yaml # Example configuration.yaml entry binary_sensor: - platform: ring - username: USERNAME - password: PASSWORD monitored_conditions: - ding - motion @@ -31,8 +27,8 @@ binary_sensor: Configuration variables: -- **username** (*Required*): The username for accessing your Ring account. -- **password** (*Required*): The password for accessing your Ring account. - **monitored_conditions** array (*Required*): Conditions to display in the frontend. The following conditions can be monitored. - **ding**: Return a boolean value when the doorbell button was pressed. - - **motion**: Return a boolean value when the a moviment was detected by the Ring doorbell. + - **motion**: Return a boolean value when a moviment was detected by the Ring doorbell. + +Currently only doorbells are supported by this sensor. diff --git a/source/_components/ring.markdown b/source/_components/ring.markdown new file mode 100644 index 00000000000..a4afe719a03 --- /dev/null +++ b/source/_components/ring.markdown @@ -0,0 +1,33 @@ +--- +layout: page +title: "Ring" +description: "Instructions on how to integrate your Ring.com devices within Home Assistant." +date: 2017-04-01 10:00 +sidebar: true +comments: false +sharing: true +footer: true +logo: ring.png +ha_category: Hub +ha_release: 0.42 +--- + +The `ring` implementation allows you to integrate your [Ring.com](https://ring.com/) devices in Home Assistant. + +Currently only doorbells are supported by this sensor. + +To enable device linked in your [Ring.com](https://ring.com/) account, add the following to your `configuration.yaml` file: + +```yaml +# Example configuration.yaml entry +ring: + username: you@example.com + password: secret +``` + +Configuration variables: + +- **username** (*Required*): The username for accessing your Ring account. +- **password** (*Required*): The password for accessing your Ring account. + +Finish its configuration by visiting the [Ring binary_sensor page](/components/binary_sensor.ring/) or [Ring sensor page](/components/sensor.ring/). diff --git a/source/_components/sensor.ring.markdown b/source/_components/sensor.ring.markdown index 9ee8ca5b124..311374cfe0f 100644 --- a/source/_components/sensor.ring.markdown +++ b/source/_components/sensor.ring.markdown @@ -2,7 +2,7 @@ layout: page title: "Ring" description: "Instructions on how to integrate your Ring.com devices within Home Assistant." -date: 2017-03-05 10:00 +date: 2017-04-01 10:00 sidebar: true comments: false sharing: true @@ -12,20 +12,19 @@ ha_category: Sensor ha_release: "0.40" --- -The `ring` sensor allows you to integrate your [Ring.com](https://ring.com/) devices in Home Assistant. -Currently it supports doorbells and external chimes only. +To get your [Ring.com](https://ring.com/) binary sensors working within Home Assistant, please follow the instructions for the general [Ring component](/components/ring). -To enable device linked in your [Ring.com](https://ring.com/) account, add the following to your `configuration.yaml` file: +Once you have enabled the [Ring component](/components/ring), add the following to your `configuration.yaml` file: ```yaml # Example configuration.yaml entry sensor: - platform: ring - username: USERNAME - password: PASSWORD monitored_conditions: - battery - last_activity + - last_ding + - last_motion - volume ``` @@ -36,5 +35,9 @@ Configuration variables: - **scan_interval** (*Optional*): Defines the update interval of the sensor in seconds. The default is 30 seconds. - **monitored_conditions** array (*Required*): Conditions to display in the frontend. The following conditions can be monitored. - **battery**: Return the battery level from device - - **last_activity**: Return the timestamp from the last event captured by the Ring doorbell camera + - **last_activity**: Return the timestamp from the last event captured (ding/motion/on_demand) by the Ring doorbell camera + - **last_ding**: Return the timestamp from the last time the Ring doorbell button was pressed + - **last_motion**: Return the timestamp from the last motion event captured by the Ring doorbell camera - **volume**: Return the volume level from the device. Currently supported by external chimes and doorbells. + +Currently it supports doorbells and external chimes only. From eaf8147342e444d9a57c8f7d0d16967a97fe9a12 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 1 Apr 2017 22:11:18 +0200 Subject: [PATCH 27/38] Minimize the configuration sample --- source/_components/sensor.lyft.markdown | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/source/_components/sensor.lyft.markdown b/source/_components/sensor.lyft.markdown index a54970ed890..bcb72bc278e 100644 --- a/source/_components/sensor.lyft.markdown +++ b/source/_components/sensor.lyft.markdown @@ -1,6 +1,6 @@ --- layout: page -title: "Lyft" +title: "Lyft Sensor" description: "How to integrate Lyft in Home Assistant" date: 2017-03-19 21:05 sidebar: true @@ -10,7 +10,7 @@ footer: true logo: lyft.png ha_category: Transport ha_iot_class: "Cloud Polling" -ha_release: 0.41 +ha_release: 0.42 --- @@ -25,12 +25,9 @@ To enable this sensor, add the following lines to your `configuration.yaml` file # Example configuration.yaml entry sensor: - platform: lyft - client_id: [...] - client_secret: [...] + client_id: CLIENT_ID + client_secret: CLIENT_SECRET start_latitude: 37.8116380 - start_longitude: -122.2648050 - end_latitude: 37.615223 - end_longitude: -122.389977 ``` Configuration variables: @@ -49,8 +46,8 @@ A full configuration entry could look like the sample below: # Example configuration.yaml entry sensor: - platform: lyft - client_id: [...] - client_secret: [...] + client_id: CLIENT_ID + client_secret: CLIENT_SECRET start_latitude: 37.8116380 start_longitude: -122.2648050 end_latitude: 37.615223 From c4ea556765888484f295976b70a780540f433970 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 1 Apr 2017 22:14:15 +0200 Subject: [PATCH 28/38] Use default format for configuration variables --- source/_components/lock.lockitron.markdown | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/_components/lock.lockitron.markdown b/source/_components/lock.lockitron.markdown index c26a16be5f8..418881c1693 100644 --- a/source/_components/lock.lockitron.markdown +++ b/source/_components/lock.lockitron.markdown @@ -24,7 +24,8 @@ lock: id: fdsa ``` -| Configuration variables| Optional | Description | -| ---------------------- | -------- | ----------- | -| `access_token` | no | The security token provided by Lockitron to lock and unlock your lock -| `id` | no | The lock id given by Lockitron (should be a GUID) \ No newline at end of file +Configuration variables: + +- **access_token** (*Required*): The usernThe security token provided by Lockitron to lock and unlock your lock. +- **id** (*Required*): The lock id given by Lockitron (should be a GUID). + From 5d1439563179b65dc9bc934f7cf974367e0023a4 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 1 Apr 2017 22:14:51 +0200 Subject: [PATCH 29/38] Update title --- source/_components/binary_sensor.ring.markdown | 2 +- source/_components/sensor.ring.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/_components/binary_sensor.ring.markdown b/source/_components/binary_sensor.ring.markdown index fdf0010de8e..be27ab30d0d 100644 --- a/source/_components/binary_sensor.ring.markdown +++ b/source/_components/binary_sensor.ring.markdown @@ -1,6 +1,6 @@ --- layout: page -title: "Ring" +title: "Ring Binary Sensor" description: "Instructions on how to integrate your Ring.com devices within Home Assistant." date: 2017-04-01 10:00 sidebar: true diff --git a/source/_components/sensor.ring.markdown b/source/_components/sensor.ring.markdown index 311374cfe0f..20c0be9fbd6 100644 --- a/source/_components/sensor.ring.markdown +++ b/source/_components/sensor.ring.markdown @@ -1,6 +1,6 @@ --- layout: page -title: "Ring" +title: "Ring Sensor" description: "Instructions on how to integrate your Ring.com devices within Home Assistant." date: 2017-04-01 10:00 sidebar: true From 0db3aa2f301268f36c1f1286bd1a5d9dcbc7f602 Mon Sep 17 00:00:00 2001 From: "Craig J. Ward" Date: Tue, 4 Apr 2017 06:19:50 -0500 Subject: [PATCH 30/38] TotalConnect documentation (#2372) * TotalConnect documentation # Conflicts: # source/_components/insteon_local.markdown # source/developers/credits.markdown * add Honeywell TC logo * version * update documentation * remove name from example --- .../alarm_control_panel.totalconnect.markdown | 31 ++++++++++++++++++ .../images/supported_brands/honeywell-tc.png | Bin 0 -> 25440 bytes 2 files changed, 31 insertions(+) create mode 100644 source/_components/alarm_control_panel.totalconnect.markdown create mode 100644 source/images/supported_brands/honeywell-tc.png diff --git a/source/_components/alarm_control_panel.totalconnect.markdown b/source/_components/alarm_control_panel.totalconnect.markdown new file mode 100644 index 00000000000..923416b929a --- /dev/null +++ b/source/_components/alarm_control_panel.totalconnect.markdown @@ -0,0 +1,31 @@ +--- +layout: page +title: "Honeywell TotalConnect Alarm Control Panel" +description: "Instructions how to integrate TotalConnect alarms into Home Assistant." +date: 2017-04-02 22:00 +sidebar: true +comments: false +sharing: true +footer: true +logo: honeywell-tc.png +ha_category: Alarm +ha_release: 0.42 +--- + +The `totalconnect` platform provides connectivity with the Honeywell TotalConnect alarm systems used by many alarm companies + +To enable this, add the following lines to your `configuration.yaml`: + +```yaml +# Example configuration.yaml entry +alarm_control_panel: + platform: totalconnect + username: YOUR_USERNAME + password: YOUR_PASSWORD +``` + +Configuration variables: +- **name** (*Optional*): Name of device in HomeAssistant +- **username** (*Required*): Username used to sign into the TotalConnect app/web client. +- **password** (*Required*): Password used to sign into the TotalConnect app/web client. + diff --git a/source/images/supported_brands/honeywell-tc.png b/source/images/supported_brands/honeywell-tc.png new file mode 100644 index 0000000000000000000000000000000000000000..f6776e66d01079fef77f74bd8b9a293072e8b94e GIT binary patch literal 25440 zcmaI7bx>VRvoDOhyKC?bY~0=5-DMNpHNoB8b|ARB1P$&k!QCZ5aMv&IbIx<__s2bV z)zn%utGau7x_{F()iV>Nsw{(wM1%wZ0f8zfE2$0v0h#%?u8#os_Z?<0YW(*@=q{z} zuHj_m?q%i*f)KNGG6zw}IhcJ0se{ZceOyLCf)EhUv^JW$?z&2f{1#3QEN1_qVexiw z{>u#kAt>VQY-V8xa;Go{eYSBFqPqCmO+{g2DMY2ir36%RmH=7X$bNAJX?#)EwD@9Y z!DmS&B1|FZ&Hq<`1IXQs!rQ^#(T(3*i0U7?{D15J`OQj2@ehf+oeV+0b0-gXA*#Qc{?`y3oc~9xquYO*>94_9z0I6i*;s)88PdOm zN=pB4QU{0sp>}gu2mK#?|F44GG<}>wtm+^)Cl6PPzmBt_{!drV{1UDpGj}IfO(!S& zf32u$?d0y{X6@umAtCXP)hOt7Y#c3}yxbW6;ZaiJmveM;H*>TA$w>-P{guLEV`ItB zD<%yDvT;dCiLr6Au}N`>@c_l7c{n(^`M9Kkyd0eW@=7{ccsPI@-T&pa{6DAia92cHMh@;UEbT>W$F_R={= zP{Ixk9Z3-xEUQMTrq~l4MxcOoM~IbTD$7aRY1v_SKLr)|F9lrYy>-HW6>8zwe`z5|c%AcVeB9t-+3FmSKg_>Bz6Mhuu&DNE zyOi)>aa|>YaI+=4bb}+vR#3uiL}mC9zprq*ds$JW$wGwrX&Isyr9R)tLkcGq^1@Hc z(l}{hIre5m{PqhAfPoYWe<33vu!dIrN2%eCkf1Q}TWWg2T2*=GYU%Z{j7OW5bVPys zvxsTq8@FS<4j6NBF_a_<3uN6@aQL1!ASk2S1kvcb9x5jc#Vjwe*kR{mEBfri_~WBW zYuXx0$v;E1Ftgxu&2;k43Gif23z@vK(F(|&eCjp%pg5$&Fr^{-Hz&|Y(0v~+F9NNWPgmMnC7*>M;{<@7X1K7=RJ`)I`ti8>@`>aYq{z;i=t#6 z1(O-stwcCGaf13*$k^kTpj<=l3X6E0d2B_}f#tW*pm$c69p9|2PifY^5=R zjHDlAPq3zn*)>v*#}&kiG+c9R`>&7Y#gyMEEv~Te}YgEB4xyW+Rj< z!f}iIggGYIyJ`uV{y1O8eRBx3`3Ieu{GJz^X;RIXKawjF zCL_?Qz$u*m{zDfHVU3yJEFGn!_u^C7;JaQoa(ik$4@{quAtSROXkoT9
    Pa)gSw! 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 literal 0 HcmV?d00001 From 4ba577a2f46094cbc77d4b93a4aeb6cd80f1766b Mon Sep 17 00:00:00 2001 From: citruz Date: Wed, 5 Apr 2017 07:16:41 +0200 Subject: [PATCH 31/38] Added documentation and logo for eddystone_temperature platform. (#2334) * Added documentation and logo for eddystone_temperature platform. * Update sensor.eddystone_temperature.markdown Fixed formatting and removed unnecessary shortenings. --- .../sensor.eddystone_temperature.markdown | 57 ++++++++++++++++++ source/images/supported_brands/eddystone.png | Bin 0 -> 3610 bytes 2 files changed, 57 insertions(+) create mode 100644 source/_components/sensor.eddystone_temperature.markdown create mode 100644 source/images/supported_brands/eddystone.png diff --git a/source/_components/sensor.eddystone_temperature.markdown b/source/_components/sensor.eddystone_temperature.markdown new file mode 100644 index 00000000000..b11cbd00766 --- /dev/null +++ b/source/_components/sensor.eddystone_temperature.markdown @@ -0,0 +1,57 @@ +--- +layout: page +title: "Eddystone Beacon" +description: "Instructions on how to integrate Eddystone beacons with Home Assistant in order to receive temperature data." +date: 2017-03-26 01:00 +sidebar: true +comments: false +sharing: true +footer: true +logo: eddystone.png +ha_category: DIY +ha_release: 0.42 +ha_iot_class: "Local Polling" +--- + +The `eddystone_temperature` sensor platform reads temperature information from Bluetooth LE advertisements transmitted by [Eddystone](https://en.wikipedia.org/wiki/Eddystone_(Google)) beacons. Your beacons must be configured to transmit UID frames (for identification) and TLM frames (for temperature). +All beacons that support the Eddystone protocol, have a temperature sensor and can transmit TLM frames are compatible with this platform. For example [Gimbal](https://store.gimbal.com/collections/beacons/), [Estimote](http://estimote.com/) or [kontakt.io](https://kontakt.io/). For more manufacturers see [this overview](https://developers.google.com/beacons/eddystone#beacon_manufacturers) by Google. + +## Requirements + +As this platform uses `bluez` to scan for Bluetooth LE devices **a Linux OS with bluez installed** is required. In addition to that, the `libbluetooth` headers need to be installed: +```shell +$ sudo apt-get install libbluetooth-dev +``` + +Scanning for Bluetooth LE devices also requires special permissions. To grant these to the python executable execute the following: +```shell +$ sudo apt-get install libcap2-bin +$ sudo setcap 'cap_net_raw,cap_net_admin+eip' $(readlink -f $(which python3)) +``` + +## Configuration + +To use your Eddystone beacon in your installation, add the following to your `configuration.yaml` file: + +```yaml +# Example configuration.yaml entry +sensor: + - platform: eddystone_temperature + bt_device_id: 0 # optional + beacons: + living_room: + namespace: "112233445566778899AA" + instance: "000000000001" + name: "Living Room" # optional + kitchen: + namespace: "112233445566778899AA" + instance: "000000000002" + name: "Kitchen" # optional +``` +Configuration variables: +- **bt_device_id** (*Optional*): The id of the bluetooth device that should be used for scanning (hci*X*). You can find the correct one using `hcitool dev` (default: 0). +- **beacons** array (*Required*): The beacons that should be monitored. + - **[entry]** (*Required*): Name of the beacon. + - **namespace** (*Required*): Namespace ID of the beacon in hexadecimal notation. Must be exactly 20 characters (10 bytes) long. + - **namespace** (*Required*): Instance ID of the beacon in hexadecimal notation. Must be exactly 12 characters (6 bytes) long. + - **name** (*Optional*): Friendly name of the beacon. diff --git a/source/images/supported_brands/eddystone.png b/source/images/supported_brands/eddystone.png new file mode 100644 index 0000000000000000000000000000000000000000..77798ee4f9af5449647e281041c99bb85a466845 GIT binary patch literal 3610 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 QexSfZ4h#vX^JnM&7g1(``2YX_ literal 0 HcmV?d00001 From 6f8db0a3f82ac03dc2f8b2ec966d21320f5246a0 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Wed, 5 Apr 2017 08:11:49 -0400 Subject: [PATCH 32/38] Rename zwave nodes by node ID instead of entity ID (#2382) --- source/_docs/z-wave.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/_docs/z-wave.markdown b/source/_docs/z-wave.markdown index 054652db65c..bbe53187b0d 100644 --- a/source/_docs/z-wave.markdown +++ b/source/_docs/z-wave.markdown @@ -241,7 +241,7 @@ The `zwave` component exposes multiple services to help maintain the network. | refresh_entity| Refresh Z-Wave entity by refreshing dependent values.| | refresh_node| Refresh Z-Wave node. | | remove_node | Put the Z-Wave controller in exclusion mode. Allows one to remove a device from the Z-Wave network.| -| rename_node | Sets a node's name. Requires an `entity_id` and `name` field. | +| rename_node | Sets a node's name. Requires a `node_id` and `name` field. | | remove_failed_node | Remove a failed node from the network. The Node should be on the Controllers Failed Node List, otherwise this command will fail.| | replace_failed_node | Replace a failed device with another. If the node is not in the controller's failed nodes list, or the node responds, this command will fail.| | set_config_parameter | Let's the user set a config parameter to a node. | From ce71b245d004732ec081305dc9e03ca9daf84e8d Mon Sep 17 00:00:00 2001 From: Thibault Cohen Date: Wed, 5 Apr 2017 13:44:56 -0400 Subject: [PATCH 33/38] Update fido sensor documentation (#2256) --- source/_components/sensor.fido.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/_components/sensor.fido.markdown b/source/_components/sensor.fido.markdown index dd1b30c6d05..1b863d0e5f0 100644 --- a/source/_components/sensor.fido.markdown +++ b/source/_components/sensor.fido.markdown @@ -32,8 +32,9 @@ sensor: Configuration variables: -- **username** (*Required*): You Fido username (your Fido phone number). +- **username** (*Required*): You Fido username (your Fido phone number or your email). - **password** (*Required*): Your Fido password. +- **number** (*Optional*): Your Fido phone number (it will use your username if empty). - **monitored_variables** array (*Required*): Variables to monitor. - **fido_dollar**: Your Fido dollar balance - **balance**: Your account balance From adf95064c54c14b4d2c095833776d669277dd980 Mon Sep 17 00:00:00 2001 From: Marc Forth Date: Thu, 6 Apr 2017 08:04:01 +0100 Subject: [PATCH 34/38] Update lets_encrypt.markdown (#2387) Fixed some spelling mistakes and a couple of formatting errors. --- .../certificates/lets_encrypt.markdown | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/source/_docs/ecosystem/certificates/lets_encrypt.markdown b/source/_docs/ecosystem/certificates/lets_encrypt.markdown index aaac97c67ea..5a6918009cb 100644 --- a/source/_docs/ecosystem/certificates/lets_encrypt.markdown +++ b/source/_docs/ecosystem/certificates/lets_encrypt.markdown @@ -28,16 +28,16 @@ This guide was added by mf_social on 16/03/2017 and was valid at the time of wri Steps we will take: -0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding -1 - Set your device to have a static IP address -2 - Set up port forwarding without TLS/SSL and test connection -3 - Set up a DuckDNS account -4 - Obtain a TLS/SSL certificate from Let's Encrypt -5 - Check the incoming conection -6 - Clean up port forwards -7 - Set up a sensor to monitor the expiry date of the certificate -8 - Set up an automatic renewal of the TLS/SSL certificate -9 - Set up an alert to warn us if something went wrong + - 0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding + - 1 - Set your device to have a static IP address + - 2 - Set up port forwarding without TLS/SSL and test connection + - 3 - Set up a DuckDNS account + - 4 - Obtain a TLS/SSL certificate from Let's Encrypt + - 5 - Check the incoming conection + - 6 - Clean up port forwards + - 7 - Set up a sensor to monitor the expiry date of the certificate + - 8 - Set up an automatic renewal of the TLS/SSL certificate + - 9 - Set up an alert to warn us if something went wrong ### {% linkable_title 0 - Gain a basic level of understanding around IP addresses, port numbers and port forwarding %} @@ -65,7 +65,7 @@ So, we can use a static IP to ensure that whenever our device running Home Assis We then have no control over our external IP, as our Service Provider will give us a new one at random intervals. To fix this we will use a service called DuckDNS which will give us a name for our connection (something like examplehome.duckdns.org) and behind the scenes will continue to update your external IP. So no matter how many times the IP address changes, typing examplehome.duckdns.org in to our browser will convert to the correct, up-to-date, IP address. This is covered in step 3 below. -To get around the issue of not being able to chain the IP addresses together (I can't say I want to call 12:12:12:12 and be put through to 192.168.0.200, and then be put through to extension 8123) we use port forwarding. Port forwarding is the process of telling your router which device to allow the outside connection to speak to. In the doctors surgery example, port forwarding is the receptionist. This takes a call from outside, and forwards it to the correct extension number inside. It is important to note that port forwarding can forward an incoming request for one port to a different port on your internal network if you so choose, and we wil be doing this later on. The end result being that when we have our SSL certificate our incoming call will be requesting port 443 (because that is the SSL port, like the SSH port is always 22), but our port forwarding rule will forward this to our HA instance on port 8123. When this guide is completed we will run something like this: +To get around the issue of not being able to chain the IP addresses together (I can't say I want to call 12:12:12:12 and be put through to 192.168.0.200, and then be put through to extension 8123) we use port forwarding. Port forwarding is the process of telling your router which device to allow the outside connection to speak to. In the doctors surgery example, port forwarding is the receptionist. This takes a call from outside, and forwards it to the correct extension number inside. It is important to note that port forwarding can forward an incoming request for one port to a different port on your internal network if you so choose, and we will be doing this later on. The end result being that when we have our SSL certificate our incoming call will be requesting port 443 (because that is the SSL port, like the SSH port is always 22), but our port forwarding rule will forward this to our HA instance on port 8123. When this guide is completed we will run something like this: ```text Outside world -> https://examplehome.duckdns.org -> 12.12.12.12:443 -> your router -> 192.168.0.200:8123 @@ -120,7 +120,7 @@ HA IP: 192.175.96.200 Press Ctrl + x to close the editor, pressing Y to save the changes when prompted. -Reboot your Pi: +Reboot your device running HA: ```bash $ sudo reboot @@ -231,15 +231,14 @@ Remember to save the new rule. In cases where your ISP blocks port 80 you will need to change the port forward options to forward port 443 from outside to port 443 on your Home Assistant device. Please note that this will limit your options for automatically renewing the certificate, but this is a limitation because of your ISP setup and there is not a lot we can do about it!

    -now SSH in to the device your Home Assistant is running on. +Now SSH in to the device your Home Assistant is running on.

    -If you're running the 'standard' setup on a Raspberry Pi the chances are you just logged in as the 'pi' user. If not, you may have logged in as the Home Assistant user. There are commands below that require the Home Assistant user to be on the `sudoers` list. If you are not using the 'standard' pi setup it is presumed you will know how to get your Home Assistant user on the `sudoers` list before continuing. If you are running the 'standard' pi setup, from your 'pi' user issue the following command (where is the Home Assistant user): +If you're running the 'standard' setup on a Raspberry Pi the chances are you just logged in as the 'pi' user. If not, you may have logged in as the Home Assistant user. There are commands below that require the Home Assistant user to be on the `sudoers` list. If you are not using the 'standard' pi setup it is presumed you will know how to get your Home Assistant user on the `sudoers` list before continuing. If you are running the 'standard' pi setup, from your 'pi' user issue the following command (where `hass` is the Home Assistant user): ```bash -$ sudo adduser sudo +$ sudo adduser hass sudo ``` -

    If you did not already log in as the user that currently runs Home Assistant, change to that user (usually `hass` or `homeassistant` - you may have used a command similar to this in the past): @@ -314,7 +313,7 @@ Protocol - Both Remember to save the rule changes. -Now edit your configuration.yaml file to reflect the SSL entries and your base URL (changing the `examplehome` subdomain to yours): +Now edit your configuration.yaml file to reflect the SSL entries and your base URL (changing the `examplehome` subdomain to yours in all three places): ```yaml http: @@ -346,7 +345,7 @@ In cases where you need to access via the local network only (which should be fe https://YOUR-HA-IP:8123 ``` -and accepting the browsers warning that you are connecting to an insecure site. This warning occurs because your certificate expects your incoming connection to come via your DuckDNS URL. It does not mean that your device has suddenly become insecure. +...and accepting the browsers warning that you are connecting to an insecure site. This warning occurs because your certificate expects your incoming connection to come via your DuckDNS URL. It does not mean that your device has suddenly become insecure. Some cases such as this are where your router does not allow 'loopback' or where there is a problem with incoming connections due to technical failure. In these cases you can still use your internal connection and ignore the warnings. @@ -366,9 +365,7 @@ Go to your router's configuration pages and delete the `ha_test` rule. You should now have two rules in relation to Home Assistant for your port forwards, named: -```text -ha_ssl and ha_letsencrypt -``` +`ha_ssl` and `ha_letsencrypt` If you have any more for Home Assistant you should delete them now. If you only have `ha_ssl` this is probably because during step 4 you had to use port 443 instead of port 80, so we deleted the rule during step 5. @@ -383,7 +380,7 @@ Let's Encrypt certificates only last for 90 days. When they have less than 30 da Move on to step 7 to see how to monitor your certificates expiry date, and be ready to renew your certificate when the time comes. -#### {% linkable_title 7 - Set up a sensor to monitor the expiry date of the certificate %} +### {% linkable_title 7 - Set up a sensor to monitor the expiry date of the certificate %} Setting a sensor to read the number of days left on your TLS/SSL certificate before it expires is not required, but it has the following advantages: @@ -509,7 +506,7 @@ Add the following sections to your configuration.yaml shell_command: renew_ssl: ./certbot/certbot-auto renew --quiet --no-self-upgrade --standalone --preferred-challenges http-01 -automation +automation: - alias: 'Auto Renew SSL Cert' trigger: platform: numeric_state From 520805d57a453f80afd4a194fe238b5abfe4e5ee Mon Sep 17 00:00:00 2001 From: Diogo Soares Date: Thu, 6 Apr 2017 03:26:30 -0400 Subject: [PATCH 35/38] Added temperature variables since pyhydroquebec 1.1.0 (#2370) --- source/_components/sensor.hydroquebec.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/_components/sensor.hydroquebec.markdown b/source/_components/sensor.hydroquebec.markdown index 71fb63b5429..398b442d613 100644 --- a/source/_components/sensor.hydroquebec.markdown +++ b/source/_components/sensor.hydroquebec.markdown @@ -48,9 +48,11 @@ Configuration variables: - **period_total_consumption**: Total Consumption - **period_lower_price_consumption**: Period Lower price consumption - **period_higher_price_consumption**: Period Higher price consumption + - **period_average_temperature**: Period Average temperature - **yesterday_total_consumption**: Yesterday total consumption - **yesterday_lower_price_consumption**: Yesterday lower price consumption - **yesterday_higher_price_consumption**: Yesterday higher price consumption + - **yesterday_average_temperature**: Yesterday Average temperature To find your contract id, go to the [Hydro-Québec website](https://www.hydroquebec.com/portail/) and connect to your account. From 2f52a6a5a51054b7151bdb66b2437feea6e00a80 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 8 Apr 2017 15:28:27 -0700 Subject: [PATCH 36/38] Add homeassistant automation platform docs --- source/_docs/automation/trigger.markdown | 23 ++++++++++++++++++-- source/_includes/asides/docs_navigation.html | 7 +++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/source/_docs/automation/trigger.markdown b/source/_docs/automation/trigger.markdown index fd9d06520ae..3686190a619 100644 --- a/source/_docs/automation/trigger.markdown +++ b/source/_docs/automation/trigger.markdown @@ -15,6 +15,8 @@ Triggers are what starts the processing of an automation rule. It is possible to ### {% linkable_title Event trigger %} Triggers when an event is being processed. Events are the raw building blocks of Home Assistant. You can match events on just the event name or also require specific event data to be present. +Events can be fired by components or via the API. There is no limitation to the types. A list of built-in events can be found [here](/docs/configuration/events/). + ```yaml automation: trigger: @@ -24,7 +26,22 @@ automation: event_data: mood: happy ``` -For example, to carry out actions when Home Assistant starts, you can use `event_type: homeassistant_start`. See other 'events' supported by Home Assistant [here](https://home-assistant.io/topics/events/). + +

    + Starting 0.42, it is no longer possible to listen for event `homeassistant_start`. Use the 'homeassistant' platform below instead. +

    + +### {% linkable_title Home Assistant trigger %} + +Use this platform to trigger when Home Assistant starts up and shuts down. + +```yaml +automation: + trigger: + platform: homeassistant + # Event can also be 'shutdown' + event: start +``` ### {% linkable_title MQTT trigger %} Triggers when a specific message is received on given topic. Optionally can match on the payload being sent over the topic. @@ -62,7 +79,7 @@ automation: trigger: platform: state entity_id: device_tracker.paulus, device_tracker.anne_therese - # Optional + # Optional from: 'not_home' to: 'home' @@ -105,6 +122,8 @@ automation: value_template: "{% raw %}{% if is_state('device_tracker.paulus', 'home') %}true{% endif %}{% endraw %}" ``` +[template]: /docs/configuration/templating/ + ### {% linkable_title Time trigger %} Time can be triggered in many ways. The most common is to specify `after` and trigger at a specific point in time each day. Alternatively, you can also match if the hour, minute or second of the current time has a specific value. You can prefix the value with a `/` to match whenever the value is divisible by that number. You cannot use `after` together with hour, minute or second. diff --git a/source/_includes/asides/docs_navigation.html b/source/_includes/asides/docs_navigation.html index 771ac9b3035..5839ef04b86 100644 --- a/source/_includes/asides/docs_navigation.html +++ b/source/_includes/asides/docs_navigation.html @@ -41,9 +41,14 @@
  • {% active_link /docs/configuration/secrets/ Storing Secrets %}
  • {% active_link /docs/configuration/templating/ Templating %}
  • {% active_link /docs/configuration/group_visibility/ Group Visibility %}
  • +
  • {% active_link /docs/configuration/platform_options/ Entity component platform options %}
  • + + +
  • + Core objects +
    • {% active_link /docs/configuration/events/ Events %}
    • {% active_link /docs/configuration/state_object/ State Objects %}
    • -
    • {% active_link /docs/configuration/platform_options/ Entity component platform options %}
  • From 8e42c08fbf7f468784b12464bf90044db35f68be Mon Sep 17 00:00:00 2001 From: happyleavesaoc Date: Sat, 8 Apr 2017 18:49:26 -0400 Subject: [PATCH 37/38] add crimereports doc (#2062) --- .../_components/sensor.crimereports.markdown | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 source/_components/sensor.crimereports.markdown diff --git a/source/_components/sensor.crimereports.markdown b/source/_components/sensor.crimereports.markdown new file mode 100644 index 00000000000..24b7bdd854a --- /dev/null +++ b/source/_components/sensor.crimereports.markdown @@ -0,0 +1,101 @@ +--- +layout: page +title: "Crime Reports" +description: "Instructions on how to integrate CrimeReports.com into Home Assistant." +date: 2017-02-16 11:00 +sidebar: true +comments: false +sharing: true +footer: true +ha_category: Sensor +featured: false +ha_release: 0.39 +ha_iot_class: "Local Polling" +--- + +The `crimereports` sensor allows one to track reported incidents occurring in a Home Assistant zone. Incidents include anything reported to [Crime Reports](http://crimereports.com). Your regional emergency services may or may not report data. The sensor only counts incidents from the current day. + +## Configuration + +To enable this sensor, add the following lines to your `configuration.yaml`. Your `zone` should be of sufficient size to capture incidents in your area. Your `home` zone is probably too small. + +```yaml +zone: + - name: neighborhood + latitude: + longitude: + radius: + +sensor: + - platform: crimereports + zone: neighborhood +``` + +Configuration options for the Crime Reports Sensor: + +- **zone** (*Required*): The zone to monitor. +- **include** (*Optional*): List of incident types to include. +- **exclude** (*Optional*): List of incident types to exclude. +- **update_inverval** (*Optional*): Minimum time interval between updates. Default is 30 minutes. Supported formats: + - `update_interval: 'HH:MM:SS'` + - `update_interval: 'HH:MM'` + - Time period dictionary, e.g.: +
    update_interval:
    +        # At least one of these must be specified:
    +        days: 0
    +        hours: 0
    +        minutes: 3
    +        seconds: 30
    +        milliseconds: 0
    +    
    + +## Notes + +### Area + +Crime Reports captures all incidents in a region defined by a square shape. Home Assistant zones are circular. Therefore, the region defined by a Home Assistant zone in a Crime Reports context is a square that is big enough to fit the zone circle. Practically, this means some incidents may be captured that are outside your zone. + +### Incident Types + +You can explicitly include or exclude incident types. Specifying `include`s restricts the incidents to those types. Specifying `exclude`s will return all incident types except those specified. + +These incident types are available: + +- Alarm +- Arson +- Assault +- Assault with Deadly Weapon +- Breaking & Entering +- Community Policing +- Death +- Disorder +- Drugs +- Emergency +- Family Offense +- Fire +- Homicide +- Kidnapping +- Liquor +- Missing Person +- Other +- Other Sexual Offense +- Pedestrian Stop +- Proactive Policing +- Property Crime +- Property Crime Commercial +- Property Crime Residential +- Quality of Life +- Robbery +- Sexual Assault +- Sexual Offense +- Theft +- Theft from Vehicle +- Theft of Vehicle +- Traffic +- Vehicle Recovery +- Vehicle Stop +- Weapons Offense + +### Events + +The `crimealerts` sensor fires a `crimealerts_incident` event when a new incident is detected, including the type, description, time, location, and coordinates of the incident. From f0b5f37b60787c62e1c1c042f99fd1fb2f1372d5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 8 Apr 2017 16:20:52 -0700 Subject: [PATCH 38/38] Release 0.42 --- _config.yml | 6 +- .../_components/sensor.crimereports.markdown | 4 +- source/_components/sensor.lyft.markdown | 2 +- ...s--lockitron-locks--total-connect.markdown | 361 ++++++++++++++++++ source/images/blog/2017-04-0.42/social.png | Bin 0 -> 38221 bytes 5 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 source/_posts/2017-04-08-eddystone-beacons--lockitron-locks--total-connect.markdown create mode 100644 source/images/blog/2017-04-0.42/social.png diff --git a/_config.yml b/_config.yml index 65c2c381813..07af064aef6 100644 --- a/_config.yml +++ b/_config.yml @@ -138,10 +138,10 @@ social: # Home Assistant release details current_major_version: 0 -current_minor_version: 41 +current_minor_version: 42 current_patch_version: 0 -date_released: 2017-03-25 +date_released: 2017-04-08 # Either # or the anchor link to latest release notes in the blog post. # Must be prefixed with a # and have double quotes around it. -#patch_version_notes: "#release-0411---march-xx" +patch_version_notes: "#" diff --git a/source/_components/sensor.crimereports.markdown b/source/_components/sensor.crimereports.markdown index 24b7bdd854a..03cfec3675f 100644 --- a/source/_components/sensor.crimereports.markdown +++ b/source/_components/sensor.crimereports.markdown @@ -9,8 +9,8 @@ sharing: true footer: true ha_category: Sensor featured: false -ha_release: 0.39 -ha_iot_class: "Local Polling" +ha_release: 0.42 +ha_iot_class: "Cloud Polling" --- The `crimereports` sensor allows one to track reported incidents occurring in a Home Assistant zone. Incidents include anything reported to [Crime Reports](http://crimereports.com). Your regional emergency services may or may not report data. The sensor only counts incidents from the current day. diff --git a/source/_components/sensor.lyft.markdown b/source/_components/sensor.lyft.markdown index bcb72bc278e..c86b811e161 100644 --- a/source/_components/sensor.lyft.markdown +++ b/source/_components/sensor.lyft.markdown @@ -10,7 +10,7 @@ footer: true logo: lyft.png ha_category: Transport ha_iot_class: "Cloud Polling" -ha_release: 0.42 +ha_release: 0.41 --- diff --git a/source/_posts/2017-04-08-eddystone-beacons--lockitron-locks--total-connect.markdown b/source/_posts/2017-04-08-eddystone-beacons--lockitron-locks--total-connect.markdown new file mode 100644 index 00000000000..f16accbfb09 --- /dev/null +++ b/source/_posts/2017-04-08-eddystone-beacons--lockitron-locks--total-connect.markdown @@ -0,0 +1,361 @@ +--- +layout: post +title: "Home Assistant 0.42: Eddystone Beacons, Lockitron locks and Total Connect alarm systems" +description: "Tons of bug fixes, performance increasements and " +date: 2017-04-08 08:04:05 +0000 +date_formatted: "April 8, 2017" +author: Paulus Schoutsen +author_twitter: balloob +comments: true +categories: Release-Notes +og_image: /images/blog/2017-04-0.42/social.png +--- + +
    + +It's time for Home Assistant 0.43. This release has been focused on refining the system and fixing a lot of bugs. We have also upgraded to the latest version of our HTTP library which should give us a significant boost serving files and API. + +On our social media front, we have crossed the 1000 likes on [our Facebook page][hass-fb]! Also on the social media front, the YouTube channel diyAutomate has been putting out a lot of great getting started videos about Home Assistant, [go check them out!][diyAutomate] + +Also want to take a moment to thank Austin Andrews aka [Templarian] for his [Material Design Icons][mli]. He is part of what makes Home Assistant so beautiful 🤗. + +[hass-fb]: https://www.facebook.com/homeassistantio +[diyAutomate]: https://www.youtube.com/c/diyautomate +[mli]: https://materialdesignicons.com/ +[Templarian]: https://github.com/templarian + +## New integrations + +- Lockitron locks ([@aarya123] - [#6805]) +- Met Office weather and sensor components ([@jacobtomlinson] - [#6742]) +- Total Connect alarm systems ([@wardcraigj] - [#6887]) +- Eddystone Beacon Temperature Sensor ([@citruz] - [#6789]) +- CrimeReports.com integration shows crimes around a location in the US ([@happyleavesaoc] - [#6966]) +- The Ring doorbell has been integrated further with the inclusion of binary sensors ([@tchellomello] - [#6520]) + + +## Breaking changes + +- We were incorrectly treating groups named `default_view` as default views. Make sure you set `view: true` in the config for these groups. [#251 (frontend)](https://github.com/home-assistant/home-assistant-polymer/pull/251) +- The last release introduced a revamped LIFX platform. We only realised after deploy that this version does not work on Windows. We have added the old LIFX implementation back as `lifx_legacy`. +- We added indexes to the database to speed up the history view. Initial boot can take a couple of minutes. Do not shut down while migration is occurring. [#6688] +- Z-Wave cover workaround has been removed. Use device config instead. [#6832] + +```yaml +zwave: + device_config: + cover.my_cover: + invert_openclose_buttons: true +``` + +- If you set an initial state for an automation, input_boolean, input_slider or input_select it will overrule over the previous state. [#6911] [#6924] +- Z-Wave rename node service parameter `entity_id` has been replaced with `node_id` to align parameters [#6938] +- Automations are now initialized when Home Assistant finishes starting up. This means that it is deprecated to listen for event `homeassistant_start`. Instead, use the new `homeassistant` automation platform. [#6936] + +```yaml +automation: + trigger: + platform: homeassistant + event: start + action: + service: light.turn_on +``` + +- The Ring component has moved the authentication to a dedicated ring component. [#6520] + +```yaml +ring: + username: !secret ring_username + password: !secret ring_password + +binary_sensor: + - platform: ring + monitored_conditions: + - ding + - motion + +sensor: + - platform: ring + monitored_conditions: + - battery + - last_activity + - last_ding + - last_motion + - volume +``` + +## All changes + +- Flux led update lib ([@danielhiversen] - [#6763]) +- Adding expire_after to mqtt sensor to expire outdated values ([@micw] - [#6708]) +- New indexes for states and recording_runs tables ([@m00dawg] - [#6688]) (breaking change) +- Fix flaky template test ([@armills] - [#6768]) +- Repair zwave sensor coverage ([@armills] - [#6764]) +- Version bump to 0.42.0.dev0 ([@balloob]) +- current temp could be none ([@turbokongen] - [#6759]) +- Typing error and update test ([@turbokongen] - [#6757]) +- Wink Aros Fixes ([@geekofweek] - [#6726]) +- Upgrade pydroid-ipcam to 0.7 ([@fabaff] - [#6772]) +- Upgrade psutil to 5.2.1 ([@fabaff] - [#6771]) +- Upgrade sleekxmpp to 1.3.2 ([@fabaff] - [#6773]) +- Tests for zwave workaround detection ([@armills] - [#6761]) +- Bugfix automation fire on bootstrap ([@pvizeli] - [#6770]) +- Homematic Fixes ([@danielperna84] - [#6769]) +- Fix wink siren ([@w1ll1am23] - [#6775]) +- Fix bridge-led support in limitlessled.py ([@quadportnick] - [#6776]) +- Wrong info in discovery schema ([@turbokongen] - [#6779]) +- switch.tplink: upgrade to the newest upstream release which adds support for plugs using the newer communication protocol ([@rytilahti] - [#6790]) +- Add switch to MQTT discovery ([@fabaff] - [#6733]) +- Update docstrings ([@fabaff] - [#6795]) +- Add optional unit of measurement ([@fabaff] - [#6796]) +- Upgrade zeroconf to 0.19.0 ([@fabaff] - [#6792]) +- Upgrade pysnmp to 4.3.5 ([@fabaff] - [#6793]) +- Platform for Munich public transport departure times ([@DavidMStraub] - [#6704]) +- Use string formatting and remove already global disabled pylint issue ([@fabaff] - [#6801]) +- Fix typo and update name ([@fabaff] - [#6809]) +- Upgrade matrix-client to 0.0.6 ([@fabaff] - [#6808]) +- Make get_snmp_data more robust ([@tantecky] - [#6798]) +- Add NVR support to Hikvision Binary Sensors ([@mezz64] - [#6807]) +- Update Insight parameters using the subscription data. ([@pavoni] - [#6782]) +- fix WOL in docker/jail ([@goto100] - [#6810]) +- Allow to monitor Windows hosts ([@fabaff] - [#6803]) +- lights/hue: use device class for on/off devices like the osram lightify plug ([@jannau] - [#6817]) +- [switch.wemo] Fix mW to kW conversion. ([@lwis] - [#6826]) +- yeelight: adjust supported features on update() ([@rytilahti] - [#6799]) +- Updated pubnubsub-handler version ([@w1ll1am23] - [#6829]) +- Remove zwave cover invert workaround. Use config instead. ([@andrey-git] - [#6832]) (breaking change) +- history_stats: Fix schema, as `state` can be arbitrary string ([@leppa] - [#6753]) +- Rflink group commands ([@aequitas] - [#5969]) +- Updating Alarm.com Component for async and no Selenium ([@Xorso] - [#6752]) +- Add voluptuous config validation to scenes ([@MartinHjelmare] - [#6830]) +- Integration with lockitron ([@aarya123] - [#6805]) (new-platform) +- [switch.wemo] Fix today_energy_kwh calculation. ([@lwis] - [#6846]) +- Locative tests to use aiohttp test utils ([@balloob] - [#6838]) +- Convert Alexa tests to use aiohttp test utils ([@balloob] - [#6839]) +- Handle initial event after entity is instantiated. ([@aequitas] - [#6760]) +- Lifx legacy ([@amelchio] - [#6847]) (new-platform) +- aiohttp 2 ([@balloob] - [#6835]) +- Fix configuration setup ([@bdurrer] - [#6853]) +- Add option to disable automatic add for lights and sensors. ([@aequitas] - [#6852]) +- Update aioHTTP to 2.0.5 ([@pvizeli] - [#6856]) +- use change light level to avoid variable ramp speeds ([@wardcraigj] - [#6860]) +- Handle aiohttp task cancellation better ([@balloob] - [#6862]) +- Introduced Ring binary sensors and refactored Ring component ([@tchellomello] - [#6520]) (breaking change) (new-platform) +- Upgrade sendgrid to 3.6.5 ([@fabaff] - [#6866]) +- Upgrade sphinx-autodoc-typehints to 1.2.0 ([@fabaff] - [#6865]) +- Added Met Office weather and sensor components ([@jacobtomlinson] - [#6742]) (new-platform) +- Upgrade speedtest-cli to 1.0.3 ([@fabaff] - [#6867]) +- Bumped amcrest module to 1.1.5 ([@tchellomello] - [#6872]) +- Upgrade pytz to 2017.02 ([@fabaff] - [#6875]) +- Upgrade aiohttp_cors to 0.5.2 ([@fabaff] - [#6874]) +- Upgrade sqlalchemy to 1.1.8 ([@fabaff] - [#6873]) +- added support for Fibaro FGR-222 (similar to FGRM-222) ([@ChristianKuehnel] - [#6890]) +- Fluxled ([@danielhiversen] - [#6892]) +- Fix Tado climate set off mode ([@wmalgadey] - [#6848]) +- Fox UMP volume set ([@danieljkemp] - [#6904]) +- Move examples out ([@balloob] - [#6908]) +- Update README.rst ([@balloob]) +- Makes amcrest.sensor to handle properly the scan_interval option. ([@tchellomello] - [#6885]) +- Make sensor.ring to handle scan_interval option as expected. ([@tchellomello] - [#6886]) +- Eliminate needless async_add_job invocation of async_add_devices ([@nugget] - [#6864]) +- Onkyo update ([@danieljkemp] - [#6906]) +- Fix for #6691 Neato Connection error handling ([@turbokongen] - [#6731]) +- Adds support for the PlugInDimmer hardware ([@gurumitts] - [#6915]) +- Support for zwave light transitions ([@armills] - [#6868]) +- Bump pyHik library version to support more cameras ([@mezz64] - [#6921]) +- Update vera cover refresh logic ([@pavoni] - [#6897]) +- Update frontend ([@balloob]) +- Automation: initial state > restore state ([@balloob] - [#6911]) (breaking change) +- Upgrade flux_led to 0.17 ([@danielhiversen] - [#6929]) +- Upgrade paho-mqtt to 1.2.1 ([@fabaff] - [#6928]) +- Upgrade distro to 1.0.4 ([@fabaff] - [#6926]) +- Upgrade Sphinx to 1.5.4 ([@fabaff] - [#6927]) +- Allow token authentication for 'hook' switch component ([@KlaasH] - [#6922]) +- WIP - Fix bug in state handling in Vera Switch and Light ([@pavoni] - [#6931]) +- total connect alarm support ([@wardcraigj] - [#6887]) (new-platform) +- Initial state over restore state ([@balloob] - [#6924]) (breaking change) +- Eddystone Beacon Temperature Sensor ([@citruz] - [#6789]) (new-platform) +- Add android ip webcam support for aiohttp2 ([@pvizeli] - [#6940]) +- Bump pywemo version. Fixes Osram/Sylvania Lightify tunable white bulbs. ([@pavoni] - [#6946]) +- Clean artifacts after running Ring tests. ([@tchellomello] - [#6944]) +- Rename zwave nodes by node ID instead of entity ID ([@armills] - [#6938]) (breaking change) +- Report proper features in mqtt_json light ([@jawilson] - [#6941]) +- Add multi phone numbers support ([@titilambert] - [#6605]) +- Upgrade Sphinx to 1.5.5 ([@fabaff] - [#6947]) +- Upgrade py-cpuinfo to 3.0.0 ([@fabaff] - [#6948]) +- Fix automations listening to HOMEASSISTANT_START ([@balloob] - [#6936]) (breaking change) +- Fix startup of sonos / snapshot handling / error handling ([@pvizeli] - [#6945]) +- Upgrade mysensors dep and callbacks ([@MartinHjelmare] - [#6950]) +- Added average temperature for the day before and the current period ([@diogos88] - [#6883]) +- Upgrade sqlalchemy to 1.1.9 ([@fabaff] - [#6955]) +- Update for 0.42 ([@fabaff]) +- Initial import for HassIO ([@pvizeli] - [#6935]) (new-platform) +- light.yeelight: catch i/o related exceptions from the backend lib ([@rytilahti] - [#6952]) +- Fix current_temperature is rounded ([@aufano] - [#6960]) +- Preserve customize glob order. ([@andrey-git] - [#6963]) +- Foscam Camera: Adding exception handling when fetching the camera image to avoid python exception errors when host is not reachable or rather any url error to camera ([@viswa-swami] - [#6964]) +- Crime Reports sensor ([@happyleavesaoc] - [#6966]) (new-platform) +- Update kodi for aiohttp2 ([@armills] - [#6967]) +- Bugfix time and task coro ([@pvizeli] - [#6968]) +- Fix control+c quitting HASS ([@balloob] - [#6974]) +- Update Emby for aiohttp v2 ([@mezz64] - [#6981]) +- switch.tplink: bump pyhs100 version requirement ([@rytilahti] - [#6986]) +- Warn if start takes a long time. ([@balloob] - [#6975]) +- Bump Amcrest module to 1.1.8 ([@tchellomello] - [#6990]) + +[#5969]: https://github.com/home-assistant/home-assistant/pull/5969 +[#6520]: https://github.com/home-assistant/home-assistant/pull/6520 +[#6605]: https://github.com/home-assistant/home-assistant/pull/6605 +[#6688]: https://github.com/home-assistant/home-assistant/pull/6688 +[#6704]: https://github.com/home-assistant/home-assistant/pull/6704 +[#6708]: https://github.com/home-assistant/home-assistant/pull/6708 +[#6726]: https://github.com/home-assistant/home-assistant/pull/6726 +[#6731]: https://github.com/home-assistant/home-assistant/pull/6731 +[#6733]: https://github.com/home-assistant/home-assistant/pull/6733 +[#6742]: https://github.com/home-assistant/home-assistant/pull/6742 +[#6752]: https://github.com/home-assistant/home-assistant/pull/6752 +[#6753]: https://github.com/home-assistant/home-assistant/pull/6753 +[#6757]: https://github.com/home-assistant/home-assistant/pull/6757 +[#6759]: https://github.com/home-assistant/home-assistant/pull/6759 +[#6760]: https://github.com/home-assistant/home-assistant/pull/6760 +[#6761]: https://github.com/home-assistant/home-assistant/pull/6761 +[#6763]: https://github.com/home-assistant/home-assistant/pull/6763 +[#6764]: https://github.com/home-assistant/home-assistant/pull/6764 +[#6768]: https://github.com/home-assistant/home-assistant/pull/6768 +[#6769]: https://github.com/home-assistant/home-assistant/pull/6769 +[#6770]: https://github.com/home-assistant/home-assistant/pull/6770 +[#6771]: https://github.com/home-assistant/home-assistant/pull/6771 +[#6772]: https://github.com/home-assistant/home-assistant/pull/6772 +[#6773]: https://github.com/home-assistant/home-assistant/pull/6773 +[#6775]: https://github.com/home-assistant/home-assistant/pull/6775 +[#6776]: https://github.com/home-assistant/home-assistant/pull/6776 +[#6779]: https://github.com/home-assistant/home-assistant/pull/6779 +[#6782]: https://github.com/home-assistant/home-assistant/pull/6782 +[#6789]: https://github.com/home-assistant/home-assistant/pull/6789 +[#6790]: https://github.com/home-assistant/home-assistant/pull/6790 +[#6792]: https://github.com/home-assistant/home-assistant/pull/6792 +[#6793]: https://github.com/home-assistant/home-assistant/pull/6793 +[#6795]: https://github.com/home-assistant/home-assistant/pull/6795 +[#6796]: https://github.com/home-assistant/home-assistant/pull/6796 +[#6798]: https://github.com/home-assistant/home-assistant/pull/6798 +[#6799]: https://github.com/home-assistant/home-assistant/pull/6799 +[#6801]: https://github.com/home-assistant/home-assistant/pull/6801 +[#6803]: https://github.com/home-assistant/home-assistant/pull/6803 +[#6805]: https://github.com/home-assistant/home-assistant/pull/6805 +[#6807]: https://github.com/home-assistant/home-assistant/pull/6807 +[#6808]: https://github.com/home-assistant/home-assistant/pull/6808 +[#6809]: https://github.com/home-assistant/home-assistant/pull/6809 +[#6810]: https://github.com/home-assistant/home-assistant/pull/6810 +[#6817]: https://github.com/home-assistant/home-assistant/pull/6817 +[#6826]: https://github.com/home-assistant/home-assistant/pull/6826 +[#6829]: https://github.com/home-assistant/home-assistant/pull/6829 +[#6830]: https://github.com/home-assistant/home-assistant/pull/6830 +[#6832]: https://github.com/home-assistant/home-assistant/pull/6832 +[#6835]: https://github.com/home-assistant/home-assistant/pull/6835 +[#6838]: https://github.com/home-assistant/home-assistant/pull/6838 +[#6839]: https://github.com/home-assistant/home-assistant/pull/6839 +[#6846]: https://github.com/home-assistant/home-assistant/pull/6846 +[#6847]: https://github.com/home-assistant/home-assistant/pull/6847 +[#6848]: https://github.com/home-assistant/home-assistant/pull/6848 +[#6852]: https://github.com/home-assistant/home-assistant/pull/6852 +[#6853]: https://github.com/home-assistant/home-assistant/pull/6853 +[#6856]: https://github.com/home-assistant/home-assistant/pull/6856 +[#6860]: https://github.com/home-assistant/home-assistant/pull/6860 +[#6862]: https://github.com/home-assistant/home-assistant/pull/6862 +[#6864]: https://github.com/home-assistant/home-assistant/pull/6864 +[#6865]: https://github.com/home-assistant/home-assistant/pull/6865 +[#6866]: https://github.com/home-assistant/home-assistant/pull/6866 +[#6867]: https://github.com/home-assistant/home-assistant/pull/6867 +[#6868]: https://github.com/home-assistant/home-assistant/pull/6868 +[#6872]: https://github.com/home-assistant/home-assistant/pull/6872 +[#6873]: https://github.com/home-assistant/home-assistant/pull/6873 +[#6874]: https://github.com/home-assistant/home-assistant/pull/6874 +[#6875]: https://github.com/home-assistant/home-assistant/pull/6875 +[#6883]: https://github.com/home-assistant/home-assistant/pull/6883 +[#6885]: https://github.com/home-assistant/home-assistant/pull/6885 +[#6886]: https://github.com/home-assistant/home-assistant/pull/6886 +[#6887]: https://github.com/home-assistant/home-assistant/pull/6887 +[#6890]: https://github.com/home-assistant/home-assistant/pull/6890 +[#6892]: https://github.com/home-assistant/home-assistant/pull/6892 +[#6897]: https://github.com/home-assistant/home-assistant/pull/6897 +[#6904]: https://github.com/home-assistant/home-assistant/pull/6904 +[#6906]: https://github.com/home-assistant/home-assistant/pull/6906 +[#6908]: https://github.com/home-assistant/home-assistant/pull/6908 +[#6911]: https://github.com/home-assistant/home-assistant/pull/6911 +[#6915]: https://github.com/home-assistant/home-assistant/pull/6915 +[#6921]: https://github.com/home-assistant/home-assistant/pull/6921 +[#6922]: https://github.com/home-assistant/home-assistant/pull/6922 +[#6924]: https://github.com/home-assistant/home-assistant/pull/6924 +[#6926]: https://github.com/home-assistant/home-assistant/pull/6926 +[#6927]: https://github.com/home-assistant/home-assistant/pull/6927 +[#6928]: https://github.com/home-assistant/home-assistant/pull/6928 +[#6929]: https://github.com/home-assistant/home-assistant/pull/6929 +[#6931]: https://github.com/home-assistant/home-assistant/pull/6931 +[#6935]: https://github.com/home-assistant/home-assistant/pull/6935 +[#6936]: https://github.com/home-assistant/home-assistant/pull/6936 +[#6938]: https://github.com/home-assistant/home-assistant/pull/6938 +[#6940]: https://github.com/home-assistant/home-assistant/pull/6940 +[#6941]: https://github.com/home-assistant/home-assistant/pull/6941 +[#6944]: https://github.com/home-assistant/home-assistant/pull/6944 +[#6945]: https://github.com/home-assistant/home-assistant/pull/6945 +[#6946]: https://github.com/home-assistant/home-assistant/pull/6946 +[#6947]: https://github.com/home-assistant/home-assistant/pull/6947 +[#6948]: https://github.com/home-assistant/home-assistant/pull/6948 +[#6950]: https://github.com/home-assistant/home-assistant/pull/6950 +[#6952]: https://github.com/home-assistant/home-assistant/pull/6952 +[#6955]: https://github.com/home-assistant/home-assistant/pull/6955 +[#6960]: https://github.com/home-assistant/home-assistant/pull/6960 +[#6963]: https://github.com/home-assistant/home-assistant/pull/6963 +[#6964]: https://github.com/home-assistant/home-assistant/pull/6964 +[#6966]: https://github.com/home-assistant/home-assistant/pull/6966 +[#6967]: https://github.com/home-assistant/home-assistant/pull/6967 +[#6968]: https://github.com/home-assistant/home-assistant/pull/6968 +[#6974]: https://github.com/home-assistant/home-assistant/pull/6974 +[#6975]: https://github.com/home-assistant/home-assistant/pull/6975 +[#6981]: https://github.com/home-assistant/home-assistant/pull/6981 +[#6986]: https://github.com/home-assistant/home-assistant/pull/6986 +[#6990]: https://github.com/home-assistant/home-assistant/pull/6990 +[@ChristianKuehnel]: https://github.com/ChristianKuehnel +[@DavidMStraub]: https://github.com/DavidMStraub +[@KlaasH]: https://github.com/KlaasH +[@MartinHjelmare]: https://github.com/MartinHjelmare +[@Xorso]: https://github.com/Xorso +[@aarya123]: https://github.com/aarya123 +[@aequitas]: https://github.com/aequitas +[@amelchio]: https://github.com/amelchio +[@andrey-git]: https://github.com/andrey-git +[@armills]: https://github.com/armills +[@aufano]: https://github.com/aufano +[@balloob]: https://github.com/balloob +[@bdurrer]: https://github.com/bdurrer +[@citruz]: https://github.com/citruz +[@danielhiversen]: https://github.com/danielhiversen +[@danieljkemp]: https://github.com/danieljkemp +[@danielperna84]: https://github.com/danielperna84 +[@diogos88]: https://github.com/diogos88 +[@fabaff]: https://github.com/fabaff +[@geekofweek]: https://github.com/geekofweek +[@goto100]: https://github.com/goto100 +[@gurumitts]: https://github.com/gurumitts +[@happyleavesaoc]: https://github.com/happyleavesaoc +[@jacobtomlinson]: https://github.com/jacobtomlinson +[@jannau]: https://github.com/jannau +[@jawilson]: https://github.com/jawilson +[@leppa]: https://github.com/leppa +[@lwis]: https://github.com/lwis +[@m00dawg]: https://github.com/m00dawg +[@mezz64]: https://github.com/mezz64 +[@micw]: https://github.com/micw +[@nugget]: https://github.com/nugget +[@pavoni]: https://github.com/pavoni +[@pvizeli]: https://github.com/pvizeli +[@quadportnick]: https://github.com/quadportnick +[@rytilahti]: https://github.com/rytilahti +[@tantecky]: https://github.com/tantecky +[@tchellomello]: https://github.com/tchellomello +[@titilambert]: https://github.com/titilambert +[@turbokongen]: https://github.com/turbokongen +[@viswa-swami]: https://github.com/viswa-swami +[@w1ll1am23]: https://github.com/w1ll1am23 +[@wardcraigj]: https://github.com/wardcraigj +[@wmalgadey]: https://github.com/wmalgadey diff --git a/source/images/blog/2017-04-0.42/social.png b/source/images/blog/2017-04-0.42/social.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c1941f030e9d94c66f3a1df042c4a7200fe1d8 GIT binary patch literal 38221 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

    5e2asvJ)vxBH(b6jI8r+1FKh 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 Mv87R!q5F;h035B&#sB~S literal 0 HcmV?d00001