Compare commits

..

271 Commits

Author SHA1 Message Date
Paulus Schoutsen
4ea71b0602 Merge pull request #17480 from home-assistant/rc
0.80.1
2018-10-15 16:10:50 +02:00
Paulus Schoutsen
708334c0c2 Bumped version to 0.80.1 2018-10-15 15:31:12 +02:00
Paulus Schoutsen
b5272f2bc7 Fix websocket API (#17471) 2018-10-15 15:30:21 +02:00
Pascal Vizeli
80867cc9b7 Bugfix eventstream with EOF on end (#17465) 2018-10-15 15:30:20 +02:00
Tommy Jonsson
f92b392a24 Fix hangout.send_message requiring data key (#17393) 2018-10-15 15:30:20 +02:00
Martin Berg
220054a6c3 Fix arm/disarm calls. (#17381) 2018-10-15 15:30:19 +02:00
Paulus Schoutsen
49a9b61f6f Update frontend to 20181014.0 2018-10-14 19:17:41 +02:00
Paulus Schoutsen
8eb4e77365 Merge pull request #17361 from home-assistant/rc
0.80.0
2018-10-12 16:57:52 +02:00
Paulus Schoutsen
cd29b47924 Bumped version to 0.80.0 2018-10-12 14:59:36 +02:00
Pascal Vizeli
edb3722abd Hass.io auth/sso part2 (#17324)
* Update discovery.py

* Create const.py

* Update auth.py

* Update const.py

* Update const.py

* Update http.py

* Update handler.py

* Update auth.py

* Update auth.py

* Update test_auth.py
2018-10-12 14:59:17 +02:00
Pascal Vizeli
bc036cc2fe Fix auth for hass.io (#17318)
* Update test_auth.py

* Update auth.py

* Update test_auth.py
2018-10-12 14:59:17 +02:00
Martin Hjelmare
8778b707f1 Allow tradfri groups for new imported entries (#17310)
* Clean up leftover config schema option

* Allow import groups via new config yaml setup

* Fix and add test

* Add a test without groups for legacy import

* Change default import groups to False

* Fix I/O in test
2018-10-12 14:59:16 +02:00
Alok Saboo
05ae8f9dd4 Fix samsung bug (#17285) 2018-10-12 14:59:16 +02:00
Nikolay Vasilchuk
d199f57aa8 Logbook: filter by entity and period (#17095)
* Filter logbook by entity_id

* Filter logbook by period

* Simple test

* houndci-bot review

* Tests

* Test fix

* Test Fix
2018-10-12 14:59:15 +02:00
Paulus Schoutsen
f47e080f37 Update translations 2018-10-12 14:58:48 +02:00
Paulus Schoutsen
cfc5ebbfb0 Update frontend 2018-10-12 14:58:23 +02:00
Paulus Schoutsen
fa3f6ca2c7 Bumped version to 0.80.0b5 2018-10-10 14:29:04 +02:00
Paul Annekov
1d78393680 fixed 'on_startup() takes 0 positional arguments but 1 was given' (#17295) 2018-10-10 14:26:34 +02:00
Pascal Vizeli
951d7154b8 Fix hassio discovery (#17275)
* Update discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Fix tests

* fix lint
2018-10-10 14:26:33 +02:00
Pascal Vizeli
3f28b30860 Hassio auth (#17274)
* Create auth.py

* Update auth.py

* Update auth.py

* Update __init__.py

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Add tests

* Update test_auth.py

* Update auth.py

* Update test_auth.py

* Update auth.py
2018-10-10 14:26:32 +02:00
Paulus Schoutsen
83dec7173c Update translations 2018-10-10 14:25:49 +02:00
Paulus Schoutsen
a8a21ee28d Bumped version to 0.80.0b4 2018-10-09 16:20:39 +02:00
Anders Melchiorsen
1a76603f53 Remove warning on script delay (#17264)
* Remove warning on script delay

* Use suppress
2018-10-09 16:20:31 +02:00
Steven Looman
089e15e046 Add defaults, fixing #17229 (#17261) 2018-10-09 16:20:31 +02:00
Sebastian Muszynski
b59d69f313 Fix ambient light state of the Philips Eyecare Lamp (Closes: #16269) (#17259) 2018-10-09 16:20:30 +02:00
Paulus Schoutsen
eb7db1f763 block external IP (#17248)
* block external IP

* Update __init__.py
2018-10-09 16:20:29 +02:00
Paulus Schoutsen
429f09deb3 Add a webhook automation trigger (#17246) 2018-10-09 16:20:29 +02:00
Paulus Schoutsen
4d3d51635d Bumped version to 0.80.0b3 2018-10-08 16:16:01 +02:00
Malte Franken
a372053eac updated georss-client library to 0.3 (#17239) 2018-10-08 16:15:40 +02:00
Paulus Schoutsen
2e120061b4 Guard for bad device info (#17238) 2018-10-08 16:15:40 +02:00
Paulus Schoutsen
3a6eac216c Fix SPC (#17236) 2018-10-08 16:15:39 +02:00
Otto Winter
6671cbb96d Fix potential MQTT discovery race condition (#17208)
* Fix potential MQTT discovery race condition

* Rename data key
2018-10-08 16:15:39 +02:00
Matt Schmitt
9e386938bb MyQ cover return unknown state if not available (#17207)
* Add additional supported states

* Use get method for lookup

* Return None if unable to get status
2018-10-08 16:15:38 +02:00
Paulus Schoutsen
6be52208fc Prevent accidental device reg override (#17136) 2018-10-08 16:15:38 +02:00
Paulus Schoutsen
bd4ff6fc21 Bumped version to 0.80.0b2 2018-10-07 23:33:46 +02:00
Martin Berg
5fcea074c4 Init sub-components using global var. (#17220) 2018-10-07 23:33:40 +02:00
Per Sandström
7369af0639 Verisure standard config for scan interval (#17192)
* verisure configurable polling

* fix indentation
2018-10-07 23:33:40 +02:00
Anders Melchiorsen
b872cb95c7 Upgrade aiolifx_effects to 0.2.1 (#17188) 2018-10-07 23:33:39 +02:00
cdce8p
3338ebd4c1 Bugfix switch flux - light service call (#17187)
* Bugfix switch flux - light service call

* Change x_val and y_val test
2018-10-07 23:33:38 +02:00
cdce8p
7b176aa7c9 Fix device_tracker service call & cleanup (#17173)
* Bugfix group service - device_tracker

* Cleanup
2018-10-07 23:33:38 +02:00
Paulus Schoutsen
c722091967 Fix data used for logbook (#17172)
* Fix data used for logbook

* Lint
2018-10-07 23:33:38 +02:00
Paulus Schoutsen
4cffef7f2b Update translations 2018-10-07 23:27:57 +02:00
Paulus Schoutsen
31b1b0c044 Update frontend to 20181007.0 2018-10-07 23:27:57 +02:00
Paulus Schoutsen
7a22fbe961 Bumped version to 0.80.0b1 2018-10-05 20:21:27 +02:00
Paulus Schoutsen
738089c57c Fix incorrect yaml in hangouts (#17169) 2018-10-05 20:21:23 +02:00
Paulus Schoutsen
88c0a92857 Bumped version to 0.80.0b0 2018-10-05 17:56:30 +02:00
Paulus Schoutsen
0c770520ed Update translations 2018-10-05 17:50:00 +02:00
Paulus Schoutsen
92e28067d8 Update frontend to 20181005.0 2018-10-05 17:49:27 +02:00
prophit987
d1636dab31 @danielhiversen as codeowner for Tibber (#17154) 2018-10-05 14:55:16 +02:00
prophit987
13aa935147 Discover Danfoss/devolo RS Room Sensor thermostat (#17153)
Allows the Danfoss/Devolo RS Room Sensor thermostat to be discovered as climate device in homeassistant.
This device is defined as GENERIC_TYPE_MULTILEVEL_SENSOR, and not GENERIC_TYPE_THERMOSTAT.
Ref: https://community.home-assistant.io/t/devolo-zwave-thermostat/58739
2018-10-05 14:39:10 +02:00
Paul Annekov
29c3f1618f Fix miflora connection errors during platform setup (#16798)
* possible fix for startup delay

* fixed reported issues

* moved update code into setup

* reverted to previous solution
2018-10-05 13:33:28 +02:00
cdce8p
37a47b5a59 Add faucet, shower, sprinkler, valve to HomeKit (#17145) 2018-10-05 12:43:50 +02:00
Julius Mittenzwei
2e62afabdc Added warning to HomeKit component (#16807)
* added warning if more then 100 devices are added to HomeKit
2018-10-05 12:32:26 +02:00
Rohan Kapoor
a8f5e8699a Fix zoneminder zms_url construction (#17150) 2018-10-05 10:30:08 +02:00
Lewis Juggins
4218efddcd Cleanly stop tradfri on shutdown (#17114)
* Tradfri shutdown fix

* Bump version

* Bump version

* Fix

* Derp

* Remove unnecessary shutdown event
2018-10-05 09:59:34 +02:00
Gerard
aec320dc19 Fix a typo (#17147) 2018-10-05 07:48:40 +02:00
Aaron Bach
acf684de05 Added OpenUV CODEOWNERS info (#17149) 2018-10-04 19:57:52 -06:00
Florian Klien
ce1e8f8ace YesssSMS handling more errors, upgrade to version 0.2.3 (#17052)
* YesssSMS handling more errors, upgrade to version 0.2.1

 - handling missing internet connection nicely
 - disabling login with non-working credentials (website locked account for 1 hour)
 - upgrade to new upstream version of YesssSMS

* notify.yessssms tests

* test requirements

* flake8 fix

* fixing tests, new upstream version 0.2.3

fixing tests based on requested changes, coverage

* removing unmotivated print

* passing exception to ConnectionError and SMSSendingError logger
2018-10-04 17:34:04 -04:00
Per Sandström
b55c7a5ba2 verisure configurable polling (#17144) 2018-10-04 21:41:02 +02:00
cdce8p
52ff232797 Bugfix invalid entity_config parameter HomeKit (#17143) 2018-10-04 20:37:04 +02:00
Paulus Schoutsen
769dda735d Remove discovery (#17070) 2018-10-04 16:04:44 +02:00
Ana Paula Gomes
02bf07d9df Add timeout and fix oscillations on Samsung TV component (#17102)
* Add timeout and fix oscillations

* Adjust code to py3.5.3

* Clean code
2018-10-04 16:02:14 +02:00
Georgi Kirichkov
b92b24e8a4 Webhook component - pass headers to webhook handler (#17091)
* Pass headers to webhook handler

* Refactors webhook component to post Request object instead of data

* Update webhook tests

* Cleanup webhook test and fix a bug in ifttt

* Address code review comments
2018-10-04 15:54:51 +02:00
Paulus Schoutsen
0cfbb9ce91 Allow config entry setup to raise not ready (#17135) 2018-10-04 15:53:50 +02:00
Tsvi Mostovicz
c9976718d4 Take timezone into consideration when calulating Zmanim. Partial fix for #16946 (#17131) 2018-10-04 15:51:56 +02:00
Jason Hu
b61a250321 Fix upnp component l10n error (#17132) 2018-10-04 15:50:42 +02:00
Alok Saboo
ae0dd33e2e Add update service to Google Travel Sensor (#17092)
* Add update service

* Update service name

* Register service only once

* Make hound happy
2018-10-04 14:02:30 +02:00
Daniel Høyer Iversen
0d93bf9a45 Update xiaomi lib (#17129) 2018-10-04 13:24:54 +02:00
Heiko Thiery
178bf736f6 Add new component fritzbox binary_sensor (#17057)
* Add new component fritzbox binary_sensor

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* fix failed flake8 test

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* add new file to .coveragerc

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* use wildcard to cover all platforms

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* remove polling because polling is true by default

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* add blank line to keep imports ordered

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* Minor changes
2018-10-04 12:16:27 +02:00
Paulus Schoutsen
a559c06d6b Make it easier for auth to consume newer formats (#17127) 2018-10-04 10:41:13 +02:00
Jerad Meisner
cc1891ef2b Add time created to persistent notifications. (#17121)
* Add time created to persistent notifications.

* UTC
2018-10-04 10:24:14 +02:00
Daniel Høyer Iversen
05d8c57212 Tibber component and notify (#17062)
* Refactor tibber, and Tibber notify

* update Tibber lib.

* tibber

* Tibber coveragerc

* Tibber upgrade lib

* style

* comments

* use async_get_service

* event
2018-10-04 09:29:49 +02:00
Adam Mills
3abdf217bb Homekit controller reconnect (#17060)
* Add threaded call_later helper

* Reconnect to device when connection fails

* Consolidate connection logs and warn on first
2018-10-04 09:25:05 +02:00
Martin Hjelmare
6a0c9a718e Fix sonos async use (#17099)
* Entry setup wasn't using the async api. Fix this by using correct
  async api.s
* Also use new async executor scheduler in async_added_to_hass.
2018-10-04 09:20:20 +02:00
Ville Skyttä
abd329d707 Upgrade pytest to 3.8.2 (#17125) 2018-10-04 09:03:31 +02:00
Aaron Bach
04fdde0e86 Bumps simplisafe-python to 3.1.2 (#16931)
* Bumps simplisafe-python to 3.0.4

* Updated requirements

* Refresh token logic added

* Member-requested changes

* Removed unused import

* Updated CODEOWNERS

* Bump library to 3.1.2
2018-10-03 21:03:29 -06:00
Michael Wei
2b3019bdf4 Support multiple accounts in Tile, use device identifiers (#17108)
*  Update tile to support multiple accounts

* 🎨 fix indent

* 🐛 fix format string

* 🎨 use .format

* 🎨 fix line indent
2018-10-03 17:22:21 -06:00
Diogo Gomes
cf0147098a Merge pull request #16300 from StevenLooman/igd
Adds discovery and config flow
Breaking change: no longer possible to map ports other than the port used by Home Assistant
2018-10-03 22:55:01 +01:00
mvn23
aeb21596a0 Fix counter restore. (#17101)
Add config option to disable restore (always use initial value on restart).
Add unit tests for restore config option.
2018-10-03 23:12:21 +02:00
Tsvi Mostovicz
cf5f02b347 Fix jewish calendar sensor with language set to english (#17104)
* Add failing testcase for issue #16830

* Fix for #16830
2018-10-03 18:43:25 +02:00
Michael Wei
467a59a6ed Change Tile icon to view-grid (#17098) 2018-10-03 09:59:11 -06:00
Kevin Fronczak
da622abb79 Adding myself as blink codeowner (#17096) 2018-10-03 17:04:31 +02:00
David Bilay
16cbc2d07f Add weather condition code to OpenWeatherMap sensor (#17093) 2018-10-03 16:15:45 +02:00
Anders Melchiorsen
952a1b3513 Smaller steps for Sonos volume up/down (#17080) 2018-10-03 15:09:05 +02:00
Anders Melchiorsen
a5402739b7 Keep the repeat mode when setting Sonos shuffle mode (#17083)
* Keep the repeat mode when setting Sonos shuffle mode

* Fix test
2018-10-03 14:50:13 +02:00
Pascal Vizeli
704c9d8582 Add support for Hass.io discovery feature for Add-ons (#17035)
* Update handler.py

* Update __init__.py

* Update handler.py

* Update __init__.py

* Create discovery.py

* Update handler.py

* Update discovery.py

* Update __init__.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update struct

* Update handler.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update __init__.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update discovery.py

* Update __init__.py

* Update discovery.py

* fix lint

* Update discovery.py

* cleanup old discovery

* Update discovery.py

* Update discovery.py

* Fix lint

* Fix tests

* Write more tests with new functions

* Update test_handler.py

* Create test_discovery.py

* Update conftest.py

* Update test_discovery.py

* Update conftest.py

* Update test_discovery.py

* Update conftest.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Update test_discovery.py

* Fix test

* Add test

* fix lint

* Update handler.py

* Update discovery.py

* Update test_discovery.py

* fix lint

* Lint
2018-10-03 13:10:38 +02:00
David Peterson
2e5eb4d9dc Add optional headers configuration for scrape (#17085) 2018-10-03 12:47:38 +02:00
Steven Looman
5d693277f0 Fix stale docstrings 2018-10-03 11:27:38 +02:00
Steven Looman
3cb20c7b4d Changes after review by @MartinHjelmare 2018-10-03 11:08:32 +02:00
Paulus Schoutsen
4210835dcd Async response all the things (#17073)
* Use async_response

* Update device_registry.py
2018-10-03 07:53:54 +02:00
Dan Cinnamon
15a160a630 Bump pyenvisalink (#17086) 2018-10-03 06:28:08 +02:00
Kevin Fronczak
c78850a983 Overhaul of Blink platform (#16942)
* Using new methods for blink camera

- Refactored blink platform (breaking change)
- Camera needs to be uniquely enabled in config from now on
- Added motion detection enable/disable to camera platform

* Fix motion detection

- bumped blinkpy to 0.8.1
- Added wifi strength sensor

* Added platform schema to sensor

- Added global variables for brand and attribution to main platform

* Removed blink binary sensor

* Add alarm control panel

* Fixed dependency, added alarm_home

* Update requirements

* Fix lint errors

* Updated throttle times

* Add trigger_camera service (replaced snap_picture)

* Add refresh after camera trigger

* Update blinkpy version

* Wait for valid camera response before returning image

- Motion detection now working!

* Updated for new blinkpy 0.9.0

* Add refresh control and other fixes for new blinkpy release

* Add save video service

* Pushing to force bot to update

* Changed based on first review

- Pass blink as BLINK_DATA instead of DOMAIN
- Remove alarm_arm_home from alarm_control_panel
- Re-add discovery with schema for sensors/binar_sensors
- Change motion_detected to a binary_sensor
- Added camera_armed binary sensor
- Update camera device_state_attributes rather than state_attributes

* Moved blink.py to own folder. Added service hints.

* Updated coveragerc to reflect previous change

* Register services with DOMAIN

- Change device add for loop order in binary_sensor

* Fix lint error

* services.async_register -> services.register
2018-10-03 04:17:14 +02:00
Fabian Affolter
8e3a70e568 Upgrade youtube_dl to 2018.09.26 (#17079) 2018-10-02 22:31:59 +02:00
Thomas Lovén
06340c9875 Allow no movement in vamera.onvif_ptz service (#17065) 2018-10-02 14:36:28 +02:00
Paulus Schoutsen
31dd327c59 Catch possible errors from tradfri (#17068)
* Catch possible errors from tradfri

* Update config_flow.py
2018-10-02 14:35:43 +02:00
Paulus Schoutsen
38e2926a48 Update translations 2018-10-02 14:33:47 +02:00
Paulus Schoutsen
19722a0ef8 bump frontend to 20181002.0 2018-10-02 14:33:30 +02:00
Paulus Schoutsen
a6f8c3f662 Add logging to light updates (#17069) 2018-10-02 13:33:16 +02:00
Thomas Lovén
11d5671ee0 De-syncing binary_sensor.ping (#17056)
* Quick and dirty asyncing of binary_sensor.ping

* Minor changes
2018-10-02 11:43:34 +02:00
Paulus Schoutsen
20601cfc2d Merge branch 'master' into dev 2018-10-02 11:19:25 +02:00
Paulus Schoutsen
07972c84a1 Merge pull request #17067 from home-assistant/rc
0.79.3
2018-10-02 11:17:14 +02:00
cdce8p
7f0a50ce31 async_create_task (#17059)
* async_create_task

* Update google.py
2018-10-02 11:03:09 +02:00
Paulus Schoutsen
03845ef490 Lint 2018-10-02 10:35:15 +02:00
Paulus Schoutsen
37706c2731 Lint 2018-10-02 10:35:00 +02:00
Aaron Bach
71e3047f5c OpenUV: Fixed issue with missing protection window data (#17051) 2018-10-02 10:34:12 +02:00
Charles Garwood
0954eefa9f MJPEG Camera Log Filter Fixes (#17050)
* Move filter to setup platform

* pylint
2018-10-02 10:24:44 +02:00
cdce8p
90f71261c5 Remove service helper (8) (#17055)
* Updated keyboard

* Updated microsoft_face

* Updated ffmpeg

* Updated logger

* Updated components/__init__.py
2018-10-02 10:23:37 +02:00
Malte Franken
13af61e103 GeoRSS events sensor refactored (#16939)
* refactored geo_rss_events sensor to make use of new georss-client library that handles the communication with the rss feed

* fixed lint error
2018-10-02 10:20:51 +02:00
Nicko van Someren
b0b3620b2b Added working support for private storage (#16903)
* Fixed file corruption bugs in private storage code.

* Restoring fixed test case.

* Implemented test suite for utils/json.py

* Added new unit test cases for util/json.py

* Dixed formatting nags

* Fixed more nags from the Hound

* Added doc strings to some very short functions

* Fixing lint's complains about my choice of parts of speach. Sigh.

* Moved atomic save operations down into util/json.py so that all benefit.

Added extra clean-up code to ensure that temporary files are removed in
case of errors.
Updated emulated_hue unit tests to avoid errors.

* Apparently 'e' is not allows as a variable name for an exception...
2018-10-02 10:16:43 +02:00
Paulus Schoutsen
e07b6dfe0b Bumped version to 0.79.3 2018-10-02 09:57:01 +02:00
Paulus Schoutsen
3f5018459f Proactor policy fix (#17066)
* Proactor policy fix

* Backport Proactor policy for <py37
2018-10-02 09:56:54 +02:00
Jason Hu
2feab82396 Use Protractor loop in Windows (#17061)
* Use Protractor loop in Windows

* Add import sys
2018-10-02 09:56:53 +02:00
Paulus Schoutsen
1decba0052 Proactor policy fix (#17066)
* Proactor policy fix

* Backport Proactor policy for <py37
2018-10-02 09:55:37 +02:00
Jason Hu
1667481342 Use Protractor loop in Windows (#17061)
* Use Protractor loop in Windows

* Add import sys
2018-10-02 09:21:02 +02:00
Mathieu Velten
8e276295eb Update pynetgear to 0.4.2 (fix #14752) (#17064) 2018-10-02 09:14:07 +02:00
Sean Wilson
284d4d49c7 Add AquaLogic component (#16763)
* Add missing ups.status states.

* Add missing DISCHRG state.

* AquaLogic work-in-progress

* - Fix dependencies
- Switch updates

* Add support for aqualogic 0.8 features.

* Remove debugging.

* Switch to async updates rather than using polling.

* Rebase

* Fix lint errors

* Fix lint errors

* Fix lint errors

* Fix lint errors

* Fix lint errors.

* Bump aqualogic version to 0.11

* Update .coveragerc

* Remove integration-specific I/O

* Resolve code review issues.

* Fixed init() call.
2018-10-02 07:32:03 +02:00
cdce8p
c3eff5773b Remove alert service helper (#17038) 2018-10-02 00:33:45 +02:00
Daniel Perna
4d471622f6 Update pyhomematic to 0.1.50 (#17048) 2018-10-02 00:02:59 +02:00
SNoof85
90f2990b9e Support code 7 (#17047) 2018-10-01 22:18:56 +02:00
Charles Garwood
b197b8bab3 Suppress urllib3 header parsing error (#17042) 2018-10-01 20:39:40 +02:00
Fabian Affolter
a148f3e2a9 Mind the unit system (fixes #16819) (#16823) 2018-10-01 20:38:41 +02:00
Steven Looman
d732f8eca2 Changes after review by @MartinHjelmare 2018-10-01 19:26:43 +02:00
Nikolay Vasilchuk
b0c1c37cd5 Fix long update 'load_power' and 'in_use' for Xiaomi Zegbee Plug (#16915) 2018-10-01 18:00:48 +02:00
Anders Melchiorsen
4c36ffd0ef Remove error logging when Sonos shuffle_set is not available (#16921)
Error on set_shuffle with UPnP Error 712 received: Play mode not supported from 10.23.2.16
2018-10-01 17:58:04 +02:00
Paulus Schoutsen
fbc1c41673 Logbook context (#16937)
* Convert logbook to use attr

* Add context to events

* Enhance logbook

* Lint

* Fix logbook entry

* Don't use intermediary classes for logbook entries
2018-10-01 16:12:25 +02:00
Paulus Schoutsen
2e6346ca43 Break up websocket 2 (#17028)
* Break up websocket 2

* Lint+Test

* Lintttt

* Rename
2018-10-01 16:09:31 +02:00
Paulus Schoutsen
122e21a3c4 Merge pull request #17041 from home-assistant/rc
0.79.2
2018-10-01 15:50:25 +02:00
Paulus Schoutsen
33a54043e9 Bumped version to 0.79.2 2018-10-01 15:08:56 +02:00
Rohan Kapoor
d09ee8ac82 Fix switch.zoneminder name (#17026) 2018-10-01 15:08:50 +02:00
Paulus Schoutsen
1ca2e5226b Fix MQTT certificates (#16999) 2018-10-01 15:08:50 +02:00
cdce8p
b5e3d8c337 Async syntax (#17033)
* async-syntax-mqtt_room

* async-syntax-alert

* Additional fixes
2018-10-01 14:44:11 +02:00
Josh Anderson
f0fbdd6a26 Send headers with REST switch GET request (#17036) 2018-10-01 14:43:54 +02:00
cdce8p
e5c0e4336d Update coverage to exclude not tested file (#17039) 2018-10-01 14:41:35 +02:00
Paulus Schoutsen
c69a790ede Add Hass.io discovery to MQTT (#16962)
* Add Hass.io discovery to MQTT

* Update en.json

* Update __init__.py

* Update config_flow.py

* Update strings.json

* Update test_config_flow.py

* Lint

* Ensure we don't send bad data in config entry
2018-10-01 14:11:21 +02:00
David De Sloovere
5bc2e78ab4 Bump Enphase_Envoy dependency for older models (#17032) 2018-10-01 14:10:32 +02:00
Heiko Thiery
68bda1c732 Add new device attributes to fritzbox climate (#17027)
* Add new device attributes to fritzbox climate

With Fitz!OS 7 new parameters are introduced.

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>

* update requirements

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>
2018-10-01 12:53:25 +02:00
Timmo
3137099348 🔨 update errors (#17029) 2018-10-01 12:51:39 +02:00
Paulus Schoutsen
22a80cf733 Break up websocket component (#17003)
* Break up websocket component

* Lint
2018-10-01 11:21:00 +02:00
Fabian Affolter
9edf1e5151 Upgrade locationsharinglib to 3.0.3 (#17010)
* Upgrade locationsharinglib to 3.0.3

* Revert change from #16969
2018-10-01 10:55:16 +02:00
Rohan Kapoor
6159f8b0ce Fix switch.zoneminder name (#17026) 2018-10-01 10:53:20 +02:00
Ville Skyttä
d4cde2bfbf Upgrade huawei-lte-api to 1.0.16 (#16972) 2018-10-01 10:52:49 +02:00
Otto Winter
760f822dce Fix MQTT discovery (#17004) 2018-10-01 09:01:40 +02:00
cdce8p
b24f9f5dfa Async syntax 3/8 (#17017)
* Async syntax 3, device_tracker & fan & hassio & image_processing & input

* Pylint fixes
2018-10-01 08:59:45 +02:00
cdce8p
134eeecd65 Async syntax 4/8 (#17018)
* Async syntax 4, media_player & notify

* Pylint fixes
2018-10-01 08:58:21 +02:00
cdce8p
3b5e5cbcd6 Async syntax 5, light & lock & remote & scene & telegram & helpers (#17019) 2018-10-01 08:56:50 +02:00
cdce8p
9e4c8f45d6 Async syntax 6, sensor (#17020) 2018-10-01 08:55:43 +02:00
cdce8p
121dba659c Async syntax 7, switch & tts & vacuum (#17021) 2018-10-01 08:55:00 +02:00
cdce8p
9aaf11de8c Async syntax 8/8 (#17022)
* Async syntax 8

* Pylint fixes
2018-10-01 08:52:42 +02:00
Charles Garwood
ea7b1e4573 Update Z-Wave service descriptions to point to proper log file (#17024) 2018-10-01 08:50:32 +02:00
cdce8p
8444b9ba03 Async syntax 2, camera & climate & config (#17016) 2018-10-01 08:50:05 +02:00
cdce8p
38e371c5d9 Async syntax 1, alarm_control_panel & automation & binary_sensor (#17015) 2018-10-01 08:49:19 +02:00
sander76
750c96709e Homematic cloud device update fix (#17001) 2018-09-30 22:39:25 +02:00
Patrik
940d5fb2ee Add basic support for Tradfri switches (#17007)
* Initial commit

* Sockets have been moved to separate component

* Sockets have been moved to separate component

* Fix const PLATFORM_SCHEMA

* Fix unique id

* Fix async_create_task

* Fix PLATFORM_SCHEMA

* Fix typo

* Remove pylint disable
2018-09-30 22:22:07 +02:00
Paulus Schoutsen
0a2b266742 Fix MQTT certificates (#16999) 2018-09-30 21:36:27 +02:00
Steven Looman
f511920a04 Merge remote-tracking branch 'upstream/dev' into igd 2018-09-30 20:22:10 +02:00
Totoo
1b7bfec247 Google Maps supports battery level and charging. (#16969)
* Google Maps supports battery level and charging.

With 3.0.2 locationsharinglib now the battery level and the charging attributes are available.

* Update google_maps.py

fix too long line error

* Update google_maps.py

Fix multi line import, and line length limit

* Update gen_requirements_all.py

Add locationsharinglib to gen_requirements_all

* update requirements_all

* Last try to fix requirements_all...
2018-09-30 15:17:39 +02:00
Paulus Schoutsen
f5632a5da5 Add webhook + IFTTT example (#16817)
* Add webhook + IFTTT example

* Abort if not externally accessible

* Abort on local url

* Add description to create entry

* Make body optional

* Allow ifttt setup without config

* Add tests

* Lint

* Fix Lint + Tests

* Fix typing
2018-09-30 14:45:48 +02:00
Ville Skyttä
06d959ed43 Upgrade pytest to 3.8.1 (#16980) 2018-09-30 10:20:10 +02:00
Greg Laabs
7f47d601f1 Fix ISY blocking bug (#16978)
This fix results in `is_on` returning False if the state is unknown (which was a bug in 0.79).
2018-09-30 09:21:27 +02:00
Rohan Kapoor
8b1bdda0fa Bump zm-py to 0.0.4 (#16979) 2018-09-30 09:21:07 +02:00
Otto Winter
70ce9bb7bc Add pressure sensor device class (#16965)
* Add pressure sensor device class

* Undo github desktop line exclude
2018-09-29 22:01:04 +02:00
Otto Winter
45fdda3f5d Add unique_id to MQTT fan (#16949) 2018-09-29 21:22:57 +02:00
Anders Melchiorsen
caaf4f5694 Fix exception during history_stats startup (#16932)
* Fix exception during history_stats startup

* Do not track changes during startup

* Ignore args
2018-09-29 21:22:24 +02:00
Otto Winter
3ddad83a84 Add unique_id to MQTT cover (#16950)
* Add unique_id to MQTT cover

* Fix tests
2018-09-29 20:54:57 +02:00
Otto Winter
35b6064581 Convert fan component to config entry (#16951)
* Conver fan component to config entry

* Lint
2018-09-29 20:53:48 +02:00
Jason Hu
c600d28b6a Override unique_id of NestActivityZoneSensor (#16961) 2018-09-29 20:53:02 +02:00
Diogo Gomes
909c3bdd63 Merge pull request #16954 from abmantis/patch-2
Adds @abmantis to CODEOWNERS
2018-09-28 23:05:59 +01:00
Abílio Costa
4b8c38819e Add myself to CODEOWNERS 2018-09-28 22:47:29 +01:00
Jan van Helvoort
7d1960baba Add zwave.network_complete_some_dead event (#16894)
* Add zwave.network_complete_some_dead event

* add missing comma

* typo

* Add SIGNAL_AWAKE_NODES_QUERIED_SOME_DEAD Test

* Add blank lines

* fix linter warnings

Line too long

* remove trailing whitespace

* Change test signal

* Listen to other event
2018-09-28 19:14:57 +02:00
Otto Winter
af89e7c50f Move more MQTT platforms to config entries (#16918)
* Move more MQTT platforms to config entries

* Address comments
2018-09-28 16:57:17 +02:00
Anders Melchiorsen
720b05c301 Fix race between script delay and turn_off (#16923) 2018-09-27 22:08:09 -06:00
Otto Winter
c9b6567265 Remove discovered mqtt_json light entity when discovery is cleared (#16906)
* Remove discovered mqtt_json entity device when discovery topic is cleared

* Keep imports ordered
2018-09-28 00:25:51 +02:00
Greg Laabs
9abdbf3db6 Rachio component modernization (#16911)
Add `unique_id` to all rachio entities
Add platform discovery to rachio component
Move config options from switch.rachio platform to the rachio component
2018-09-27 23:17:15 +02:00
cdce8p
f879ac0993 Remove service helper (6) (#16920)
* Update automation

* Update group

* Async_create_task
2018-09-27 23:14:09 +02:00
cdce8p
70b901017f Remove service helper (5) (#16917)
* Update switch

* Update script

* Update light

* Fix tests

* Fix config/script hook

* Async_create_task

* Fix flux switch
2018-09-27 23:13:11 +02:00
Paulus Schoutsen
a7248d4574 Handle exception handling websocket command (#16927)
* Handle exception handling websocket command

* lint

* Lint2
2018-09-27 23:10:07 +02:00
Paulus Schoutsen
bac71d3d22 Update translations 2018-09-27 23:04:28 +02:00
Paulus Schoutsen
d77e88645e Bump frontend to 20180927.0 2018-09-27 23:04:03 +02:00
Otto Winter
2d104f95d7 Fix MQTT Config Entry Discovery (#16919) 2018-09-27 22:56:04 +02:00
Paulus Schoutsen
81e21b90c9 Fix auth redirect (#16914)
* Fix auth redirect

* Remove old test
2018-09-27 09:02:50 -07:00
Otto Winter
d1ad2cc225 Make MQTT platforms config entries (#16904)
* Make MQTT platforms config entries

* Fix tests

* Address Comment

* Rework tests

* Undo style auto-reformat style changes
2018-09-27 16:07:56 +02:00
zxdavb
8d65230a36 Add (EU-based) Honeywell evohome CH/DHW controller (#16427)
* Add support for Honeywell evohome CH/DHW systems

More flake8 corrections

Passes Flake8 tests

Almost passed flake8.pylint!

Passed all tox tests

Now it needs serious testing!

Almost ready to submit

BUGFIX: DHW state now functional

More improvements to available()

Solved the DHW temp units problem!

Last minute bug squash

to improve dicts merge

Trying to rebase

fixing more rbase errors

revert to creating HTTP_error_code internally for now

ready to submit PR

Added support for Honeywell evohome CH/DHW systems

* Updated requirements_test_all.txt

* Fix: D401 First line should be in imperative mood

* Remove _LOGGER.info (replace with _LOGGER.debug)

* raise PlatformNotReady when RequestException during setup()

* Revert some LOGGER.debug to LOGGER.warning

* Improved logging levels, and removed some unwanted comments

* Improvments to logging - additional self._status info

* BUGFIX: DHW wrongly showing available = False (and some other tweaks)

* Fix trailing whitespace

* Remove state_attributes override and API_VER code

* Removed heating zones, DHW and heuristics to reduce # lines of code

* Removed some more lines of code

* Removed unused configuration parameters

* Remove some more un-needed lines

* Removed more (uneeded) lines of code & fixed two minor typos

* Improvements to debug logging of available() = False

* Improvements to code, and code clean-up

* Corrected a minor typo

* A small tidy up

* reduces precision of emulated temps floats to 0.1

* Some code improvements as suggested by JeardM

* Rewrite of exception handler

* Removed another unwanted logging in properties

* Remove async_ version of various methods

* moved available heuristics to update()

* Cleanup of code, and re-work linter hints

* fixed a minor documentation typo

* scan_interval is now no longer a configurable option

* Change from Master/Slave to Parent/Child

* Removed the last of the slaves

* Removed the last of the masters

* Move -PARALLEL_UPDATES to .\climate\evohome.py'

* main code moved to climate/evohome.py

* merge EvoEntity into EvoController class

* remove should_poll (for now)

* woops! left a hint in

* removed icon

* only log a WARNING the first time available = False

* cleanup dodgy exception handling

* Tidy up exception handling

* Many changes as suggested by @MartinHjelmare, thanks

* remove hass from init, part 1

* use async_added_to_hass instead of dispatcher_connect

* remove hass from init, part 2 (done)

* add 1-2 arrays, and tidied up some comments

* from dispatcher to async_added_to_hass

* cleaned up some logging, and removed others

* Many changes as request by @MartinHjelmare

* Homage to the lint

* Changed to the HA of doing operating_mode

* Now using update_before_add=True

* reduced logging further still...

* fixed minor lint

* fix a small logic error

* Add device_state_attributes to track actual operating mode

* Clean up doc quotes caused by  previous changes

* Woops! removed some debug lines that shoudln't have stayed in

* Add a complete set of device_state_attributes

* Cleanup some constants

* Remove more legacy code

* domain_data to evo_data & this else should be a finally

* minor change for readability

* Minor change for readability #2

* removed unused code

* small tidy up - no code changes

* fix minor lint

* Correct URLs & descriptions in docstring

* whoops - fixed a typo in docstrings

* remove an unused line of cide & a small tidy-up
2018-09-27 13:29:44 +02:00
Blake Blackshear
2cc6263092 Add new services for set/refresh Z-Wave device values (#16638)
* Add services for getting and setting indicator values for Z-Wave

* Add service to manually refresh Z-Wave node value by value_id

* Remove refresh_indicator service

* Coerce to int

* Add generic set_node_value service

* Remove set_indicator service
2018-09-27 12:34:42 +02:00
emontnemery
ad79dc673d MQTT Light - Do not throw if property is missing from templated MQTT message (#16720)
* Do not throw if property is missing

* Render template once, add debug prints
2018-09-27 11:48:52 +02:00
Paulus Schoutsen
da3342f1aa Update new values coming in for dev registry (#16852)
* Update new values coming in for dev registry

* fix Lint+Test;2C
2018-09-27 11:26:58 +02:00
Anders Melchiorsen
29db43edb2 Ignore Xiaomi hub callbacks during setup (#16910) 2018-09-27 09:44:19 +02:00
Anders Melchiorsen
24e9c62fe7 Upgrade pysonos to 0.0.3 (#16901)
This version has downgraded/removed some logging that we then no
longer have to hide.
2018-09-27 01:09:30 +02:00
Anders Melchiorsen
81d4338b93 Upgrade aiolifx_effects to 0.2.0 (#16900) 2018-09-27 01:08:20 +02:00
Jason Hu
96e5acda1a Optimize Ring Sensors platform setup (#16886) 2018-09-26 15:38:13 -07:00
Anders Melchiorsen
726cf9b1c4 Remove unused import (#16909)
* Remove unused import

* Revert test usage
2018-09-27 00:21:29 +02:00
Paulus Schoutsen
631ecf578e Lint 2018-09-26 23:48:55 +02:00
Paulus Schoutsen
273a7af330 Prevent discovered Tradfri while already configured (#16891)
* Prevent discovered Tradfri while already configured

* Lint
2018-09-26 18:03:25 +02:00
cdce8p
4b674b1d16 Remove unused legacy test helper methods (#16893) 2018-09-26 18:03:13 +02:00
cdce8p
dd45e99302 Remove service helper (4) (#16892)
* Update media_player

* Update lock

* Update notify

* Update remote

* Update scene

* Update vacuum

* Remove timer helpers

* Removed unused legacy helpers
2018-09-26 18:02:05 +02:00
Paulus Schoutsen
d0ddc28f96 Revert file mode write_json (#16897) 2018-09-26 17:58:44 +02:00
Paulus Schoutsen
9ab8f78b19 Don't pass use_env=True (#16896) 2018-09-26 17:20:34 +02:00
Paulus Schoutsen
732009c668 Update translations 2018-09-26 15:39:20 +02:00
Paulus Schoutsen
d20e0f5c95 Update frontend to 20180926.0 2018-09-26 15:39:20 +02:00
cgtobi
98a4b1e9ac Update language strings (#16884) 2018-09-26 13:07:43 +02:00
Nikolay Vasilchuk
917df1af00 Telegram_bot polling support proxy_url and proxy_params (Fix #15746) (#16740)
* Telegram bot polling proxy support

* CI fix

* houndci-bot review fix

* houndci-bot review fix

* CI fix

* Review

* Update polling.py
2018-09-26 11:59:37 +02:00
Blake Blackshear
f13f723a04 Add bitwise operations as template helpers (#16833) 2018-09-26 11:57:16 +02:00
Jason Hu
75c372021d Fix example for long-lived access token WS API (#16882) 2018-09-26 11:20:48 +02:00
Nicko van Someren
e5861241c7 Added support for private storage. (#16878)
* Addded support for private storage.

Include 'private' flag parameters to the Store class and save_json function.
Updated various authentication and onboarding classes to use private stores.
Fixed unit test for emulated_hue which used a mock patch on save_json().

* Fixed Hound formatting issues not detected by local linting.
2018-09-26 10:24:32 +02:00
Paulus Schoutsen
e205092693 Revert incorrect check (#16883) 2018-09-26 10:15:49 +02:00
cdce8p
fa98a27df7 Remove service helper (2) (#16863)
* alarm_control_panel

* automation

* camera

* climate

* counter

* fan

* Add legacy notes

* Fix tests
2018-09-26 09:49:55 +02:00
Paulus Schoutsen
c899875abb Fix MQTT discovery (#16864)
* Fix MQTT discovery

* Update __init__.py
2018-09-26 09:38:50 +02:00
Charles Garwood
bab079f649 Add unique_id to Nest Sensors (#16869)
* Add unique_id

* Add device_info

* Fix typo

* Update __init__.py
2018-09-26 09:19:47 +02:00
Jason Hu
92a5068977 Use HA native OAuth2 flow for google assistant components (#16848)
* Use HA native OAuth2 flow for google assistant components

* Lint

* Force breaking changes

* Fix CONFIG_SCHEMA
2018-09-26 08:57:55 +02:00
Charles Garwood
3cba2e695c Device Registry Support for iOS Sensors (#16862)
* Add device_info property to iOS sensors for device registry

* Remove unused logger import

* Fix spacing

* lint

* Lint
2018-09-26 08:56:23 +02:00
cdce8p
bfa1c55803 Fix fan_init test (#16865)
* Fix fan_init test

* Readd __init__.py
2018-09-26 08:53:24 +02:00
Paulus Schoutsen
ba2b8512c5 Make ring sync again (#16866) 2018-09-26 08:52:22 +02:00
cdce8p
e2a56721d3 Remove service helper (3) (#16879)
* Update duckdns

* Update google_assistant

* Update group

* Update homematic

* Update image_processing

* Update input_boolean

* Update input_number

* Update input_select

* Update input_text
2018-09-26 08:50:05 +02:00
Martin Mois
672fc61bb2 aiohttp.ClientSession gets proxy information from HTTP_PROXY/HTTPS_PROXY (#16874) 2018-09-26 08:43:09 +02:00
Gerard
6490ec87f3 Upgrade to bimmer_connected 0.5.3 (#16877) 2018-09-26 08:24:59 +02:00
Daniel Høyer Iversen
dc102a96a9 Tibber realtime consumption, Tibber pulse (#16870)
* tibber real time data

* Tibber Pulse, realtime consumption

* update lib
2018-09-26 07:49:09 +02:00
cdce8p
b91a061cef Add missing __init__ test files (#16871) 2018-09-25 23:08:37 +02:00
cdce8p
7eaf8640d0 Update cover tests (#16832)
* Update test_group
* Update test_command_line
* Update test_demo
* Update test_mqtt
* Update test_template
* Remove cover service call helpers
2018-09-25 22:32:05 +02:00
Jedmeng
8e311686d0 Add support for Opple light (#16765)
* Add support for Opple light

* Update docstring

* review fix

* review fix

* review fix
2018-09-25 20:49:37 +02:00
Paulus Schoutsen
5a22e7d211 Fail if dirty (#16839)
* Fail if dirty

* Update check_dirty

* Update text

* Fix comment

* Add -e

* Update dirty script
2018-09-25 20:47:51 +02:00
Paulus Schoutsen
7de0e1e39a Add executor job (#16853) 2018-09-25 20:47:22 +02:00
emontnemery
4501bdb4a0 Remove discovered MQTT cover device when discovery topic is cleared (#16857) 2018-09-25 19:32:42 +02:00
emontnemery
4a265f37e0 Remove discovered MQTT fan device when discovery topic is cleared (#16858) 2018-09-25 19:32:31 +02:00
emontnemery
c3f58b8c74 Remove discovered MQTT lock device when discovery topic is cleared (#16859) 2018-09-25 19:32:25 +02:00
emontnemery
422ccc1a28 Remove discovered MQTT sensor device when discovery topic is cleared (#16860) 2018-09-25 19:32:16 +02:00
emontnemery
eb59f2dd3c Move MQTT discovery removal tests to platform test files (#16861) 2018-09-25 19:32:04 +02:00
Paulus Schoutsen
399040de46 Fix files left behind (#16855)
* Light demo test to not write entity registry

* Fix Manual MQTT alarm control panel
2018-09-25 17:19:46 +02:00
emontnemery
0dbfd77402 Remove discovered MQTT climate device when discovery topic is cleared (#16856) 2018-09-25 17:15:39 +02:00
Tommy Jonsson
bc8d323bdd Add image support to hangouts notifications (#16560)
* add image to services.yaml

* add image support

Add image support to hangouts notification.

* fix indents

* fix line length

* Add data schema

forgot schema

* fix linelength

* use is_allowed_path and better file error handling

* elif not else if

* fix logger error

* fixes

* fix travis errors/warnings

* remove trailing whitespace

* fix travis pylint naming

* new async style

* removed unused async_timeout

* change to image_file/url (#3)

* change to image_file/url

* removed whitespace

* forgot to remove unused urlparse import

* image_file/url in service help
2018-09-25 15:04:43 +02:00
Paulus Schoutsen
a1c914dfeb On removal, only unload config entry if loaded (#16844)
* On removal, only unload config entry if loaded

* Fix test
2018-09-25 14:29:13 +02:00
emontnemery
093285f92f Remove discovered MQTT binary_sensor device when discovery topic is cleared (#16826) 2018-09-25 14:25:03 +02:00
Paulus Schoutsen
9ea5afd109 Add unique ID and device info to Nest camera (#16846)
* Add unique ID and device info to Nest camera

* Remove sw version
2018-09-25 13:47:12 +02:00
Daniel Høyer Iversen
01925fdfff change unknown to None in Netatmo public (#16845) 2018-09-25 13:41:29 +02:00
Paulus Schoutsen
7840b1e387 Fix MQTT leaving files behind (#16840) 2018-09-25 12:22:27 +02:00
Paulus Schoutsen
e4898bb05c Allow MQTT discovery (#16842) 2018-09-25 12:22:14 +02:00
Paulus Schoutsen
f4974f58fe Config entry update data (#16843)
* WIP

* Allow updating data of a config entry
2018-09-25 12:21:11 +02:00
Paulus Schoutsen
2b2502c91c Support old tradfri config format (#16841) 2018-09-25 11:57:32 +02:00
Daniel Winks
4a4c07ac1b GitLab-CI sensor integration addition. (#16561)
* Updates to GitLab Sensor

* Updates to GitLab_CI sensor.

* Added GitLab_CI sensor.

* Updated interval to a more appropriate 300 seconds.

* Added GitLab_CI.py to ommitted files.

* Initial refactor to use python-gitlab PyPI module.

* Fixes to dict parsing.

* Updated required packages for GitLab_CI requirements.

* Updates and refactoring to more closely align with Home-Assistant standards.

* Moved import to init, removed unreachable requests exception.

* Removed references to STATE_UNKNOWN and replaced with None

* Removed extra whitespace

* Changed PLATFORM_SCHEMA and renamed add_devices.

Changed PLATFORM_SCHEMA to use SCAN_INTERVAL and add_devices to add_entities

* Added configurable name, changed logger and removed cruft.

* Removed _status to use _state instead, as both held same value.

* Fixed ATTR_BUILD_BRANCH, removed more extraneous cruft.

* Changed required config keys to dict[key] format.

* Removed extraneous CONF_SCAN_INTERVAL as it's already defined.
2018-09-25 11:18:23 +02:00
GP8x
03bce84c32 Add additional Netatmo public data sensors (#16671)
Update deps
2018-09-25 11:14:42 +02:00
Paulus Schoutsen
4f9fc9b39f Don't create entity registry in tests (#16838) 2018-09-25 10:16:30 +02:00
sander76
069b819679 Add unique_id to homematic_cloud (#16828)
* add unique_id

* add docstring and trigger travis
2018-09-25 10:15:03 +02:00
emontnemery
90197b6ec9 Remove discovered MQTT light device when discovery topic is cleared (#16824) 2018-09-25 09:19:04 +02:00
emontnemery
42790d3e97 Remove discovered MQTT alarm_control_panel device when discovery topic is cleared (#16825) 2018-09-25 08:44:14 +02:00
Paulus Schoutsen
e78f4d1b65 Extract lovelace to it's own component (#16816)
* Extract lovelace to it's own component

* Lint

* Update comment

* Lint

* Lint
2018-09-25 08:39:35 +02:00
Rohan Kapoor
354c8f3409 Bump zm-py to 0.0.3 (#16835) 2018-09-25 07:53:35 +02:00
Paulus Schoutsen
579b77ba4c Don't warn but info when on dev mode (#16831) 2018-09-25 07:52:10 +02:00
randellhodges
b52e8525ac Add mode (daily/hourly) to darksky (#16719)
* added daily mode to darksky and wind_bearing, ozone, and visibility

* Removed dew point and pressure until the standard is updated
2018-09-24 18:09:15 +02:00
Paulus Schoutsen
dc75db6376 Bumped version to 0.80.0.dev0 2018-09-24 12:15:47 +02:00
Steven Looman
6e01ea5929 Preserve compatibility with original upnp 2018-09-20 18:15:04 +02:00
Steven Looman
b72499a949 Fixes after rename 2018-09-18 20:22:33 +02:00
Steven Looman
b770acd9a7 Update requirements_all.txt 2018-09-18 20:21:52 +02:00
Steven Looman
5cb0c92e78 Fix discovery/config entry handlers 2018-09-17 22:25:32 +02:00
Steven Looman
a7a16e4317 Fix tracebacks 2018-09-17 22:15:44 +02:00
Steven Looman
c19665fed4 Rename igd to upnp 2018-09-17 22:10:18 +02:00
Steven Looman
6588dceadd Fix uppercase
Fix translation
2018-09-17 22:09:51 +02:00
Steven Looman
ca7911ec47 Set ports (hass -> hass) when no ports have been specified 2018-09-14 21:30:08 +02:00
Steven Looman
6433f2e2e3 Working on igd 2018-09-08 00:24:47 +02:00
Steven Looman
f4a54e2483 Changes after review 2018-09-03 21:16:45 +02:00
Steven Looman
85c40d29ee Linting 2018-09-02 17:03:31 +02:00
Steven Looman
a4a175440b Move ensure_domain_data 2018-09-02 16:40:39 +02:00
Steven Looman
8bec4a55d1 Working on igd 2018-09-01 21:20:15 +02:00
Steven Looman
50f63ed4c5 Fix not being able to re-add IGD when removed 2018-09-01 18:13:45 +02:00
Steven Looman
c9e34e236d Prevent error message when component is actually ok 2018-09-01 10:14:21 +02:00
Steven Looman
38318ed15f Ensure config_flow is imported 2018-09-01 10:09:22 +02:00
Steven Looman
553d3c0179 Merge remote-tracking branch 'upstream/dev' into igd 2018-09-01 10:01:12 +02:00
Steven Looman
20879726b0 Working on IGD 2018-08-30 17:41:11 +02:00
Steven Looman
3db766e2ec Merge remote-tracking branch 'upstream/dev' into igd 2018-08-29 21:19:27 +02:00
Steven Looman
1eac6408f5 Working on IGD 2018-08-29 21:19:04 +02:00
Steven Looman
e73f31d829 Merge remote-tracking branch 'upstream/dev' into igd 2018-08-24 15:25:07 +02:00
Steven Looman
839b58c600 Working on IGD 2018-08-17 21:28:29 +02:00
Steven Looman
71d00062e5 Upgrade to async_upnp_client 0.12.4 2018-08-17 21:25:08 +02:00
Steven Looman
80f98b9ea2 Fix message "Updating dlna_dmr media_player took longer than ..." 2018-08-16 22:14:13 +02:00
727 changed files with 15611 additions and 9157 deletions

View File

@@ -28,6 +28,9 @@ omit =
homeassistant/components/apple_tv.py
homeassistant/components/*/apple_tv.py
homeassistant/components/aqualogic.py
homeassistant/components/*/aqualogic.py
homeassistant/components/arduino.py
homeassistant/components/*/arduino.py
@@ -53,7 +56,7 @@ omit =
homeassistant/components/bbb_gpio.py
homeassistant/components/*/bbb_gpio.py
homeassistant/components/blink.py
homeassistant/components/blink/*
homeassistant/components/*/blink.py
homeassistant/components/bloomsky.py
@@ -105,8 +108,11 @@ omit =
homeassistant/components/envisalink.py
homeassistant/components/*/envisalink.py
homeassistant/components/evohome.py
homeassistant/components/*/evohome.py
homeassistant/components/fritzbox.py
homeassistant/components/switch/fritzbox.py
homeassistant/components/*/fritzbox.py
homeassistant/components/ecovacs.py
homeassistant/components/*/ecovacs.py
@@ -310,6 +316,9 @@ omit =
homeassistant/components/*/thinkingcleaner.py
homeassistant/components/tibber/*
homeassistant/components/*/tibber.py
homeassistant/components/toon.py
homeassistant/components/*/toon.py
@@ -510,6 +519,7 @@ omit =
homeassistant/components/light/lw12wifi.py
homeassistant/components/light/mystrom.py
homeassistant/components/light/nanoleaf_aurora.py
homeassistant/components/light/opple.py
homeassistant/components/light/osramlightify.py
homeassistant/components/light/piglow.py
homeassistant/components/light/rpi_gpio_pwm.py
@@ -620,7 +630,6 @@ omit =
homeassistant/components/notify/telstra.py
homeassistant/components/notify/twitter.py
homeassistant/components/notify/xmpp.py
homeassistant/components/notify/yessssms.py
homeassistant/components/nuimo_controller.py
homeassistant/components/prometheus.py
homeassistant/components/rainbird.py
@@ -679,6 +688,7 @@ omit =
homeassistant/components/sensor/fritzbox_netmonitor.py
homeassistant/components/sensor/gearbest.py
homeassistant/components/sensor/geizhals.py
homeassistant/components/sensor/gitlab_ci.py
homeassistant/components/sensor/gitter.py
homeassistant/components/sensor/glances.py
homeassistant/components/sensor/google_travel_time.py
@@ -687,6 +697,7 @@ omit =
homeassistant/components/sensor/haveibeenpwned.py
homeassistant/components/sensor/hp_ilo.py
homeassistant/components/sensor/htu21d.py
homeassistant/components/sensor/upnp.py
homeassistant/components/sensor/imap_email_content.py
homeassistant/components/sensor/imap.py
homeassistant/components/sensor/influxdb.py
@@ -709,6 +720,7 @@ omit =
homeassistant/components/sensor/mqtt_room.py
homeassistant/components/sensor/mvglive.py
homeassistant/components/sensor/nederlandse_spoorwegen.py
homeassistant/components/sensor/netatmo_public.py
homeassistant/components/sensor/netdata.py
homeassistant/components/sensor/netdata_public.py
homeassistant/components/sensor/neurio_energy.py
@@ -764,7 +776,6 @@ omit =
homeassistant/components/sensor/tank_utility.py
homeassistant/components/sensor/ted5000.py
homeassistant/components/sensor/temper.py
homeassistant/components/sensor/tibber.py
homeassistant/components/sensor/time_date.py
homeassistant/components/sensor/torque.py
homeassistant/components/sensor/trafikverket_weatherstation.py
@@ -772,7 +783,6 @@ omit =
homeassistant/components/sensor/travisci.py
homeassistant/components/sensor/twitch.py
homeassistant/components/sensor/uber.py
homeassistant/components/sensor/upnp.py
homeassistant/components/sensor/ups.py
homeassistant/components/sensor/uscis.py
homeassistant/components/sensor/vasttrafik.py

View File

@@ -41,6 +41,7 @@ homeassistant/components/hassio.py @home-assistant/hassio
# Individual components
homeassistant/components/alarm_control_panel/egardia.py @jeroenterheerdt
homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell
homeassistant/components/alarm_control_panel/simplisafe.py @bachya
homeassistant/components/binary_sensor/hikvision.py @mezz64
homeassistant/components/bmw_connected_drive.py @ChristianKuehnel
homeassistant/components/camera/yi.py @bachya
@@ -50,6 +51,7 @@ homeassistant/components/climate/sensibo.py @andrey-git
homeassistant/components/cover/group.py @cdce8p
homeassistant/components/cover/template.py @PhracturedBlue
homeassistant/components/device_tracker/automatic.py @armills
homeassistant/components/device_tracker/huawei_router.py @abmantis
homeassistant/components/device_tracker/tile.py @bachya
homeassistant/components/history_graph.py @andrey-git
homeassistant/components/light/lifx.py @amelchio
@@ -80,19 +82,21 @@ homeassistant/components/sensor/qnap.py @colinodell
homeassistant/components/sensor/sma.py @kellerza
homeassistant/components/sensor/sql.py @dgomes
homeassistant/components/sensor/sytadin.py @gautric
homeassistant/components/sensor/tibber.py @danielhiversen
homeassistant/components/sensor/upnp.py @dgomes
homeassistant/components/sensor/waqi.py @andrey-git
homeassistant/components/switch/tplink.py @rytilahti
homeassistant/components/vacuum/roomba.py @pschmitt
homeassistant/components/xiaomi_aqara.py @danielhiversen @syssi
homeassistant/components/*/axis.py @kane610
homeassistant/components/blink/* @fronzbot
homeassistant/components/*/blink.py @fronzbot
homeassistant/components/*/bmw_connected_drive.py @ChristianKuehnel
homeassistant/components/*/broadlink.py @danielhiversen
homeassistant/components/*/deconz.py @kane610
homeassistant/components/ecovacs.py @OverloadUT
homeassistant/components/*/ecovacs.py @OverloadUT
homeassistant/components/edp_redy.py @abmantis
homeassistant/components/*/edp_redy.py @abmantis
homeassistant/components/eight_sleep.py @mezz64
homeassistant/components/*/eight_sleep.py @mezz64
homeassistant/components/hive.py @Rendili @KJonline
@@ -106,7 +110,7 @@ homeassistant/components/konnected.py @heythisisnate
homeassistant/components/*/konnected.py @heythisisnate
homeassistant/components/matrix.py @tinloaf
homeassistant/components/*/matrix.py @tinloaf
homeassistant/components/openuv.py @bachya
homeassistant/components/openuv/* @bachya
homeassistant/components/*/openuv.py @bachya
homeassistant/components/qwikswitch.py @kellerza
homeassistant/components/*/qwikswitch.py @kellerza
@@ -119,6 +123,8 @@ homeassistant/components/tesla.py @zabuldon
homeassistant/components/*/tesla.py @zabuldon
homeassistant/components/tellduslive.py @molobrakos @fredrike
homeassistant/components/*/tellduslive.py @molobrakos @fredrike
homeassistant/components/tibber/* @danielhiversen
homeassistant/components/*/tibber.py @danielhiversen
homeassistant/components/*/tradfri.py @ggravlingen
homeassistant/components/upcloud.py @scop
homeassistant/components/*/upcloud.py @scop

View File

@@ -22,16 +22,31 @@ from homeassistant.const import (
def set_loop() -> None:
"""Attempt to use uvloop."""
import asyncio
from asyncio.events import BaseDefaultEventLoopPolicy
policy = None
if sys.platform == 'win32':
asyncio.set_event_loop(asyncio.ProactorEventLoop())
if hasattr(asyncio, 'WindowsProactorEventLoopPolicy'):
# pylint: disable=no-member
policy = asyncio.WindowsProactorEventLoopPolicy()
else:
class ProactorPolicy(BaseDefaultEventLoopPolicy):
"""Event loop policy to create proactor loops."""
_loop_factory = asyncio.ProactorEventLoop
policy = ProactorPolicy()
else:
try:
import uvloop
except ImportError:
pass
else:
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
policy = uvloop.EventLoopPolicy()
if policy is not None:
asyncio.set_event_loop_policy(policy)
def validate_python() -> None:

View File

@@ -1,9 +1,9 @@
"""Storage for auth models."""
from collections import OrderedDict
from datetime import timedelta
import hmac
from logging import getLogger
from typing import Any, Dict, List, Optional # noqa: F401
import hmac
from homeassistant.auth.const import ACCESS_TOKEN_EXPIRATION
from homeassistant.core import HomeAssistant, callback
@@ -28,7 +28,8 @@ class AuthStore:
"""Initialize the auth store."""
self.hass = hass
self._users = None # type: Optional[Dict[str, models.User]]
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY,
private=True)
async def async_get_users(self) -> List[models.User]:
"""Retrieve all users."""
@@ -213,14 +214,24 @@ class AuthStore:
if self._users is not None:
return
users = OrderedDict() # type: Dict[str, models.User]
if data is None:
self._users = users
self._set_defaults()
return
users = OrderedDict() # type: Dict[str, models.User]
# When creating objects we mention each attribute explicetely. This
# prevents crashing if user rolls back HA version after a new property
# was added.
for user_dict in data['users']:
users[user_dict['id']] = models.User(**user_dict)
users[user_dict['id']] = models.User(
name=user_dict['name'],
id=user_dict['id'],
is_owner=user_dict['is_owner'],
is_active=user_dict['is_active'],
system_generated=user_dict['system_generated'],
)
for cred_dict in data['credentials']:
users[cred_dict['user_id']].credentials.append(models.Credentials(
@@ -340,3 +351,7 @@ class AuthStore:
'credentials': credentials,
'refresh_tokens': refresh_tokens,
}
def _set_defaults(self) -> None:
"""Set default values for auth store."""
self._users = OrderedDict() # type: Dict[str, models.User]

View File

@@ -85,7 +85,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
super().__init__(hass, config)
self._user_settings = None # type: Optional[_UsersDict]
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY)
STORAGE_VERSION, STORAGE_KEY, private=True)
self._include = config.get(CONF_INCLUDE, [])
self._exclude = config.get(CONF_EXCLUDE, [])
self._message_template = config[CONF_MESSAGE]

View File

@@ -67,7 +67,7 @@ class TotpAuthModule(MultiFactorAuthModule):
super().__init__(hass, config)
self._users = None # type: Optional[Dict[str, str]]
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY)
STORAGE_VERSION, STORAGE_KEY, private=True)
@property
def input_schema(self) -> vol.Schema:

View File

@@ -19,19 +19,19 @@ class User:
"""A user."""
name = attr.ib(type=str) # type: Optional[str]
id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex))
id = attr.ib(type=str, factory=lambda: uuid.uuid4().hex)
is_owner = attr.ib(type=bool, default=False)
is_active = attr.ib(type=bool, default=False)
system_generated = attr.ib(type=bool, default=False)
# List of credentials of a user.
credentials = attr.ib(
type=list, default=attr.Factory(list), cmp=False
type=list, factory=list, cmp=False
) # type: List[Credentials]
# Tokens associated with a user.
refresh_tokens = attr.ib(
type=dict, default=attr.Factory(dict), cmp=False
type=dict, factory=dict, cmp=False
) # type: Dict[str, RefreshToken]
@@ -48,12 +48,10 @@ class RefreshToken:
validator=attr.validators.in_((
TOKEN_TYPE_NORMAL, TOKEN_TYPE_SYSTEM,
TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN)))
id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex))
created_at = attr.ib(type=datetime, default=attr.Factory(dt_util.utcnow))
token = attr.ib(type=str,
default=attr.Factory(lambda: generate_secret(64)))
jwt_key = attr.ib(type=str,
default=attr.Factory(lambda: generate_secret(64)))
id = attr.ib(type=str, factory=lambda: uuid.uuid4().hex)
created_at = attr.ib(type=datetime, factory=dt_util.utcnow)
token = attr.ib(type=str, factory=lambda: generate_secret(64))
jwt_key = attr.ib(type=str, factory=lambda: generate_secret(64))
last_used_at = attr.ib(type=Optional[datetime], default=None)
last_used_ip = attr.ib(type=Optional[str], default=None)
@@ -69,7 +67,7 @@ class Credentials:
# Allow the auth provider to store data to represent their auth.
data = attr.ib(type=dict)
id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex))
id = attr.ib(type=str, factory=lambda: uuid.uuid4().hex)
is_new = attr.ib(type=bool, default=True)

View File

@@ -52,7 +52,8 @@ class Data:
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the user data store."""
self.hass = hass
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY,
private=True)
self._data = None # type: Optional[Dict[str, Any]]
async def async_load(self) -> None:

View File

@@ -59,61 +59,9 @@ def is_on(hass, entity_id=None):
return False
def turn_on(hass, entity_id=None, **service_data):
"""Turn specified entity on if possible."""
if entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
hass.services.call(ha.DOMAIN, SERVICE_TURN_ON, service_data)
def turn_off(hass, entity_id=None, **service_data):
"""Turn specified entity off."""
if entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
hass.services.call(ha.DOMAIN, SERVICE_TURN_OFF, service_data)
def toggle(hass, entity_id=None, **service_data):
"""Toggle specified entity."""
if entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
hass.services.call(ha.DOMAIN, SERVICE_TOGGLE, service_data)
def stop(hass):
"""Stop Home Assistant."""
hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP)
def restart(hass):
"""Stop Home Assistant."""
hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART)
def check_config(hass):
"""Check the config files."""
hass.services.call(ha.DOMAIN, SERVICE_CHECK_CONFIG)
def reload_core_config(hass):
"""Reload the core config."""
hass.services.call(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG)
@asyncio.coroutine
def async_reload_core_config(hass):
"""Reload the core config."""
yield from hass.services.async_call(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG)
@asyncio.coroutine
def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
"""Set up general services related to Home Assistant."""
@asyncio.coroutine
def async_handle_turn_service(service):
async def async_handle_turn_service(service):
"""Handle calls to homeassistant.turn_on/off."""
entity_ids = extract_entity_ids(hass, service)
@@ -148,7 +96,7 @@ def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
tasks.append(hass.services.async_call(
domain, service.service, data, blocking))
yield from asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
ha.DOMAIN, SERVICE_TURN_OFF, async_handle_turn_service)
@@ -164,15 +112,14 @@ def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
intent.INTENT_TOGGLE, ha.DOMAIN, SERVICE_TOGGLE, "Toggled {}"))
@asyncio.coroutine
def async_handle_core_service(call):
async def async_handle_core_service(call):
"""Service handler for handling core services."""
if call.service == SERVICE_HOMEASSISTANT_STOP:
hass.async_create_task(hass.async_stop())
return
try:
errors = yield from conf_util.async_check_ha_config_file(hass)
errors = await conf_util.async_check_ha_config_file(hass)
except HomeAssistantError:
return
@@ -193,16 +140,15 @@ def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
hass.services.async_register(
ha.DOMAIN, SERVICE_CHECK_CONFIG, async_handle_core_service)
@asyncio.coroutine
def async_handle_reload_config(call):
async def async_handle_reload_config(call):
"""Service handler for reloading core config."""
try:
conf = yield from conf_util.async_hass_config_yaml(hass)
conf = await conf_util.async_hass_config_yaml(hass)
except HomeAssistantError as err:
_LOGGER.error(err)
return
yield from conf_util.async_process_ha_core_config(
await conf_util.async_process_ha_core_config(
hass, conf.get(ha.DOMAIN) or {})
hass.services.async_register(

View File

@@ -4,7 +4,6 @@ This component provides basic support for Abode Home Security system.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/abode/
"""
import asyncio
import logging
from functools import partial
from requests.exceptions import HTTPError, ConnectTimeout
@@ -261,8 +260,7 @@ class AbodeDevice(Entity):
self._data = data
self._device = device
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Subscribe Abode events."""
self.hass.async_add_job(
self._data.abode.events.add_device_callback,
@@ -308,8 +306,7 @@ class AbodeAutomation(Entity):
self._automation = automation
self._event = event
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Subscribe Abode events."""
if self._event:
self.hass.async_add_job(

View File

@@ -4,7 +4,6 @@ Component to interface with an alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel/
"""
import asyncio
from datetime import timedelta
import logging
@@ -14,7 +13,6 @@ from homeassistant.const import (
ATTR_CODE, ATTR_CODE_FORMAT, ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY,
SERVICE_ALARM_ARM_NIGHT, SERVICE_ALARM_ARM_CUSTOM_BYPASS)
from homeassistant.loader import bind_hass
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
@@ -32,85 +30,12 @@ ALARM_SERVICE_SCHEMA = vol.Schema({
})
@bind_hass
def alarm_disarm(hass, code=None, entity_id=None):
"""Send the alarm the command for disarm."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data)
@bind_hass
def alarm_arm_home(hass, code=None, entity_id=None):
"""Send the alarm the command for arm home."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_HOME, data)
@bind_hass
def alarm_arm_away(hass, code=None, entity_id=None):
"""Send the alarm the command for arm away."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data)
@bind_hass
def alarm_arm_night(hass, code=None, entity_id=None):
"""Send the alarm the command for arm night."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_NIGHT, data)
@bind_hass
def alarm_trigger(hass, code=None, entity_id=None):
"""Send the alarm the command for trigger."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data)
@bind_hass
def alarm_arm_custom_bypass(hass, code=None, entity_id=None):
"""Send the alarm the command for arm custom bypass."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_CUSTOM_BYPASS, data)
@asyncio.coroutine
def async_setup(hass, config):
async def async_setup(hass, config):
"""Track states and offer events for sensors."""
component = hass.data[DOMAIN] = EntityComponent(
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)
yield from component.async_setup(config)
await component.async_setup(config)
component.async_register_entity_service(
SERVICE_ALARM_DISARM, ALARM_SERVICE_SCHEMA,

View File

@@ -4,7 +4,6 @@ Support for AlarmDecoder-based alarm control panels (Honeywell/DSC).
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.alarmdecoder/
"""
import asyncio
import logging
import voluptuous as vol
@@ -59,8 +58,7 @@ class AlarmDecoderAlarmPanel(alarm.AlarmControlPanel):
self._ready = None
self._zone_bypassed = None
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
self.hass.helpers.dispatcher.async_dispatcher_connect(
SIGNAL_PANEL_MESSAGE, self._message_callback)

View File

@@ -4,7 +4,6 @@ Interfaces with Alarm.com alarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.alarmdotcom/
"""
import asyncio
import logging
import re
@@ -32,9 +31,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a Alarm.com control panel."""
name = config.get(CONF_NAME)
code = config.get(CONF_CODE)
@@ -42,7 +40,7 @@ def async_setup_platform(hass, config, async_add_entities,
password = config.get(CONF_PASSWORD)
alarmdotcom = AlarmDotCom(hass, name, code, username, password)
yield from alarmdotcom.async_login()
await alarmdotcom.async_login()
async_add_entities([alarmdotcom])
@@ -63,15 +61,13 @@ class AlarmDotCom(alarm.AlarmControlPanel):
self._alarm = Alarmdotcom(
username, password, self._websession, hass.loop)
@asyncio.coroutine
def async_login(self):
async def async_login(self):
"""Login to Alarm.com."""
yield from self._alarm.async_login()
await self._alarm.async_login()
@asyncio.coroutine
def async_update(self):
async def async_update(self):
"""Fetch the latest state."""
yield from self._alarm.async_update()
await self._alarm.async_update()
return self._alarm.state
@property
@@ -106,23 +102,20 @@ class AlarmDotCom(alarm.AlarmControlPanel):
'sensor_status': self._alarm.sensor_status
}
@asyncio.coroutine
def async_alarm_disarm(self, code=None):
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
if self._validate_code(code):
yield from self._alarm.async_alarm_disarm()
await self._alarm.async_alarm_disarm()
@asyncio.coroutine
def async_alarm_arm_home(self, code=None):
async def async_alarm_arm_home(self, code=None):
"""Send arm hom command."""
if self._validate_code(code):
yield from self._alarm.async_alarm_arm_home()
await self._alarm.async_alarm_arm_home()
@asyncio.coroutine
def async_alarm_arm_away(self, code=None):
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
if self._validate_code(code):
yield from self._alarm.async_alarm_arm_away()
await self._alarm.async_alarm_arm_away()
def _validate_code(self, code):
"""Validate given code."""

View File

@@ -0,0 +1,86 @@
"""
Support for Blink Alarm Control Panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.blink/
"""
import logging
from homeassistant.components.alarm_control_panel import AlarmControlPanel
from homeassistant.components.blink import (
BLINK_DATA, DEFAULT_ATTRIBUTION)
from homeassistant.const import (
ATTR_ATTRIBUTION, STATE_ALARM_DISARMED, STATE_ALARM_ARMED_AWAY)
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['blink']
ICON = 'mdi:security'
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Arlo Alarm Control Panels."""
if discovery_info is None:
return
data = hass.data[BLINK_DATA]
# Current version of blinkpy API only supports one sync module. When
# support for additional models is added, the sync module name should
# come from the API.
sync_modules = []
sync_modules.append(BlinkSyncModule(data, 'sync'))
add_entities(sync_modules, True)
class BlinkSyncModule(AlarmControlPanel):
"""Representation of a Blink Alarm Control Panel."""
def __init__(self, data, name):
"""Initialize the alarm control panel."""
self.data = data
self.sync = data.sync
self._name = name
self._state = None
@property
def icon(self):
"""Return icon."""
return ICON
@property
def state(self):
"""Return the state of the device."""
return self._state
@property
def name(self):
"""Return the name of the panel."""
return "{} {}".format(BLINK_DATA, self._name)
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION,
}
def update(self):
"""Update the state of the device."""
_LOGGER.debug("Updating Blink Alarm Control Panel %s", self._name)
self.data.refresh()
mode = self.sync.arm
if mode:
self._state = STATE_ALARM_ARMED_AWAY
else:
self._state = STATE_ALARM_DISARMED
def alarm_disarm(self, code=None):
"""Send disarm command."""
self.sync.arm = False
self.sync.refresh()
def alarm_arm_away(self, code=None):
"""Send arm command."""
self.sync.arm = True
self.sync.refresh()

View File

@@ -4,7 +4,6 @@ Interfaces with Egardia/Woonveilig alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.egardia/
"""
import asyncio
import logging
import requests
@@ -61,8 +60,7 @@ class EgardiaAlarm(alarm.AlarmControlPanel):
self._rs_codes = rs_codes
self._rs_port = rs_port
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Add Egardiaserver callback if enabled."""
if self._rs_enabled:
_LOGGER.debug("Registering callback to Egardiaserver")

View File

@@ -4,7 +4,6 @@ Support for Envisalink-based alarm control panels (Honeywell/DSC).
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.envisalink/
"""
import asyncio
import logging
import voluptuous as vol
@@ -32,9 +31,8 @@ ALARM_KEYPRESS_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Perform the setup for Envisalink alarm panels."""
configured_partitions = discovery_info['partitions']
code = discovery_info[CONF_CODE]
@@ -88,8 +86,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
_LOGGER.debug("Setting up alarm: %s", alarm_name)
super().__init__(alarm_name, info, controller)
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_KEYPAD_UPDATE, self._update_callback)
@@ -128,8 +125,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
state = STATE_ALARM_DISARMED
return state
@asyncio.coroutine
def async_alarm_disarm(self, code=None):
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
if code:
self.hass.data[DATA_EVL].disarm_partition(
@@ -138,8 +134,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
self.hass.data[DATA_EVL].disarm_partition(
str(self._code), self._partition_number)
@asyncio.coroutine
def async_alarm_arm_home(self, code=None):
async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
if code:
self.hass.data[DATA_EVL].arm_stay_partition(
@@ -148,8 +143,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
self.hass.data[DATA_EVL].arm_stay_partition(
str(self._code), self._partition_number)
@asyncio.coroutine
def async_alarm_arm_away(self, code=None):
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
if code:
self.hass.data[DATA_EVL].arm_away_partition(
@@ -158,8 +152,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
self.hass.data[DATA_EVL].arm_away_partition(
str(self._code), self._partition_number)
@asyncio.coroutine
def async_alarm_trigger(self, code=None):
async def async_alarm_trigger(self, code=None):
"""Alarm trigger command. Will be used to trigger a panic alarm."""
self.hass.data[DATA_EVL].panic_alarm(self._panic_type)

View File

@@ -4,7 +4,6 @@ Support for manual alarms controllable via MQTT.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.manual_mqtt/
"""
import asyncio
import copy
import datetime
import logging
@@ -363,8 +362,8 @@ class ManualMQTTAlarm(alarm.AlarmControlPanel):
return mqtt.async_subscribe(
self.hass, self._command_topic, message_received, self._qos)
@asyncio.coroutine
def _async_state_changed_listener(self, entity_id, old_state, new_state):
async def _async_state_changed_listener(self, entity_id, old_state,
new_state):
"""Publish state change to MQTT."""
mqtt.async_publish(
self.hass, self._state_topic, new_state.state, self._qos, True)

View File

@@ -4,7 +4,6 @@ This platform enables the possibility to control a MQTT alarm.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.mqtt/
"""
import asyncio
import logging
import re
@@ -18,10 +17,13 @@ from homeassistant.const import (
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN,
CONF_NAME, CONF_CODE)
from homeassistant.components.mqtt import (
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS,
CONF_RETAIN, MqttAvailability)
ATTR_DISCOVERY_HASH, CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC,
CONF_COMMAND_TOPIC, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE,
CONF_QOS, CONF_RETAIN, MqttAvailability, MqttDiscoveryUpdate)
from homeassistant.components.mqtt.discovery import MQTT_DISCOVERY_NEW
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
_LOGGER = logging.getLogger(__name__)
@@ -46,13 +48,28 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MQTT Alarm Control Panel platform."""
if discovery_info is not None:
config = PLATFORM_SCHEMA(discovery_info)
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
async_add_entities, discovery_info=None):
"""Set up MQTT alarm control panel through configuration.yaml."""
await _async_setup_entity(hass, config, async_add_entities)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up MQTT alarm control panel dynamically through MQTT discovery."""
async def async_discover(discovery_payload):
"""Discover and add an MQTT alarm control panel."""
config = PLATFORM_SCHEMA(discovery_payload)
await _async_setup_entity(hass, config, async_add_entities,
discovery_payload[ATTR_DISCOVERY_HASH])
async_dispatcher_connect(
hass, MQTT_DISCOVERY_NEW.format(alarm.DOMAIN, 'mqtt'),
async_discover)
async def _async_setup_entity(hass, config, async_add_entities,
discovery_hash=None):
"""Set up the MQTT Alarm Control Panel platform."""
async_add_entities([MqttAlarm(
config.get(CONF_NAME),
config.get(CONF_STATE_TOPIC),
@@ -65,18 +82,22 @@ def async_setup_platform(hass, config, async_add_entities,
config.get(CONF_CODE),
config.get(CONF_AVAILABILITY_TOPIC),
config.get(CONF_PAYLOAD_AVAILABLE),
config.get(CONF_PAYLOAD_NOT_AVAILABLE))])
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
discovery_hash,)])
class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
class MqttAlarm(MqttAvailability, MqttDiscoveryUpdate,
alarm.AlarmControlPanel):
"""Representation of a MQTT alarm status."""
def __init__(self, name, state_topic, command_topic, qos, retain,
payload_disarm, payload_arm_home, payload_arm_away, code,
availability_topic, payload_available, payload_not_available):
availability_topic, payload_available, payload_not_available,
discovery_hash):
"""Init the MQTT Alarm Control Panel."""
super().__init__(availability_topic, qos, payload_available,
payload_not_available)
MqttAvailability.__init__(self, availability_topic, qos,
payload_available, payload_not_available)
MqttDiscoveryUpdate.__init__(self, discovery_hash)
self._state = STATE_UNKNOWN
self._name = name
self._state_topic = state_topic
@@ -87,11 +108,12 @@ class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
self._payload_arm_home = payload_arm_home
self._payload_arm_away = payload_arm_away
self._code = code
self._discovery_hash = discovery_hash
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Subscribe mqtt events."""
yield from super().async_added_to_hass()
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
@callback
def message_received(topic, payload, qos):
@@ -104,7 +126,7 @@ class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
self._state = payload
self.async_schedule_update_ha_state()
yield from mqtt.async_subscribe(
await mqtt.async_subscribe(
self.hass, self._state_topic, message_received, self._qos)
@property
@@ -131,8 +153,7 @@ class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
return 'Number'
return 'Any'
@asyncio.coroutine
def async_alarm_disarm(self, code=None):
async def async_alarm_disarm(self, code=None):
"""Send disarm command.
This method is a coroutine.
@@ -143,8 +164,7 @@ class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
self.hass, self._command_topic, self._payload_disarm, self._qos,
self._retain)
@asyncio.coroutine
def async_alarm_arm_home(self, code=None):
async def async_alarm_arm_home(self, code=None):
"""Send arm home command.
This method is a coroutine.
@@ -155,8 +175,7 @@ class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
self.hass, self._command_topic, self._payload_arm_home, self._qos,
self._retain)
@asyncio.coroutine
def async_alarm_arm_away(self, code=None):
async def async_alarm_arm_away(self, code=None):
"""Send arm away command.
This method is a coroutine.

View File

@@ -4,7 +4,6 @@ Support for Satel Integra alarm, using ETHM module: https://www.satel.pl/en/ .
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.satel_integra/
"""
import asyncio
import logging
import homeassistant.components.alarm_control_panel as alarm
@@ -18,9 +17,8 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['satel_integra']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up for Satel Integra alarm panels."""
if not discovery_info:
return
@@ -39,8 +37,7 @@ class SatelIntegraAlarmPanel(alarm.AlarmControlPanel):
self._state = None
self._arm_home_mode = arm_home_mode
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_PANEL_MESSAGE, self._message_callback)
@@ -74,21 +71,18 @@ class SatelIntegraAlarmPanel(alarm.AlarmControlPanel):
"""Return the state of the device."""
return self._state
@asyncio.coroutine
def async_alarm_disarm(self, code=None):
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
if code:
yield from self.hass.data[DATA_SATEL].disarm(code)
await self.hass.data[DATA_SATEL].disarm(code)
@asyncio.coroutine
def async_alarm_arm_away(self, code=None):
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
if code:
yield from self.hass.data[DATA_SATEL].arm(code)
await self.hass.data[DATA_SATEL].arm(code)
@asyncio.coroutine
def async_alarm_arm_home(self, code=None):
async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
if code:
yield from self.hass.data[DATA_SATEL].arm(
await self.hass.data[DATA_SATEL].arm(
code, self._arm_home_mode)

View File

@@ -12,75 +12,100 @@ import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA, AlarmControlPanel)
from homeassistant.const import (
CONF_CODE, CONF_NAME, CONF_PASSWORD, CONF_USERNAME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED, STATE_UNKNOWN)
import homeassistant.helpers.config_validation as cv
CONF_CODE, CONF_NAME, CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED)
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.util.json import load_json, save_json
REQUIREMENTS = ['simplisafe-python==2.0.2']
REQUIREMENTS = ['simplisafe-python==3.1.2']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'SimpliSafe'
ATTR_ALARM_ACTIVE = "alarm_active"
ATTR_TEMPERATURE = "temperature"
DATA_FILE = '.simplisafe'
DEFAULT_NAME = 'SimpliSafe'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_CODE): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_CODE): cv.string,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the SimpliSafe platform."""
from simplipy.api import SimpliSafeApiInterface, SimpliSafeAPIException
from simplipy import API
from simplipy.errors import SimplipyError
username = config[CONF_USERNAME]
password = config[CONF_PASSWORD]
name = config.get(CONF_NAME)
code = config.get(CONF_CODE)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
websession = aiohttp_client.async_get_clientsession(hass)
config_data = await hass.async_add_executor_job(
load_json, hass.config.path(DATA_FILE))
try:
simplisafe = SimpliSafeApiInterface(username, password)
except SimpliSafeAPIException:
_LOGGER.error("Failed to set up SimpliSafe")
if config_data:
try:
simplisafe = await API.login_via_token(
config_data['refresh_token'], websession)
_LOGGER.debug('Logging in with refresh token')
except SimplipyError:
_LOGGER.info('Refresh token expired; attempting credentials')
simplisafe = await API.login_via_credentials(
username, password, websession)
else:
simplisafe = await API.login_via_credentials(
username, password, websession)
_LOGGER.debug('Logging in with credentials')
except SimplipyError as err:
_LOGGER.error("There was an error during setup: %s", err)
return
systems = []
config_data = {'refresh_token': simplisafe.refresh_token}
await hass.async_add_executor_job(
save_json, hass.config.path(DATA_FILE), config_data)
for system in simplisafe.get_systems():
systems.append(SimpliSafeAlarm(system, name, code))
add_entities(systems)
systems = await simplisafe.get_systems()
async_add_entities(
[SimpliSafeAlarm(system, name, code) for system in systems], True)
class SimpliSafeAlarm(AlarmControlPanel):
"""Representation of a SimpliSafe alarm."""
def __init__(self, simplisafe, name, code):
def __init__(self, system, name, code):
"""Initialize the SimpliSafe alarm."""
self.simplisafe = simplisafe
self._name = name
self._attrs = {}
self._code = str(code) if code else None
self._name = name
self._system = system
self._state = None
@property
def unique_id(self):
"""Return the unique ID."""
return self.simplisafe.location_id
return self._system.system_id
@property
def name(self):
"""Return the name of the device."""
if self._name is not None:
if self._name:
return self._name
return 'Alarm {}'.format(self.simplisafe.location_id)
return 'Alarm {}'.format(self._system.system_id)
@property
def code_format(self):
"""Return one or more digits/characters."""
if self._code is None:
if not self._code:
return None
if isinstance(self._code, str) and re.search('^\\d+$', self._code):
return 'Number'
@@ -89,53 +114,12 @@ class SimpliSafeAlarm(AlarmControlPanel):
@property
def state(self):
"""Return the state of the device."""
status = self.simplisafe.state
if status.lower() == 'off':
state = STATE_ALARM_DISARMED
elif status.lower() == 'home' or status.lower() == 'home_count':
state = STATE_ALARM_ARMED_HOME
elif (status.lower() == 'away' or status.lower() == 'exitDelay' or
status.lower() == 'away_count'):
state = STATE_ALARM_ARMED_AWAY
else:
state = STATE_UNKNOWN
return state
return self._state
@property
def device_state_attributes(self):
"""Return the state attributes."""
attributes = {}
attributes[ATTR_ALARM_ACTIVE] = self.simplisafe.alarm_active
if self.simplisafe.temperature is not None:
attributes[ATTR_TEMPERATURE] = self.simplisafe.temperature
return attributes
def update(self):
"""Update alarm status."""
self.simplisafe.update()
def alarm_disarm(self, code=None):
"""Send disarm command."""
if not self._validate_code(code, 'disarming'):
return
self.simplisafe.set_state('off')
_LOGGER.info("SimpliSafe alarm disarming")
def alarm_arm_home(self, code=None):
"""Send arm home command."""
if not self._validate_code(code, 'arming home'):
return
self.simplisafe.set_state('home')
_LOGGER.info("SimpliSafe alarm arming home")
def alarm_arm_away(self, code=None):
"""Send arm away command."""
if not self._validate_code(code, 'arming away'):
return
self.simplisafe.set_state('away')
_LOGGER.info("SimpliSafe alarm arming away")
return self._attrs
def _validate_code(self, code, state):
"""Validate given code."""
@@ -143,3 +127,46 @@ class SimpliSafeAlarm(AlarmControlPanel):
if not check:
_LOGGER.warning("Wrong code entered for %s", state)
return check
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
if not self._validate_code(code, 'disarming'):
return
await self._system.set_off()
async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
if not self._validate_code(code, 'arming home'):
return
await self._system.set_home()
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
if not self._validate_code(code, 'arming away'):
return
await self._system.set_away()
async def async_update(self):
"""Update alarm status."""
await self._system.update()
if self._system.state == self._system.SystemStates.off:
self._state = STATE_ALARM_DISARMED
elif self._system.state in (
self._system.SystemStates.home,
self._system.SystemStates.home_count):
self._state = STATE_ALARM_ARMED_HOME
elif self._system.state in (
self._system.SystemStates.away,
self._system.SystemStates.away_count,
self._system.SystemStates.exit_delay):
self._state = STATE_ALARM_ARMED_AWAY
else:
self._state = None
self._attrs[ATTR_ALARM_ACTIVE] = self._system.alarm_going_off
if self._system.temperature:
self._attrs[ATTR_TEMPERATURE] = self._system.temperature

View File

@@ -9,8 +9,7 @@ import logging
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.core import callback
from homeassistant.components.spc import (
ATTR_DISCOVER_AREAS, DATA_API, SIGNAL_UPDATE_ALARM)
from homeassistant.components.spc import (DATA_API, SIGNAL_UPDATE_ALARM)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED)
@@ -37,12 +36,11 @@ def _get_alarm_state(area):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the SPC alarm control panel platform."""
if (discovery_info is None or
discovery_info[ATTR_DISCOVER_AREAS] is None):
if discovery_info is None:
return
async_add_entities([SpcAlarm(area=area, api=hass.data[DATA_API])
for area in discovery_info[ATTR_DISCOVER_AREAS]])
api = hass.data[DATA_API]
async_add_entities([SpcAlarm(area=area, api=api)
for area in api.areas.values()])
class SpcAlarm(alarm.AlarmControlPanel):
@@ -87,19 +85,23 @@ class SpcAlarm(alarm.AlarmControlPanel):
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
from pyspcwebgw.const import AreaMode
self._api.change_mode(area=self._area, new_mode=AreaMode.UNSET)
await self._api.change_mode(area=self._area,
new_mode=AreaMode.UNSET)
async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
from pyspcwebgw.const import AreaMode
self._api.change_mode(area=self._area, new_mode=AreaMode.PART_SET_A)
await self._api.change_mode(area=self._area,
new_mode=AreaMode.PART_SET_A)
async def async_alarm_arm_night(self, code=None):
"""Send arm home command."""
from pyspcwebgw.const import AreaMode
self._api.change_mode(area=self._area, new_mode=AreaMode.PART_SET_B)
await self._api.change_mode(area=self._area,
new_mode=AreaMode.PART_SET_B)
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
from pyspcwebgw.const import AreaMode
self._api.change_mode(area=self._area, new_mode=AreaMode.FULL_SET)
await self._api.change_mode(area=self._area,
new_mode=AreaMode.FULL_SET)

View File

@@ -4,7 +4,6 @@ Interfaces with Wink Cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.wink/
"""
import asyncio
import logging
import homeassistant.components.alarm_control_panel as alarm
@@ -38,8 +37,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel):
"""Representation a Wink camera alarm."""
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Call when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['alarm_control_panel'].append(self)

View File

@@ -10,7 +10,8 @@ import logging
import voluptuous as vol
from homeassistant.core import callback
from homeassistant.components.notify import (
ATTR_MESSAGE, DOMAIN as DOMAIN_NOTIFY)
from homeassistant.const import (
CONF_ENTITY_ID, STATE_IDLE, CONF_NAME, CONF_STATE, STATE_ON, STATE_OFF,
SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE, ATTR_ENTITY_ID)
@@ -59,53 +60,12 @@ def is_on(hass, entity_id):
return hass.states.is_state(entity_id, STATE_ON)
def turn_on(hass, entity_id):
"""Reset the alert."""
hass.add_job(async_turn_on, hass, entity_id)
@callback
def async_turn_on(hass, entity_id):
"""Async reset the alert."""
data = {ATTR_ENTITY_ID: entity_id}
hass.async_create_task(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data))
def turn_off(hass, entity_id):
"""Acknowledge alert."""
hass.add_job(async_turn_off, hass, entity_id)
@callback
def async_turn_off(hass, entity_id):
"""Async acknowledge the alert."""
data = {ATTR_ENTITY_ID: entity_id}
hass.async_create_task(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data))
def toggle(hass, entity_id):
"""Toggle acknowledgement of alert."""
hass.add_job(async_toggle, hass, entity_id)
@callback
def async_toggle(hass, entity_id):
"""Async toggle acknowledgement of alert."""
data = {ATTR_ENTITY_ID: entity_id}
hass.async_create_task(
hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data))
@asyncio.coroutine
def async_setup(hass, config):
async def async_setup(hass, config):
"""Set up the Alert component."""
alerts = config.get(DOMAIN)
all_alerts = {}
@asyncio.coroutine
def async_handle_alert_service(service_call):
async def async_handle_alert_service(service_call):
"""Handle calls to alert services."""
alert_ids = service.extract_entity_ids(hass, service_call)
@@ -113,11 +73,11 @@ def async_setup(hass, config):
alert = all_alerts[alert_id]
alert.async_set_context(service_call.context)
if service_call.service == SERVICE_TURN_ON:
yield from alert.async_turn_on()
await alert.async_turn_on()
elif service_call.service == SERVICE_TOGGLE:
yield from alert.async_toggle()
await alert.async_toggle()
else:
yield from alert.async_turn_off()
await alert.async_turn_off()
# Setup alerts
for entity_id, alert in alerts.items():
@@ -141,7 +101,7 @@ def async_setup(hass, config):
tasks = [alert.async_update_ha_state() for alert in all_alerts.values()]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks, loop=hass.loop)
return True
@@ -196,17 +156,15 @@ class Alert(ToggleEntity):
"""Hide the alert when it is not firing."""
return not self._can_ack or not self._firing
@asyncio.coroutine
def watched_entity_change(self, entity, from_state, to_state):
async def watched_entity_change(self, entity, from_state, to_state):
"""Determine if the alert should start or stop."""
_LOGGER.debug("Watched entity (%s) has changed", entity)
if to_state.state == self._alert_state and not self._firing:
yield from self.begin_alerting()
await self.begin_alerting()
if to_state.state != self._alert_state and self._firing:
yield from self.end_alerting()
await self.end_alerting()
@asyncio.coroutine
def begin_alerting(self):
async def begin_alerting(self):
"""Begin the alert procedures."""
_LOGGER.debug("Beginning Alert: %s", self._name)
self._ack = False
@@ -214,25 +172,23 @@ class Alert(ToggleEntity):
self._next_delay = 0
if not self._skip_first:
yield from self._notify()
await self._notify()
else:
yield from self._schedule_notify()
await self._schedule_notify()
self.async_schedule_update_ha_state()
@asyncio.coroutine
def end_alerting(self):
async def end_alerting(self):
"""End the alert procedures."""
_LOGGER.debug("Ending Alert: %s", self._name)
self._cancel()
self._ack = False
self._firing = False
if self._done_message and self._send_done_message:
yield from self._notify_done_message()
await self._notify_done_message()
self.async_schedule_update_ha_state()
@asyncio.coroutine
def _schedule_notify(self):
async def _schedule_notify(self):
"""Schedule a notification."""
delay = self._delay[self._next_delay]
next_msg = datetime.now() + delay
@@ -240,8 +196,7 @@ class Alert(ToggleEntity):
event.async_track_point_in_time(self.hass, self._notify, next_msg)
self._next_delay = min(self._next_delay + 1, len(self._delay) - 1)
@asyncio.coroutine
def _notify(self, *args):
async def _notify(self, *args):
"""Send the alert notification."""
if not self._firing:
return
@@ -250,36 +205,32 @@ class Alert(ToggleEntity):
_LOGGER.info("Alerting: %s", self._name)
self._send_done_message = True
for target in self._notifiers:
yield from self.hass.services.async_call(
'notify', target, {'message': self._name})
yield from self._schedule_notify()
await self.hass.services.async_call(
DOMAIN_NOTIFY, target, {ATTR_MESSAGE: self._name})
await self._schedule_notify()
@asyncio.coroutine
def _notify_done_message(self, *args):
async def _notify_done_message(self, *args):
"""Send notification of complete alert."""
_LOGGER.info("Alerting: %s", self._done_message)
self._send_done_message = False
for target in self._notifiers:
yield from self.hass.services.async_call(
'notify', target, {'message': self._done_message})
await self.hass.services.async_call(
DOMAIN_NOTIFY, target, {ATTR_MESSAGE: self._done_message})
@asyncio.coroutine
def async_turn_on(self, **kwargs):
async def async_turn_on(self, **kwargs):
"""Async Unacknowledge alert."""
_LOGGER.debug("Reset Alert: %s", self._name)
self._ack = False
yield from self.async_update_ha_state()
await self.async_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
async def async_turn_off(self, **kwargs):
"""Async Acknowledge alert."""
_LOGGER.debug("Acknowledged Alert: %s", self._name)
self._ack = True
yield from self.async_update_ha_state()
await self.async_update_ha_state()
@asyncio.coroutine
def async_toggle(self, **kwargs):
async def async_toggle(self, **kwargs):
"""Async toggle alert."""
if self._ack:
return self.async_turn_on()
return self.async_turn_off()
return await self.async_turn_on()
return await self.async_turn_off()

View File

@@ -4,7 +4,6 @@ Support for Alexa skill service end point.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/alexa/
"""
import asyncio
import logging
import voluptuous as vol
@@ -53,8 +52,7 @@ CONFIG_SCHEMA = vol.Schema({
}, extra=vol.ALLOW_EXTRA)
@asyncio.coroutine
def async_setup(hass, config):
async def async_setup(hass, config):
"""Activate Alexa component."""
config = config.get(DOMAIN, {})
flash_briefings_config = config.get(CONF_FLASH_BRIEFINGS)

View File

@@ -4,7 +4,6 @@ Support for Alexa skill service end point.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/alexa/
"""
import asyncio
import enum
import logging
@@ -59,16 +58,15 @@ class AlexaIntentsView(http.HomeAssistantView):
url = INTENTS_API_ENDPOINT
name = 'api:alexa'
@asyncio.coroutine
def post(self, request):
async def post(self, request):
"""Handle Alexa."""
hass = request.app['hass']
message = yield from request.json()
message = await request.json()
_LOGGER.debug("Received Alexa request: %s", message)
try:
response = yield from async_handle_message(hass, message)
response = await async_handle_message(hass, message)
return b'' if response is None else self.json(response)
except UnknownRequest as err:
_LOGGER.warning(str(err))
@@ -101,8 +99,7 @@ def intent_error_response(hass, message, error):
return alexa_response.as_dict()
@asyncio.coroutine
def async_handle_message(hass, message):
async def async_handle_message(hass, message):
"""Handle an Alexa intent.
Raises:
@@ -120,20 +117,18 @@ def async_handle_message(hass, message):
if not handler:
raise UnknownRequest('Received unknown request {}'.format(req_type))
return (yield from handler(hass, message))
return await handler(hass, message)
@HANDLERS.register('SessionEndedRequest')
@asyncio.coroutine
def async_handle_session_end(hass, message):
async def async_handle_session_end(hass, message):
"""Handle a session end request."""
return None
@HANDLERS.register('IntentRequest')
@HANDLERS.register('LaunchRequest')
@asyncio.coroutine
def async_handle_intent(hass, message):
async def async_handle_intent(hass, message):
"""Handle an intent request.
Raises:
@@ -153,7 +148,7 @@ def async_handle_intent(hass, message):
else:
intent_name = alexa_intent_info['name']
intent_response = yield from intent.async_handle(
intent_response = await intent.async_handle(
hass, DOMAIN, intent_name,
{key: {'value': value} for key, value
in alexa_response.variables.items()})

View File

@@ -1,5 +1,4 @@
"""Support for alexa Smart Home Skill API."""
import asyncio
import logging
import math
from datetime import datetime
@@ -695,8 +694,7 @@ class SmartHomeView(http.HomeAssistantView):
"""Initialize."""
self.smart_home_config = smart_home_config
@asyncio.coroutine
def post(self, request):
async def post(self, request):
"""Handle Alexa Smart Home requests.
The Smart Home API requires the endpoint to be implemented in AWS
@@ -704,11 +702,11 @@ class SmartHomeView(http.HomeAssistantView):
the response.
"""
hass = request.app['hass']
message = yield from request.json()
message = await request.json()
_LOGGER.debug("Received Alexa Smart Home request: %s", message)
response = yield from async_handle_message(
response = await async_handle_message(
hass, self.smart_home_config, message)
_LOGGER.debug("Sending Alexa Smart Home response: %s", response)
return b'' if response is None else self.json(response)

View File

@@ -149,16 +149,14 @@ CONFIG_SCHEMA = vol.Schema({
}, extra=vol.ALLOW_EXTRA)
@asyncio.coroutine
def async_setup(hass, config):
async def async_setup(hass, config):
"""Set up the IP Webcam component."""
from pydroid_ipcam import PyDroidIPCam
webcams = hass.data[DATA_IP_WEBCAM] = {}
websession = async_get_clientsession(hass)
@asyncio.coroutine
def async_setup_ipcamera(cam_config):
async def async_setup_ipcamera(cam_config):
"""Set up an IP camera."""
host = cam_config[CONF_HOST]
username = cam_config.get(CONF_USERNAME)
@@ -188,16 +186,15 @@ def async_setup(hass, config):
if motion is None:
motion = 'motion_active' in cam.enabled_sensors
@asyncio.coroutine
def async_update_data(now):
async def async_update_data(now):
"""Update data from IP camera in SCAN_INTERVAL."""
yield from cam.update()
await cam.update()
async_dispatcher_send(hass, SIGNAL_UPDATE_DATA, host)
async_track_point_in_utc_time(
hass, async_update_data, utcnow() + interval)
yield from async_update_data(None)
await async_update_data(None)
# Load platforms
webcams[host] = cam
@@ -242,7 +239,7 @@ def async_setup(hass, config):
tasks = [async_setup_ipcamera(conf) for conf in config[DOMAIN]]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks, loop=hass.loop)
return True
@@ -255,8 +252,7 @@ class AndroidIPCamEntity(Entity):
self._host = host
self._ipcam = ipcam
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register update dispatcher."""
@callback
def async_ipcam_update(host):

View File

@@ -141,6 +141,8 @@ class APIEventStream(HomeAssistantView):
_LOGGER.debug("STREAM %s RESPONSE CLOSED", id(stop_obj))
unsub_stream()
return response
class APIConfigView(HomeAssistantView):
"""View to handle Configuration requests."""

View File

@@ -77,14 +77,13 @@ def request_configuration(hass, config, atv, credentials):
"""Request configuration steps from the user."""
configurator = hass.components.configurator
@asyncio.coroutine
def configuration_callback(callback_data):
async def configuration_callback(callback_data):
"""Handle the submitted configuration."""
from pyatv import exceptions
pin = callback_data.get('pin')
try:
yield from atv.airplay.finish_authentication(pin)
await atv.airplay.finish_authentication(pin)
hass.components.persistent_notification.async_create(
'Authentication succeeded!<br /><br />Add the following '
'to credentials: in your apple_tv configuration:<br /><br />'
@@ -108,11 +107,10 @@ def request_configuration(hass, config, atv, credentials):
)
@asyncio.coroutine
def scan_for_apple_tvs(hass):
async def scan_for_apple_tvs(hass):
"""Scan for devices and present a notification of the ones found."""
import pyatv
atvs = yield from pyatv.scan_for_apple_tvs(hass.loop, timeout=3)
atvs = await pyatv.scan_for_apple_tvs(hass.loop, timeout=3)
devices = []
for atv in atvs:
@@ -132,14 +130,12 @@ def scan_for_apple_tvs(hass):
notification_id=NOTIFICATION_SCAN_ID)
@asyncio.coroutine
def async_setup(hass, config):
async def async_setup(hass, config):
"""Set up the Apple TV component."""
if DATA_APPLE_TV not in hass.data:
hass.data[DATA_APPLE_TV] = {}
@asyncio.coroutine
def async_service_handler(service):
async def async_service_handler(service):
"""Handle service calls."""
entity_ids = service.data.get(ATTR_ENTITY_ID)
@@ -158,17 +154,16 @@ def async_setup(hass, config):
continue
atv = device.atv
credentials = yield from atv.airplay.generate_credentials()
yield from atv.airplay.load_credentials(credentials)
credentials = await atv.airplay.generate_credentials()
await atv.airplay.load_credentials(credentials)
_LOGGER.debug('Generated new credentials: %s', credentials)
yield from atv.airplay.start_authentication()
await atv.airplay.start_authentication()
hass.async_add_job(request_configuration,
hass, config, atv, credentials)
@asyncio.coroutine
def atv_discovered(service, info):
async def atv_discovered(service, info):
"""Set up an Apple TV that was auto discovered."""
yield from _setup_atv(hass, {
await _setup_atv(hass, {
CONF_NAME: info['name'],
CONF_HOST: info['host'],
CONF_LOGIN_ID: info['properties']['hG'],
@@ -179,7 +174,7 @@ def async_setup(hass, config):
tasks = [_setup_atv(hass, conf) for conf in config.get(DOMAIN, [])]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SCAN, async_service_handler,
@@ -192,8 +187,7 @@ def async_setup(hass, config):
return True
@asyncio.coroutine
def _setup_atv(hass, atv_config):
async def _setup_atv(hass, atv_config):
"""Set up an Apple TV."""
import pyatv
name = atv_config.get(CONF_NAME)
@@ -209,7 +203,7 @@ def _setup_atv(hass, atv_config):
session = async_get_clientsession(hass)
atv = pyatv.connect_to_apple_tv(details, hass.loop, session=session)
if credentials:
yield from atv.airplay.load_credentials(credentials)
await atv.airplay.load_credentials(credentials)
power = AppleTVPowerManager(hass, atv, start_off)
hass.data[DATA_APPLE_TV][host] = {
@@ -258,4 +252,4 @@ class AppleTVPowerManager:
self.atv.push_updater.start()
for listener in self.listeners:
self.hass.async_add_job(listener.async_update_ha_state())
self.hass.async_create_task(listener.async_update_ha_state())

View File

@@ -0,0 +1,95 @@
"""
Support for AquaLogic component.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/aqualogic/
"""
from datetime import timedelta
import logging
import time
import threading
import voluptuous as vol
from homeassistant.const import (CONF_HOST, CONF_PORT,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
from homeassistant.helpers import config_validation as cv
REQUIREMENTS = ["aqualogic==1.0"]
_LOGGER = logging.getLogger(__name__)
DOMAIN = "aqualogic"
UPDATE_TOPIC = DOMAIN + "_update"
CONF_UNIT = "unit"
RECONNECT_INTERVAL = timedelta(seconds=10)
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PORT): cv.port
}),
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Set up AquaLogic platform."""
host = config[DOMAIN][CONF_HOST]
port = config[DOMAIN][CONF_PORT]
processor = AquaLogicProcessor(hass, host, port)
hass.data[DOMAIN] = processor
hass.bus.listen_once(EVENT_HOMEASSISTANT_START,
processor.start_listen)
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
processor.shutdown)
_LOGGER.debug("AquaLogicProcessor %s:%i initialized", host, port)
return True
class AquaLogicProcessor(threading.Thread):
"""AquaLogic event processor thread."""
def __init__(self, hass, host, port):
"""Initialize the data object."""
super().__init__(daemon=True)
self._hass = hass
self._host = host
self._port = port
self._shutdown = False
self._panel = None
def start_listen(self, event):
"""Start event-processing thread."""
_LOGGER.debug("Event processing thread started")
self.start()
def shutdown(self, event):
"""Signal shutdown of processing event."""
_LOGGER.debug("Event processing signaled exit")
self._shutdown = True
def data_changed(self, panel):
"""Aqualogic data changed callback."""
self._hass.helpers.dispatcher.dispatcher_send(UPDATE_TOPIC)
def run(self):
"""Event thread."""
from aqualogic.core import AquaLogic
while True:
self._panel = AquaLogic()
self._panel.connect(self._host, self._port)
self._panel.process(self.data_changed)
if self._shutdown:
return
_LOGGER.error("Connection to %s:%d lost",
self._host, self._port)
time.sleep(RECONNECT_INTERVAL.seconds)
@property
def panel(self):
"""Retrieve the AquaLogic object."""
return self._panel

View File

@@ -16,7 +16,8 @@
"description": "Ein Einmal-Passwort wurde per ** notify gesendet. {notify_service} **. Bitte gebe es unten ein:",
"title": "\u00dcberpr\u00fcfe das Setup"
}
}
},
"title": "Benachrichtig f\u00fcr One-Time Password"
},
"totp": {
"error": {

View File

@@ -1,11 +1,23 @@
{
"mfa_setup": {
"notify": {
"abort": {
"no_available_service": "Aucun service de notification disponible."
},
"error": {
"invalid_code": "Code invalide. Veuillez essayer \u00e0 nouveau."
},
"step": {
"init": {
"description": "Veuillez s\u00e9lectionner l'un des services de notification:",
"title": "Configurer un mot de passe \u00e0 usage unique d\u00e9livr\u00e9 par le composant notify"
},
"setup": {
"description": "Un mot de passe unique a \u00e9t\u00e9 envoy\u00e9 par **notify.{notify_service}**. Veuillez le saisir ci-dessous :"
"description": "Un mot de passe unique a \u00e9t\u00e9 envoy\u00e9 par **notify.{notify_service}**. Veuillez le saisir ci-dessous :",
"title": "V\u00e9rifier la configuration"
}
}
},
"title": "Notifier un mot de passe unique"
},
"totp": {
"error": {

View File

@@ -1,5 +1,21 @@
{
"mfa_setup": {
"notify": {
"abort": {
"no_available_service": "Nincs el\u00e9rhet\u0151 \u00e9rtes\u00edt\u00e9si szolg\u00e1ltat\u00e1s."
},
"error": {
"invalid_code": "\u00c9rv\u00e9nytelen k\u00f3d, pr\u00f3b\u00e1ld \u00fajra."
},
"step": {
"init": {
"description": "V\u00e1lassz \u00e9rtes\u00edt\u00e9si szolg\u00e1ltat\u00e1st:"
},
"setup": {
"title": "Be\u00e1ll\u00edt\u00e1s ellen\u0151rz\u00e9se"
}
}
},
"totp": {
"error": {
"invalid_code": "\u00c9rv\u00e9nytelen k\u00f3d, pr\u00f3b\u00e1ld \u00fajra. Ha ez a hiba folyamatosan el\u0151fordul, akkor gy\u0151z\u0151dj meg r\u00f3la, hogy a Home Assistant rendszered \u00f3r\u00e1ja pontosan j\u00e1r."

View File

@@ -26,7 +26,7 @@
"step": {
"init": {
"description": "\uc2dc\uac04 \uae30\ubc18\uc758 \uc77c\ud68c\uc6a9 \ube44\ubc00\ubc88\ud638\ub97c \uc0ac\uc6a9\ud558\ub294 2\ub2e8\uacc4 \uc778\uc99d\uc744 \ud558\ub824\uba74 \uc778\uc99d\uc6a9 \uc571\uc744 \uc774\uc6a9\ud574\uc11c QR \ucf54\ub4dc\ub97c \uc2a4\uce94\ud574 \uc8fc\uc138\uc694. \uc778\uc99d\uc6a9 \uc571\uc740 [Google OTP](https://support.google.com/accounts/answer/1066447) \ub610\ub294 [Authy](https://authy.com/) \ub97c \ucd94\ucc9c\ub4dc\ub9bd\ub2c8\ub2e4.\n\n{qr_code}\n\n\uc2a4\uce94 \ud6c4\uc5d0 \uc0dd\uc131\ub41c 6\uc790\ub9ac \ucf54\ub4dc\ub97c \uc785\ub825\ud574\uc11c \uc124\uc815\uc744 \ud655\uc778\ud558\uc138\uc694. QR \ucf54\ub4dc \uc2a4\uce94\uc5d0 \ubb38\uc81c\uac00 \uc788\ub2e4\uba74, **`{code}`** \ucf54\ub4dc\ub85c \uc9c1\uc811 \uc124\uc815\ud574\ubcf4\uc138\uc694.",
"title": "TOTP \ub97c \uc0ac\uc6a9\ud558\uc5ec 2 \ub2e8\uacc4 \uc778\uc99d \uad6c\uc131"
"title": "TOTP \ub97c \uc0ac\uc6a9\ud558\uc5ec 2\ub2e8\uacc4 \uc778\uc99d \uad6c\uc131"
}
},
"title": "TOTP (\uc2dc\uac04 \uae30\ubc18 OTP)"

View File

@@ -1,5 +1,24 @@
{
"mfa_setup": {
"notify": {
"abort": {
"no_available_service": "Geen meldingsservices beschikbaar."
},
"error": {
"invalid_code": "Ongeldige code, probeer opnieuw."
},
"step": {
"init": {
"description": "Selecteer een van de meldingsdiensten:",
"title": "Stel een \u00e9\u00e9nmalig wachtwoord in dat wordt afgegeven door een meldingscomponent"
},
"setup": {
"description": "Een \u00e9\u00e9nmalig wachtwoord is verzonden via **notify. {notify_service}**. Voer het hieronder in:",
"title": "Controleer de instellingen"
}
},
"title": "Eenmalig wachtwoord melden"
},
"totp": {
"error": {
"invalid_code": "Ongeldige code, probeer het opnieuw. Als u deze fout blijft krijgen, controleer dan of de klok van uw Home Assistant systeem correct is ingesteld."

View File

@@ -13,10 +13,11 @@
"title": "Skonfiguruj has\u0142o jednorazowe dostarczone przez komponent powiadomie\u0144"
},
"setup": {
"description": "Has\u0142o jednorazowe zosta\u0142o wys\u0142ane przez ** powiadom. {notify_service} **. Wpisz je poni\u017cej:",
"description": "Has\u0142o jednorazowe zosta\u0142o wys\u0142ane przez **notify.{notify_service}**. Wpisz je poni\u017cej:",
"title": "Sprawd\u017a konfiguracj\u0119"
}
}
},
"title": "Powiadomienie z has\u0142em jednorazowym"
},
"totp": {
"error": {

View File

@@ -1,5 +1,24 @@
{
"mfa_setup": {
"notify": {
"abort": {
"no_available_service": "Nenhum servi\u00e7o de notifica\u00e7\u00e3o dispon\u00edvel."
},
"error": {
"invalid_code": "C\u00f3digo inv\u00e1lido, por favor tente novamente."
},
"step": {
"init": {
"description": "Por favor, selecione um dos servi\u00e7os de notifica\u00e7\u00e3o:",
"title": "Configurar uma palavra passe entregue pela componente de notifica\u00e7\u00e3o"
},
"setup": {
"description": "Foi enviada uma palavra passe atrav\u00e9s de **notify.{notify_service}**. Por favor, insira-a:",
"title": "Verificar a configura\u00e7\u00e3o"
}
},
"title": "Notificar palavra passe de uso \u00fanico"
},
"totp": {
"error": {
"invalid_code": "C\u00f3digo inv\u00e1lido, por favor, tente novamente. Se receber este erro constantemente, por favor, certifique-se de que o rel\u00f3gio do sistema que hospeda o Home Assistent \u00e9 preciso."

View File

@@ -8,11 +8,16 @@
"invalid_code": "Ogiltig kod, var god f\u00f6rs\u00f6k igen."
},
"step": {
"init": {
"description": "Var god v\u00e4lj en av notifieringstj\u00e4nsterna:",
"title": "Konfigurera ett eng\u00e5ngsl\u00f6senord levererat genom notifieringskomponenten"
},
"setup": {
"description": "Ett eng\u00e5ngsl\u00f6senord har skickats av **notify.{notify_service}**. V\u00e4nligen ange det nedan:",
"title": "Verifiera installationen"
"title": "Verifiera inst\u00e4llningen"
}
}
},
"title": "Meddela eng\u00e5ngsl\u00f6senord"
},
"totp": {
"error": {

View File

@@ -25,7 +25,7 @@
},
"step": {
"init": {
"description": "\u6b32\u555f\u7528\u4e00\u6b21\u6027\u4e14\u5177\u6642\u6548\u6027\u7684\u5bc6\u78bc\u4e4b\u5169\u6b65\u9a5f\u9a57\u8b49\u529f\u80fd\uff0c\u8acb\u4f7f\u7528\u60a8\u7684\u9a57\u8b49 App \u6383\u7784\u4e0b\u65b9\u7684 QR code \u3002\u5018\u82e5\u60a8\u5c1a\u672a\u5b89\u88dd\u4efb\u4f55 App\uff0c\u63a8\u85a6\u60a8\u4f7f\u7528 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \u6216 [Authy](https://authy.com/)\u3002\n\n{qr_code}\n\n\u65bc\u6383\u63cf\u4e4b\u5f8c\uff0c\u8f38\u5165 App \u4e2d\u7684\u516d\u4f4d\u6578\u5b57\u9032\u884c\u8a2d\u5b9a\u9a57\u8b49\u3002\u5047\u5982\u6383\u63cf\u51fa\u73fe\u554f\u984c\uff0c\u8acb\u624b\u52d5\u8f38\u5165\u4ee5\u4e0b\u9a57\u8b49\u78bc **`{code}`**\u3002",
"description": "\u6b32\u555f\u7528\u4e00\u6b21\u6027\u4e14\u5177\u6642\u6548\u6027\u7684\u5bc6\u78bc\u4e4b\u5169\u6b65\u9a5f\u9a57\u8b49\u529f\u80fd\uff0c\u8acb\u4f7f\u7528\u60a8\u7684\u9a57\u8b49 App \u6383\u7784\u4e0b\u65b9\u7684 QR code \u3002\u5018\u82e5\u60a8\u5c1a\u672a\u5b89\u88dd\u4efb\u4f55 App\uff0c\u63a8\u85a6\u60a8\u4f7f\u7528 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \u6216 [Authy](https://authy.com/)\u3002\n\n{qr_code}\n\n\u65bc\u641c\u5c0b\u4e4b\u5f8c\uff0c\u8f38\u5165 App \u4e2d\u7684\u516d\u4f4d\u6578\u5b57\u9032\u884c\u8a2d\u5b9a\u9a57\u8b49\u3002\u5047\u5982\u641c\u5c0b\u51fa\u73fe\u554f\u984c\uff0c\u8acb\u624b\u52d5\u8f38\u5165\u4ee5\u4e0b\u9a57\u8b49\u78bc **`{code}`**\u3002",
"title": "\u4f7f\u7528 TOTP \u8a2d\u5b9a\u5169\u6b65\u9a5f\u9a57\u8b49"
}
},

View File

@@ -105,7 +105,6 @@ Home Assistant. User need to record the token in secure place.
"id": 11,
"type": "auth/long_lived_access_token",
"client_name": "GPS Logger",
"client_icon": null,
"lifespan": 365
}
@@ -433,7 +432,7 @@ def websocket_current_user(
"""Get current user."""
enabled_modules = await hass.auth.async_get_enabled_mfa(user)
connection.send_message_outside(
connection.send_message(
websocket_api.result_message(msg['id'], {
'id': user.id,
'name': user.name,
@@ -468,7 +467,7 @@ def websocket_create_long_lived_access_token(
access_token = hass.auth.async_create_access_token(
refresh_token)
connection.send_message_outside(
connection.send_message(
websocket_api.result_message(msg['id'], access_token))
hass.async_create_task(
@@ -480,8 +479,8 @@ def websocket_create_long_lived_access_token(
def websocket_refresh_tokens(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg):
"""Return metadata of users refresh tokens."""
current_id = connection.request.get('refresh_token_id')
connection.to_write.put_nowait(websocket_api.result_message(msg['id'], [{
current_id = connection.refresh_token_id
connection.send_message(websocket_api.result_message(msg['id'], [{
'id': refresh.id,
'client_id': refresh.client_id,
'client_name': refresh.client_name,
@@ -509,7 +508,7 @@ def websocket_delete_refresh_token(
await hass.auth.async_remove_refresh_token(refresh_token)
connection.send_message_outside(
connection.send_message(
websocket_api.result_message(msg['id'], {}))
hass.async_create_task(

View File

@@ -1,24 +1,13 @@
"""Helpers to resolve client ID/secret."""
import asyncio
from ipaddress import ip_address
from html.parser import HTMLParser
from ipaddress import ip_address, ip_network
from urllib.parse import urlparse, urljoin
import aiohttp
from aiohttp.client_exceptions import ClientError
# IP addresses of loopback interfaces
ALLOWED_IPS = (
ip_address('127.0.0.1'),
ip_address('::1'),
)
# RFC1918 - Address allocation for Private Internets
ALLOWED_NETWORKS = (
ip_network('10.0.0.0/8'),
ip_network('172.16.0.0/12'),
ip_network('192.168.0.0/16'),
)
from homeassistant.util.network import is_local
async def verify_redirect_uri(hass, client_id, redirect_uri):
@@ -185,9 +174,7 @@ def _parse_client_id(client_id):
# Not an ip address
pass
if (address is None or
address in ALLOWED_IPS or
any(address in network for network in ALLOWED_NETWORKS)):
if address is None or is_local(address):
return parts
raise ValueError('Hostname should be a domain name or local IP address')

View File

@@ -64,7 +64,7 @@ def websocket_setup_mfa(
if flow_id is not None:
result = await flow_manager.async_configure(
flow_id, msg.get('user_input'))
connection.send_message_outside(
connection.send_message(
websocket_api.result_message(
msg['id'], _prepare_result_json(result)))
return
@@ -72,7 +72,7 @@ def websocket_setup_mfa(
mfa_module_id = msg.get('mfa_module_id')
mfa_module = hass.auth.get_auth_mfa_module(mfa_module_id)
if mfa_module is None:
connection.send_message_outside(websocket_api.error_message(
connection.send_message(websocket_api.error_message(
msg['id'], 'no_module',
'MFA module {} is not found'.format(mfa_module_id)))
return
@@ -80,7 +80,7 @@ def websocket_setup_mfa(
result = await flow_manager.async_init(
mfa_module_id, data={'user_id': connection.user.id})
connection.send_message_outside(
connection.send_message(
websocket_api.result_message(
msg['id'], _prepare_result_json(result)))
@@ -99,13 +99,13 @@ def websocket_depose_mfa(
await hass.auth.async_disable_user_mfa(
connection.user, msg['mfa_module_id'])
except ValueError as err:
connection.send_message_outside(websocket_api.error_message(
connection.send_message(websocket_api.error_message(
msg['id'], 'disable_failed',
'Cannot disable MFA Module {}: {}'.format(
mfa_module_id, err)))
return
connection.send_message_outside(
connection.send_message(
websocket_api.result_message(
msg['id'], 'done'))

View File

@@ -17,15 +17,15 @@
"step": {
"init": {
"title": "Set up one-time password delivered by notify component",
"description": "Please select one of notify service:"
"description": "Please select one of the notification services:"
},
"setup": {
"title": "Verify setup",
"description": "A one-time password have sent by **notify.{notify_service}**. Please input it in below:"
"description": "A one-time password has been sent via **notify.{notify_service}**. Please enter it below:"
}
},
"abort": {
"no_available_service": "No available notify services."
"no_available_service": "No notification services available."
},
"error": {
"invalid_code": "Invalid code, please try again."

View File

@@ -17,7 +17,6 @@ from homeassistant.loader import bind_hass
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF,
SERVICE_TOGGLE, SERVICE_RELOAD, EVENT_HOMEASSISTANT_START, CONF_ID)
from homeassistant.components import logbook
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import extract_domain_configs, script, condition
from homeassistant.helpers.entity import ToggleEntity
@@ -115,49 +114,6 @@ def is_on(hass, entity_id):
return hass.states.is_state(entity_id, STATE_ON)
@bind_hass
def turn_on(hass, entity_id=None):
"""Turn on specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
@bind_hass
def turn_off(hass, entity_id=None):
"""Turn off specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
@bind_hass
def toggle(hass, entity_id=None):
"""Toggle specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
@bind_hass
def trigger(hass, entity_id=None):
"""Trigger specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TRIGGER, data)
@bind_hass
def reload(hass):
"""Reload the automation from config."""
hass.services.call(DOMAIN, SERVICE_RELOAD)
@bind_hass
def async_reload(hass):
"""Reload the automation from config.
Returns a coroutine object.
"""
return hass.services.async_call(DOMAIN, SERVICE_RELOAD)
async def async_setup(hass, config):
"""Set up the automation."""
component = EntityComponent(_LOGGER, DOMAIN, hass,
@@ -412,8 +368,8 @@ def _async_get_action(hass, config, name):
async def action(entity_id, variables, context):
"""Execute an action."""
_LOGGER.info('Executing %s', name)
logbook.async_log_entry(
hass, name, 'has been triggered', DOMAIN, entity_id)
hass.components.logbook.async_log_entry(
name, 'has been triggered', DOMAIN, entity_id)
await script_obj.async_run(variables, context)
return action

View File

@@ -4,7 +4,6 @@ Offer event listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#event-trigger
"""
import asyncio
import logging
import voluptuous as vol
@@ -25,8 +24,7 @@ TRIGGER_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for events based on configuration."""
event_type = config.get(CONF_EVENT_TYPE)
event_data_schema = vol.Schema(

View File

@@ -4,7 +4,6 @@ Offer Home Assistant core automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#homeassistant-trigger
"""
import asyncio
import logging
import voluptuous as vol
@@ -23,8 +22,7 @@ TRIGGER_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for events based on configuration."""
event = config.get(CONF_EVENT)

View File

@@ -4,7 +4,6 @@ Trigger an automation when a LiteJet switch is released.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/automation.litejet/
"""
import asyncio
import logging
import voluptuous as vol
@@ -33,8 +32,7 @@ TRIGGER_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for events based on configuration."""
number = config.get(CONF_NUMBER)
held_more_than = config.get(CONF_HELD_MORE_THAN)

View File

@@ -4,7 +4,6 @@ Offer MQTT listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#mqtt-trigger
"""
import asyncio
import json
import voluptuous as vol
@@ -25,8 +24,7 @@ TRIGGER_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for state changes based on configuration."""
topic = config.get(CONF_TOPIC)
payload = config.get(CONF_PAYLOAD)
@@ -51,6 +49,6 @@ def async_trigger(hass, config, action):
'trigger': data
})
remove = yield from mqtt.async_subscribe(
remove = await mqtt.async_subscribe(
hass, topic, mqtt_automation_listener)
return remove

View File

@@ -4,7 +4,6 @@ Offer numeric state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#numeric-state-trigger
"""
import asyncio
import logging
import voluptuous as vol
@@ -29,8 +28,7 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({
_LOGGER = logging.getLogger(__name__)
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID)
below = config.get(CONF_BELOW)

View File

@@ -4,7 +4,6 @@ Offer state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#state-trigger
"""
import asyncio
import voluptuous as vol
from homeassistant.core import callback
@@ -27,8 +26,7 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({
}), cv.key_dependency(CONF_FOR, CONF_TO))
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID)
from_state = config.get(CONF_FROM, MATCH_ALL)

View File

@@ -4,7 +4,6 @@ Offer sun based automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#sun-trigger
"""
import asyncio
from datetime import timedelta
import logging
@@ -25,8 +24,7 @@ TRIGGER_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for events based on configuration."""
event = config.get(CONF_EVENT)
offset = config.get(CONF_OFFSET)

View File

@@ -4,7 +4,6 @@ Offer template automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#template-trigger
"""
import asyncio
import logging
import voluptuous as vol
@@ -23,8 +22,7 @@ TRIGGER_SCHEMA = IF_ACTION_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for state changes based on configuration."""
value_template = config.get(CONF_VALUE_TEMPLATE)
value_template.hass = hass

View File

@@ -4,7 +4,6 @@ Offer time listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#time-trigger
"""
import asyncio
import logging
import voluptuous as vol
@@ -29,8 +28,7 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({
}), cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AT))
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for state changes based on configuration."""
if CONF_AT in config:
at_time = config.get(CONF_AT)

View File

@@ -0,0 +1,54 @@
"""
Offer webhook triggered automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#webhook-trigger
"""
from functools import partial
import logging
from aiohttp import hdrs
import voluptuous as vol
from homeassistant.core import callback
from homeassistant.const import CONF_PLATFORM
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ('webhook',)
_LOGGER = logging.getLogger(__name__)
CONF_WEBHOOK_ID = 'webhook_id'
TRIGGER_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): 'webhook',
vol.Required(CONF_WEBHOOK_ID): cv.string,
})
async def _handle_webhook(action, hass, webhook_id, request):
"""Handle incoming webhook."""
result = {
'platform': 'webhook',
'webhook_id': webhook_id,
}
if 'json' in request.headers.get(hdrs.CONTENT_TYPE, ''):
result['json'] = await request.json()
else:
result['data'] = await request.post()
hass.async_run_job(action, {'trigger': result})
async def async_trigger(hass, config, action):
"""Trigger based on incoming webhooks."""
webhook_id = config.get(CONF_WEBHOOK_ID)
hass.components.webhook.async_register(
webhook_id, partial(_handle_webhook, action))
@callback
def unregister():
"""Unregister webhook."""
hass.components.webhook.async_unregister(webhook_id)
return unregister

View File

@@ -4,7 +4,6 @@ Offer zone automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/docs/automation/trigger/#zone-trigger
"""
import asyncio
import voluptuous as vol
from homeassistant.core import callback
@@ -27,8 +26,7 @@ TRIGGER_SCHEMA = vol.Schema({
})
@asyncio.coroutine
def async_trigger(hass, config, action):
async def async_trigger(hass, config, action):
"""Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID)
zone_entity_id = config.get(CONF_ZONE)

View File

@@ -4,7 +4,6 @@ Support for ADS binary sensors.
For more details about this platform, please refer to the documentation.
https://home-assistant.io/components/binary_sensor.ads/
"""
import asyncio
import logging
import voluptuous as vol
@@ -50,8 +49,7 @@ class AdsBinarySensor(BinarySensorDevice):
self._ads_hub = ads_hub
self.ads_var = ads_var
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register device notification."""
def update(name, value):
"""Handle device notifications."""

View File

@@ -4,7 +4,6 @@ Support for AlarmDecoder zone states- represented as binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.alarmdecoder/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@@ -64,8 +63,7 @@ class AlarmDecoderBinarySensor(BinarySensorDevice):
self._relay_addr = relay_addr
self._relay_chan = relay_chan
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
self.hass.helpers.dispatcher.async_dispatcher_connect(
SIGNAL_ZONE_FAULT, self._fault_callback)

View File

@@ -4,8 +4,6 @@ Support for IP Webcam binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.android_ip_webcam/
"""
import asyncio
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.android_ip_webcam import (
KEY_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST, CONF_NAME)
@@ -13,9 +11,8 @@ from homeassistant.components.android_ip_webcam import (
DEPENDENCIES = ['android_ip_webcam']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the IP Webcam binary sensors."""
if discovery_info is None:
return
@@ -51,8 +48,7 @@ class IPWebcamBinarySensor(AndroidIPCamEntity, BinarySensorDevice):
"""Return true if the binary sensor is on."""
return self._state
@asyncio.coroutine
def async_update(self):
async def async_update(self):
"""Retrieve latest state."""
state, _ = self._ipcam.export_sensor(self._sensor)
self._state = state == 1.0

View File

@@ -4,7 +4,6 @@ Use Bayesian Inference to trigger a binary sensor.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.bayesian/
"""
import asyncio
import logging
from collections import OrderedDict
@@ -74,9 +73,8 @@ def update_probability(prior, prob_true, prob_false):
return probability
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Bayesian Binary sensor."""
name = config.get(CONF_NAME)
observations = config.get(CONF_OBSERVATIONS)
@@ -119,8 +117,7 @@ class BayesianBinarySensor(BinarySensorDevice):
'state': self._process_state
}
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Call when entity about to be added."""
@callback
def async_threshold_sensor_state_listener(entity, old_state,
@@ -214,7 +211,6 @@ class BayesianBinarySensor(BinarySensorDevice):
ATTR_PROBABILITY_THRESHOLD: self._probability_threshold,
}
@asyncio.coroutine
def async_update(self):
async def async_update(self):
"""Get the latest data and update the states."""
self._deviation = bool(self.probability >= self._probability_threshold)

View File

@@ -2,10 +2,11 @@
Support for Blink system camera control.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.blink/
https://home-assistant.io/components/binary_sensor.blink.
"""
from homeassistant.components.blink import DOMAIN
from homeassistant.components.blink import BLINK_DATA, BINARY_SENSORS
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.const import CONF_MONITORED_CONDITIONS
DEPENDENCIES = ['blink']
@@ -14,24 +15,27 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the blink binary sensors."""
if discovery_info is None:
return
data = hass.data[BLINK_DATA]
data = hass.data[DOMAIN].blink
devs = list()
for name in data.cameras:
devs.append(BlinkCameraMotionSensor(name, data))
devs.append(BlinkSystemSensor(data))
devs = []
for camera in data.sync.cameras:
for sensor_type in discovery_info[CONF_MONITORED_CONDITIONS]:
devs.append(BlinkBinarySensor(data, camera, sensor_type))
add_entities(devs, True)
class BlinkCameraMotionSensor(BinarySensorDevice):
class BlinkBinarySensor(BinarySensorDevice):
"""Representation of a Blink binary sensor."""
def __init__(self, name, data):
def __init__(self, data, camera, sensor_type):
"""Initialize the sensor."""
self._name = 'blink_' + name + '_motion_enabled'
self._camera_name = name
self.data = data
self._state = self.data.cameras[self._camera_name].armed
self._type = sensor_type
name, icon = BINARY_SENSORS[sensor_type]
self._name = "{} {} {}".format(BLINK_DATA, camera, name)
self._icon = icon
self._camera = data.sync.cameras[camera]
self._state = None
@property
def name(self):
@@ -46,29 +50,4 @@ class BlinkCameraMotionSensor(BinarySensorDevice):
def update(self):
"""Update sensor state."""
self.data.refresh()
self._state = self.data.cameras[self._camera_name].armed
class BlinkSystemSensor(BinarySensorDevice):
"""A representation of a Blink system sensor."""
def __init__(self, data):
"""Initialize the sensor."""
self._name = 'blink armed status'
self.data = data
self._state = self.data.arm
@property
def name(self):
"""Return the name of the blink sensor."""
return self._name.replace(" ", "_")
@property
def is_on(self):
"""Return the status of the sensor."""
return self._state
def update(self):
"""Update sensor state."""
self.data.refresh()
self._state = self.data.arm
self._state = self._camera.attributes[self._type]

View File

@@ -4,7 +4,6 @@ Reads vehicle status from BMW connected drive portal.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.bmw_connected_drive/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@@ -124,7 +123,10 @@ class BMWConnectedDriveSensor(BinarySensorDevice):
if not check_control_messages:
result['check_control_messages'] = 'OK'
else:
result['check_control_messages'] = check_control_messages
cbs_list = []
for message in check_control_messages:
cbs_list.append(message['ccmDescriptionShort'])
result['check_control_messages'] = cbs_list
elif self._attribute == 'charging_status':
result['charging_status'] = vehicle_state.charging_status.value
# pylint: disable=protected-access
@@ -190,8 +192,7 @@ class BMWConnectedDriveSensor(BinarySensorDevice):
"""Schedule a state update."""
self.schedule_update_ha_state(True)
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Add callback after being added to hass.
Show latest data after startup.

View File

@@ -4,7 +4,6 @@ Interfaces with Egardia/Woonveilig alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.egardia/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@@ -18,9 +17,8 @@ EGARDIA_TYPE_TO_DEVICE_CLASS = {'IR Sensor': 'motion',
'IR': 'motion'}
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Initialize the platform."""
if (discovery_info is None or
discovery_info[ATTR_DISCOVER_DEVICES] is None):

View File

@@ -4,7 +4,6 @@ Support for Envisalink zone states- represented as binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.envisalink/
"""
import asyncio
import logging
import datetime
@@ -22,9 +21,8 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['envisalink']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Envisalink binary sensor devices."""
configured_zones = discovery_info['zones']
@@ -56,8 +54,7 @@ class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorDevice):
_LOGGER.debug('Setting up zone: %s', zone_name)
super().__init__(zone_name, info, controller)
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_ZONE_UPDATE, self._update_callback)

View File

@@ -4,7 +4,6 @@ Provides a binary sensor which is a collection of ffmpeg tools.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.ffmpeg_motion/
"""
import asyncio
import logging
import voluptuous as vol
@@ -46,13 +45,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the FFmpeg binary motion sensor."""
manager = hass.data[DATA_FFMPEG]
if not manager.async_run_test(config.get(CONF_INPUT)):
if not await manager.async_run_test(config.get(CONF_INPUT)):
return
entity = FFmpegMotion(hass, manager, config)
@@ -98,8 +96,7 @@ class FFmpegMotion(FFmpegBinarySensor):
self.ffmpeg = SensorMotion(
manager.binary, hass.loop, self._async_callback)
@asyncio.coroutine
def _async_start_ffmpeg(self, entity_ids):
async def _async_start_ffmpeg(self, entity_ids):
"""Start a FFmpeg instance.
This method is a coroutine.
@@ -116,7 +113,7 @@ class FFmpegMotion(FFmpegBinarySensor):
)
# run
yield from self.ffmpeg.open_sensor(
await self.ffmpeg.open_sensor(
input_source=self._config.get(CONF_INPUT),
extra_cmd=self._config.get(CONF_EXTRA_ARGUMENTS),
)

View File

@@ -4,7 +4,6 @@ Provides a binary sensor which is a collection of ffmpeg tools.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.ffmpeg_noise/
"""
import asyncio
import logging
import voluptuous as vol
@@ -43,13 +42,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the FFmpeg noise binary sensor."""
manager = hass.data[DATA_FFMPEG]
if not manager.async_run_test(config.get(CONF_INPUT)):
if not await manager.async_run_test(config.get(CONF_INPUT)):
return
entity = FFmpegNoise(hass, manager, config)
@@ -67,8 +65,7 @@ class FFmpegNoise(FFmpegBinarySensor):
self.ffmpeg = SensorNoise(
manager.binary, hass.loop, self._async_callback)
@asyncio.coroutine
def _async_start_ffmpeg(self, entity_ids):
async def _async_start_ffmpeg(self, entity_ids):
"""Start a FFmpeg instance.
This method is a coroutine.
@@ -82,7 +79,7 @@ class FFmpegNoise(FFmpegBinarySensor):
peak=self._config.get(CONF_PEAK),
)
yield from self.ffmpeg.open_sensor(
await self.ffmpeg.open_sensor(
input_source=self._config.get(CONF_INPUT),
output_dest=self._config.get(CONF_OUTPUT),
extra_cmd=self._config.get(CONF_EXTRA_ARGUMENTS),

View File

@@ -0,0 +1,64 @@
"""
Support for Fritzbox binary sensors.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.fritzbox/
"""
import logging
import requests
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.fritzbox import DOMAIN as FRITZBOX_DOMAIN
DEPENDENCIES = ['fritzbox']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Fritzbox binary sensor platform."""
devices = []
fritz_list = hass.data[FRITZBOX_DOMAIN]
for fritz in fritz_list:
device_list = fritz.get_devices()
for device in device_list:
if device.has_alarm:
devices.append(FritzboxBinarySensor(device, fritz))
add_entities(devices, True)
class FritzboxBinarySensor(BinarySensorDevice):
"""Representation of a binary Fritzbox device."""
def __init__(self, device, fritz):
"""Initialize the Fritzbox binary sensor."""
self._device = device
self._fritz = fritz
@property
def name(self):
"""Return the name of the entity."""
return self._device.name
@property
def device_class(self):
"""Return the class of this sensor."""
return 'window'
@property
def is_on(self):
"""Return true if sensor is on."""
if not self._device.present:
return False
return self._device.alert_state
def update(self):
"""Get latest data from the Fritzbox."""
try:
self._device.update()
except requests.exceptions.HTTPError as ex:
_LOGGER.warning("Connection error: %s", ex)
self._fritz.login()

View File

@@ -4,7 +4,6 @@ Support for INSTEON dimmers via PowerLinc Modem.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.insteon/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@@ -22,9 +21,8 @@ SENSOR_TYPES = {'openClosedSensor': 'opening',
'batterySensor': 'battery'}
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the INSTEON device class for the hass platform."""
insteon_modem = hass.data['insteon'].get('modem')

View File

@@ -4,8 +4,6 @@ Support for ISY994 binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.isy994/
"""
import asyncio
import logging
from datetime import timedelta
from typing import Callable
@@ -121,10 +119,9 @@ class ISYBinarySensorDevice(ISYDevice, BinarySensorDevice):
self._computed_state = bool(self._node.status._val)
self._status_was_unknown = False
@asyncio.coroutine
def async_added_to_hass(self) -> None:
async def async_added_to_hass(self) -> None:
"""Subscribe to the node and subnode event emitters."""
yield from super().async_added_to_hass()
await super().async_added_to_hass()
self._node.controlEvents.subscribe(self._positive_node_control_handler)
@@ -261,10 +258,9 @@ class ISYBinarySensorHeartbeat(ISYDevice, BinarySensorDevice):
self._parent_device = parent_device
self._heartbeat_timer = None
@asyncio.coroutine
def async_added_to_hass(self) -> None:
async def async_added_to_hass(self) -> None:
"""Subscribe to the node and subnode event emitters."""
yield from super().async_added_to_hass()
await super().async_added_to_hass()
self._node.controlEvents.subscribe(
self._heartbeat_node_control_handler)

View File

@@ -4,23 +4,26 @@ Support for MQTT binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.mqtt/
"""
import asyncio
import logging
from typing import Optional
import voluptuous as vol
from homeassistant.core import callback
from homeassistant.components import mqtt
from homeassistant.components import mqtt, binary_sensor
from homeassistant.components.binary_sensor import (
BinarySensorDevice, DEVICE_CLASSES_SCHEMA)
from homeassistant.const import (
CONF_FORCE_UPDATE, CONF_NAME, CONF_VALUE_TEMPLATE, CONF_PAYLOAD_ON,
CONF_PAYLOAD_OFF, CONF_DEVICE_CLASS)
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_AVAILABILITY_TOPIC, CONF_PAYLOAD_AVAILABLE,
CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, MqttAvailability)
ATTR_DISCOVERY_HASH, CONF_STATE_TOPIC, CONF_AVAILABILITY_TOPIC,
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS,
MqttAvailability, MqttDiscoveryUpdate)
from homeassistant.components.mqtt.discovery import MQTT_DISCOVERY_NEW
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
_LOGGER = logging.getLogger(__name__)
@@ -44,13 +47,28 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MQTT binary sensor."""
if discovery_info is not None:
config = PLATFORM_SCHEMA(discovery_info)
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
async_add_entities, discovery_info=None):
"""Set up MQTT binary sensor through configuration.yaml."""
await _async_setup_entity(hass, config, async_add_entities)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up MQTT binary sensor dynamically through MQTT discovery."""
async def async_discover(discovery_payload):
"""Discover and add a MQTT binary sensor."""
config = PLATFORM_SCHEMA(discovery_payload)
await _async_setup_entity(hass, config, async_add_entities,
discovery_payload[ATTR_DISCOVERY_HASH])
async_dispatcher_connect(
hass, MQTT_DISCOVERY_NEW.format(binary_sensor.DOMAIN, 'mqtt'),
async_discover)
async def _async_setup_entity(hass, config, async_add_entities,
discovery_hash=None):
"""Set up the MQTT binary sensor."""
value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is not None:
value_template.hass = hass
@@ -68,19 +86,22 @@ def async_setup_platform(hass, config, async_add_entities,
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
value_template,
config.get(CONF_UNIQUE_ID),
discovery_hash,
)])
class MqttBinarySensor(MqttAvailability, BinarySensorDevice):
class MqttBinarySensor(MqttAvailability, MqttDiscoveryUpdate,
BinarySensorDevice):
"""Representation a binary sensor that is updated by MQTT."""
def __init__(self, name, state_topic, availability_topic, device_class,
qos, force_update, payload_on, payload_off, payload_available,
payload_not_available, value_template,
unique_id: Optional[str]):
unique_id: Optional[str], discovery_hash):
"""Initialize the MQTT binary sensor."""
super().__init__(availability_topic, qos, payload_available,
payload_not_available)
MqttAvailability.__init__(self, availability_topic, qos,
payload_available, payload_not_available)
MqttDiscoveryUpdate.__init__(self, discovery_hash)
self._name = name
self._state = None
self._state_topic = state_topic
@@ -91,11 +112,12 @@ class MqttBinarySensor(MqttAvailability, BinarySensorDevice):
self._force_update = force_update
self._template = value_template
self._unique_id = unique_id
self._discovery_hash = discovery_hash
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Subscribe mqtt events."""
yield from super().async_added_to_hass()
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
@callback
def state_message_received(topic, payload, qos):
@@ -115,7 +137,7 @@ class MqttBinarySensor(MqttAvailability, BinarySensorDevice):
self.async_schedule_update_ha_state()
yield from mqtt.async_subscribe(
await mqtt.async_subscribe(
self.hass, self._state_topic, state_message_received, self._qos)
@property

View File

@@ -3,8 +3,6 @@
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.mychevy/
"""
import asyncio
import logging
from homeassistant.components.mychevy import (
@@ -22,9 +20,8 @@ SENSORS = [
]
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MyChevy sensors."""
if discovery_info is None:
return
@@ -75,8 +72,7 @@ class EVBinarySensor(BinarySensorDevice):
"""Return the car."""
return self._conn.get_car(self._car_vid)
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
self.hass.helpers.dispatcher.async_dispatcher_connect(
UPDATE_TOPIC, self.async_update_callback)

View File

@@ -4,7 +4,6 @@ Support for the myStrom buttons.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.mystrom/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice
@@ -16,9 +15,8 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['http']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up myStrom Binary Sensor."""
hass.http.register_view(MyStromView(async_add_entities))
@@ -37,14 +35,12 @@ class MyStromView(HomeAssistantView):
self.buttons = {}
self.add_entities = add_entities
@asyncio.coroutine
def get(self, request):
async def get(self, request):
"""Handle the GET request received from a myStrom button."""
res = yield from self._handle(request.app['hass'], request.query)
res = await self._handle(request.app['hass'], request.query)
return res
@asyncio.coroutine
def _handle(self, hass, data):
async def _handle(self, hass, data):
"""Handle requests to the myStrom endpoint."""
button_action = next((
parameter for parameter in data

View File

@@ -93,7 +93,11 @@ class OpenUvBinarySensor(OpenUvEntity, BinarySensorDevice):
async def async_update(self):
"""Update the state."""
data = self.openuv.data[DATA_PROTECTION_WINDOW]['result']
data = self.openuv.data[DATA_PROTECTION_WINDOW]
if not data:
return
if self._sensor_type == TYPE_PROTECTION_WINDOW:
self._state = parse_datetime(
data['from_time']) <= utcnow() <= parse_datetime(

View File

@@ -4,18 +4,19 @@ Tracks the latency of a host by sending ICMP echo requests (ping).
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.ping/
"""
import logging
import subprocess
import re
import sys
import asyncio
from datetime import timedelta
import logging
import re
import subprocess
import sys
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.const import CONF_NAME, CONF_HOST
PLATFORM_SCHEMA, BinarySensorDevice)
from homeassistant.const import CONF_HOST, CONF_NAME
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
@@ -48,13 +49,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the Ping Binary sensor."""
name = config.get(CONF_NAME)
host = config.get(CONF_HOST)
count = config.get(CONF_PING_COUNT)
add_entities([PingBinarySensor(name, PingData(host, count))], True)
async_add_entities([PingBinarySensor(name, PingData(host, count))], True)
class PingBinarySensor(BinarySensorDevice):
@@ -91,9 +93,9 @@ class PingBinarySensor(BinarySensorDevice):
ATTR_ROUND_TRIP_TIME_MIN: self.ping.data['min'],
}
def update(self):
async def async_update(self):
"""Get the latest data."""
self.ping.update()
await self.ping.update()
class PingData:
@@ -114,12 +116,13 @@ class PingData:
'ping', '-n', '-q', '-c', str(self._count), '-W1',
self._ip_address]
def ping(self):
async def ping(self):
"""Send ICMP echo request and return details if success."""
pinger = subprocess.Popen(
self._ping_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pinger = await asyncio.create_subprocess_shell(
' '.join(self._ping_cmd), stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
try:
out = pinger.communicate()
out = await pinger.communicate()
_LOGGER.debug("Output is %s", str(out))
if sys.platform == 'win32':
match = WIN32_PING_MATCHER.search(str(out).split('\n')[-1])
@@ -128,7 +131,8 @@ class PingData:
'min': rtt_min,
'avg': rtt_avg,
'max': rtt_max,
'mdev': ''}
'mdev': '',
}
if 'max/' not in str(out):
match = PING_MATCHER_BUSYBOX.search(str(out).split('\n')[-1])
rtt_min, rtt_avg, rtt_max = match.groups()
@@ -136,18 +140,20 @@ class PingData:
'min': rtt_min,
'avg': rtt_avg,
'max': rtt_max,
'mdev': ''}
'mdev': '',
}
match = PING_MATCHER.search(str(out).split('\n')[-1])
rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups()
return {
'min': rtt_min,
'avg': rtt_avg,
'max': rtt_max,
'mdev': rtt_mdev}
'mdev': rtt_mdev,
}
except (subprocess.CalledProcessError, AttributeError):
return False
def update(self):
async def update(self):
"""Retrieve the latest details from the host."""
self.data = self.ping()
self.data = await self.ping()
self.available = bool(self.data)

View File

@@ -92,6 +92,11 @@ class RachioControllerOnlineBinarySensor(RachioControllerBinarySensor):
"""Return the name of this sensor including the controller name."""
return "{} online".format(self._controller.name)
@property
def unique_id(self) -> str:
"""Return a unique id for this entity."""
return "{}-online".format(self._controller.controller_id)
@property
def device_class(self) -> str:
"""Return the class of this device, from component DEVICE_CLASSES."""

View File

@@ -4,7 +4,6 @@ Support for Satel Integra zone states- represented as binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.satel_integra/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@@ -20,9 +19,8 @@ DEPENDENCIES = ['satel_integra']
_LOGGER = logging.getLogger(__name__)
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Satel Integra binary sensor devices."""
if not discovery_info:
return
@@ -50,8 +48,7 @@ class SatelIntegraBinarySensor(BinarySensorDevice):
self._zone_type = zone_type
self._state = 0
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_ZONES_UPDATED, self._zones_updated)

View File

@@ -9,8 +9,7 @@ import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.core import callback
from homeassistant.components.spc import (
ATTR_DISCOVER_DEVICES, SIGNAL_UPDATE_SENSOR)
from homeassistant.components.spc import (DATA_API, SIGNAL_UPDATE_SENSOR)
_LOGGER = logging.getLogger(__name__)
@@ -27,13 +26,12 @@ def _get_device_class(zone_type):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the SPC binary sensor."""
if (discovery_info is None or
discovery_info[ATTR_DISCOVER_DEVICES] is None):
if discovery_info is None:
return
async_add_entities(SpcBinarySensor(zone)
for zone in discovery_info[ATTR_DISCOVER_DEVICES]
if _get_device_class(zone.type))
api = hass.data[DATA_API]
async_add_entities([SpcBinarySensor(zone)
for zone in api.zones.values()
if _get_device_class(zone.type)])
class SpcBinarySensor(BinarySensorDevice):

View File

@@ -4,7 +4,6 @@ Support for exposing a templated binary sensor.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.template/
"""
import asyncio
import logging
import voluptuous as vol
@@ -46,9 +45,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up template binary sensors."""
sensors = []
@@ -109,8 +107,7 @@ class BinarySensorTemplate(BinarySensorDevice):
self._delay_on = delay_on
self._delay_off = delay_off
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Register callbacks."""
@callback
def template_bsensor_state_listener(entity, old_state, new_state):

View File

@@ -4,7 +4,6 @@ Support for monitoring if a sensor value is below/above a threshold.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.threshold/
"""
import asyncio
import logging
import voluptuous as vol
@@ -54,9 +53,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Threshold sensor."""
entity_id = config.get(CONF_ENTITY_ID)
name = config.get(CONF_NAME)
@@ -147,8 +145,7 @@ class ThresholdSensor(BinarySensorDevice):
ATTR_UPPER: self._threshold_upper,
}
@asyncio.coroutine
def async_update(self):
async def async_update(self):
"""Get the latest data and updates the states."""
def below(threshold):
"""Determine if the sensor value is below a threshold."""

View File

@@ -4,7 +4,6 @@ A sensor that monitors trends in other components.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.trend/
"""
import asyncio
from collections import deque
import logging
import math
@@ -138,8 +137,7 @@ class SensorTrend(BinarySensorDevice):
"""No polling needed."""
return False
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Complete device setup after being added to hass."""
@callback
def trend_sensor_state_listener(entity, old_state, new_state):
@@ -160,8 +158,7 @@ class SensorTrend(BinarySensorDevice):
self.hass, self._entity_id,
trend_sensor_state_listener)
@asyncio.coroutine
def async_update(self):
async def async_update(self):
"""Get the latest data and update the states."""
# Remove outdated samples
if self._sample_duration > 0:
@@ -173,7 +170,7 @@ class SensorTrend(BinarySensorDevice):
return
# Calculate gradient of linear trend
yield from self.hass.async_add_job(self._calculate_gradient)
await self.hass.async_add_job(self._calculate_gradient)
# Update state
self._state = (

View File

@@ -4,7 +4,6 @@ Support for Wink binary sensors.
For more details about this platform, please refer to the documentation at
at https://home-assistant.io/components/binary_sensor.wink/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@@ -101,8 +100,7 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice):
else:
self.capability = None
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Call when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['binary_sensor'].append(self)

View File

@@ -4,7 +4,6 @@ Sensor to indicate whether the current day is a workday.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.workday/
"""
import asyncio
import logging
from datetime import datetime, timedelta
@@ -162,8 +161,7 @@ class IsWorkdaySensor(BinarySensorDevice):
CONF_OFFSET: self._days_offset
}
@asyncio.coroutine
def async_update(self):
async def async_update(self):
"""Get date and look whether it is a holiday."""
# Default is no workday
self._state = False

View File

@@ -1,89 +0,0 @@
"""
Support for Blink Home Camera System.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/blink/
"""
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
CONF_USERNAME, CONF_PASSWORD, ATTR_FRIENDLY_NAME, ATTR_ARMED)
from homeassistant.helpers import discovery
REQUIREMENTS = ['blinkpy==0.6.0']
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'blink'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string
})
}, extra=vol.ALLOW_EXTRA)
ARM_SYSTEM_SCHEMA = vol.Schema({
vol.Optional(ATTR_ARMED): cv.boolean
})
ARM_CAMERA_SCHEMA = vol.Schema({
vol.Required(ATTR_FRIENDLY_NAME): cv.string,
vol.Optional(ATTR_ARMED): cv.boolean
})
SNAP_PICTURE_SCHEMA = vol.Schema({
vol.Required(ATTR_FRIENDLY_NAME): cv.string
})
class BlinkSystem:
"""Blink System class."""
def __init__(self, config_info):
"""Initialize the system."""
import blinkpy
self.blink = blinkpy.Blink(username=config_info[DOMAIN][CONF_USERNAME],
password=config_info[DOMAIN][CONF_PASSWORD])
self.blink.setup_system()
def setup(hass, config):
"""Set up Blink System."""
hass.data[DOMAIN] = BlinkSystem(config)
discovery.load_platform(hass, 'camera', DOMAIN, {}, config)
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
def snap_picture(call):
"""Take a picture."""
cameras = hass.data[DOMAIN].blink.cameras
name = call.data.get(ATTR_FRIENDLY_NAME, '')
if name in cameras:
cameras[name].snap_picture()
def arm_camera(call):
"""Arm a camera."""
cameras = hass.data[DOMAIN].blink.cameras
name = call.data.get(ATTR_FRIENDLY_NAME, '')
value = call.data.get(ATTR_ARMED, True)
if name in cameras:
cameras[name].set_motion_detect(value)
def arm_system(call):
"""Arm the system."""
value = call.data.get(ATTR_ARMED, True)
hass.data[DOMAIN].blink.arm = value
hass.data[DOMAIN].blink.refresh()
hass.services.register(
DOMAIN, 'snap_picture', snap_picture, schema=SNAP_PICTURE_SCHEMA)
hass.services.register(
DOMAIN, 'arm_camera', arm_camera, schema=ARM_CAMERA_SCHEMA)
hass.services.register(
DOMAIN, 'arm_system', arm_system, schema=ARM_SYSTEM_SCHEMA)
return True

View File

@@ -0,0 +1,161 @@
"""
Support for Blink Home Camera System.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/blink/
"""
import logging
from datetime import timedelta
import voluptuous as vol
from homeassistant.helpers import (
config_validation as cv, discovery)
from homeassistant.const import (
CONF_USERNAME, CONF_PASSWORD, CONF_NAME, CONF_SCAN_INTERVAL,
CONF_BINARY_SENSORS, CONF_SENSORS, CONF_FILENAME,
CONF_MONITORED_CONDITIONS, TEMP_FAHRENHEIT)
REQUIREMENTS = ['blinkpy==0.9.0']
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'blink'
BLINK_DATA = 'blink'
CONF_CAMERA = 'camera'
CONF_ALARM_CONTROL_PANEL = 'alarm_control_panel'
DEFAULT_BRAND = 'Blink'
DEFAULT_ATTRIBUTION = "Data provided by immedia-semi.com"
SIGNAL_UPDATE_BLINK = "blink_update"
DEFAULT_SCAN_INTERVAL = timedelta(seconds=60)
TYPE_CAMERA_ARMED = 'motion_enabled'
TYPE_MOTION_DETECTED = 'motion_detected'
TYPE_TEMPERATURE = 'temperature'
TYPE_BATTERY = 'battery'
TYPE_WIFI_STRENGTH = 'wifi_strength'
TYPE_STATUS = 'status'
SERVICE_REFRESH = 'blink_update'
SERVICE_TRIGGER = 'trigger_camera'
SERVICE_SAVE_VIDEO = 'save_video'
BINARY_SENSORS = {
TYPE_CAMERA_ARMED: ['Camera Armed', 'mdi:verified'],
TYPE_MOTION_DETECTED: ['Motion Detected', 'mdi:run-fast'],
}
SENSORS = {
TYPE_TEMPERATURE: ['Temperature', TEMP_FAHRENHEIT, 'mdi:thermometer'],
TYPE_BATTERY: ['Battery', '%', 'mdi:battery-80'],
TYPE_WIFI_STRENGTH: ['Wifi Signal', 'dBm', 'mdi:wifi-strength-2'],
TYPE_STATUS: ['Status', '', 'mdi:bell']
}
BINARY_SENSOR_SCHEMA = vol.Schema({
vol.Optional(CONF_MONITORED_CONDITIONS, default=list(BINARY_SENSORS)):
vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)])
})
SENSOR_SCHEMA = vol.Schema({
vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSORS)):
vol.All(cv.ensure_list, [vol.In(SENSORS)])
})
SERVICE_TRIGGER_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.string
})
SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_FILENAME): cv.string,
})
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN:
vol.Schema({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL):
cv.time_period,
vol.Optional(CONF_BINARY_SENSORS, default={}):
BINARY_SENSOR_SCHEMA,
vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA,
})
},
extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Set up Blink System."""
from blinkpy import blinkpy
conf = config[BLINK_DATA]
username = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]
scan_interval = conf[CONF_SCAN_INTERVAL]
hass.data[BLINK_DATA] = blinkpy.Blink(username=username,
password=password)
hass.data[BLINK_DATA].refresh_rate = scan_interval.total_seconds()
hass.data[BLINK_DATA].start()
platforms = [
('alarm_control_panel', {}),
('binary_sensor', conf[CONF_BINARY_SENSORS]),
('camera', {}),
('sensor', conf[CONF_SENSORS]),
]
for component, schema in platforms:
discovery.load_platform(hass, component, DOMAIN, schema, config)
def trigger_camera(call):
"""Trigger a camera."""
cameras = hass.data[BLINK_DATA].sync.cameras
name = call.data[CONF_NAME]
if name in cameras:
cameras[name].snap_picture()
hass.data[BLINK_DATA].refresh(force_cache=True)
def blink_refresh(event_time):
"""Call blink to refresh info."""
hass.data[BLINK_DATA].refresh(force_cache=True)
async def async_save_video(call):
"""Call save video service handler."""
await async_handle_save_video_service(hass, call)
hass.services.register(DOMAIN, SERVICE_REFRESH, blink_refresh)
hass.services.register(DOMAIN,
SERVICE_TRIGGER,
trigger_camera,
schema=SERVICE_TRIGGER_SCHEMA)
hass.services.register(DOMAIN,
SERVICE_SAVE_VIDEO,
async_save_video,
schema=SERVICE_SAVE_VIDEO_SCHEMA)
return True
async def async_handle_save_video_service(hass, call):
"""Handle save video service calls."""
camera_name = call.data[CONF_NAME]
video_path = call.data[CONF_FILENAME]
if not hass.config.is_allowed_path(video_path):
_LOGGER.error(
"Can't write %s, no access to path!", video_path)
return
def _write_video(camera_name, video_path):
"""Call video write."""
all_cameras = hass.data[BLINK_DATA].sync.cameras
if camera_name in all_cameras:
all_cameras[camera_name].video_to_file(video_path)
try:
await hass.async_add_executor_job(
_write_video, camera_name, video_path)
except OSError as err:
_LOGGER.error("Can't write image to file: %s", err)

View File

@@ -0,0 +1,21 @@
# Describes the format for available Blink services
blink_update:
description: Force a refresh.
trigger_camera:
description: Request named camera to take new image.
fields:
name:
description: Name of camera to take new image.
example: 'Living Room'
save_video:
description: Save last recorded video clip to local file.
fields:
name:
description: Name of camera to grab video from.
example: 'Living Room'
filename:
description: Filename to writable path (directory may need to be included in whitelist_dirs in config)
example: '/tmp/video.mp4'

View File

@@ -14,7 +14,7 @@ from homeassistant.helpers import discovery
from homeassistant.helpers.event import track_utc_time_change
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['bimmer_connected==0.5.2']
REQUIREMENTS = ['bimmer_connected==0.5.3']
_LOGGER = logging.getLogger(__name__)

View File

@@ -83,62 +83,6 @@ class Image:
content = attr.ib(type=bytes)
@bind_hass
def turn_off(hass, entity_id=None):
"""Turn off camera."""
hass.add_job(async_turn_off, hass, entity_id)
@bind_hass
async def async_turn_off(hass, entity_id=None):
"""Turn off camera."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data)
@bind_hass
def turn_on(hass, entity_id=None):
"""Turn on camera."""
hass.add_job(async_turn_on, hass, entity_id)
@bind_hass
async def async_turn_on(hass, entity_id=None):
"""Turn on camera, and set operation mode."""
data = {}
if entity_id is not None:
data[ATTR_ENTITY_ID] = entity_id
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data)
@bind_hass
def enable_motion_detection(hass, entity_id=None):
"""Enable Motion Detection."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(
DOMAIN, SERVICE_ENABLE_MOTION, data))
@bind_hass
def disable_motion_detection(hass, entity_id=None):
"""Disable Motion Detection."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(
DOMAIN, SERVICE_DISABLE_MOTION, data))
@bind_hass
@callback
def async_snapshot(hass, filename, entity_id=None):
"""Make a snapshot from a camera."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
data[ATTR_FILENAME] = filename
hass.async_add_job(hass.services.async_call(
DOMAIN, SERVICE_SNAPSHOT, data))
@bind_hass
async def async_get_image(hass, entity_id, timeout=10):
"""Fetch an image from a camera entity."""
@@ -239,7 +183,7 @@ async def async_setup(hass, config):
"""Update tokens of the entities."""
for entity in component.entities:
entity.async_update_token()
hass.async_add_job(entity.async_update_ha_state())
hass.async_create_task(entity.async_update_ha_state())
hass.helpers.event.async_track_time_interval(
update_tokens, TOKEN_CHANGE_INTERVAL)
@@ -508,27 +452,23 @@ class CameraMjpegStream(CameraView):
raise web.HTTPBadRequest()
@callback
def websocket_camera_thumbnail(hass, connection, msg):
@websocket_api.async_response
async def websocket_camera_thumbnail(hass, connection, msg):
"""Handle get camera thumbnail websocket command.
Async friendly.
"""
async def send_camera_still():
"""Send a camera still."""
try:
image = await async_get_image(hass, msg['entity_id'])
connection.send_message_outside(websocket_api.result_message(
msg['id'], {
'content_type': image.content_type,
'content': base64.b64encode(image.content).decode('utf-8')
}
))
except HomeAssistantError:
connection.send_message_outside(websocket_api.error_message(
msg['id'], 'image_fetch_failed', 'Unable to fetch image'))
hass.async_add_job(send_camera_still())
try:
image = await async_get_image(hass, msg['entity_id'])
connection.send_message(websocket_api.result_message(
msg['id'], {
'content_type': image.content_type,
'content': base64.b64encode(image.content).decode('utf-8')
}
))
except HomeAssistantError:
connection.send_message(websocket_api.error_message(
msg['id'], 'image_fetch_failed', 'Unable to fetch image'))
async def async_handle_snapshot_service(camera, service):

View File

@@ -4,7 +4,6 @@ This component provides HA camera support for Abode Security System.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.abode/
"""
import asyncio
import logging
from datetime import timedelta
@@ -51,10 +50,9 @@ class AbodeCamera(AbodeDevice, Camera):
self._event = event
self._response = None
@asyncio.coroutine
def async_added_to_hass(self):
async def async_added_to_hass(self):
"""Subscribe Abode events."""
yield from super().async_added_to_hass()
await super().async_added_to_hass()
self.hass.async_add_job(
self._data.abode.events.add_timeline_callback,

View File

@@ -4,7 +4,6 @@ This component provides basic support for Amcrest IP cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.amcrest/
"""
import asyncio
import logging
from homeassistant.components.amcrest import (
@@ -21,9 +20,8 @@ DEPENDENCIES = ['amcrest', 'ffmpeg']
_LOGGER = logging.getLogger(__name__)
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up an Amcrest IP Camera."""
if discovery_info is None:
return
@@ -57,12 +55,11 @@ class AmcrestCam(Camera):
response = self._camera.snapshot(channel=self._resolution)
return response.data
@asyncio.coroutine
def handle_async_mjpeg_stream(self, request):
async def handle_async_mjpeg_stream(self, request):
"""Return an MJPEG stream."""
# The snapshot implementation is handled by the parent class
if self._stream_source == STREAM_SOURCE_LIST['snapshot']:
yield from super().handle_async_mjpeg_stream(request)
await super().handle_async_mjpeg_stream(request)
return
if self._stream_source == STREAM_SOURCE_LIST['mjpeg']:
@@ -72,7 +69,7 @@ class AmcrestCam(Camera):
stream_coro = websession.get(
streaming_url, auth=self._token, timeout=TIMEOUT)
yield from async_aiohttp_proxy_web(self.hass, request, stream_coro)
await async_aiohttp_proxy_web(self.hass, request, stream_coro)
else:
# streaming via fmpeg
@@ -80,13 +77,13 @@ class AmcrestCam(Camera):
streaming_url = self._camera.rtsp_url(typeno=self._resolution)
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
yield from stream.open_camera(
await stream.open_camera(
streaming_url, extra_cmd=self._ffmpeg_arguments)
yield from async_aiohttp_proxy_stream(
await async_aiohttp_proxy_stream(
self.hass, request, stream,
'multipart/x-mixed-replace;boundary=ffserver')
yield from stream.close()
await stream.close()
@property
def name(self):

View File

@@ -4,31 +4,27 @@ Support for Blink system camera.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.blink/
"""
from datetime import timedelta
import logging
import requests
from homeassistant.components.blink import DOMAIN
from homeassistant.components.blink import BLINK_DATA, DEFAULT_BRAND
from homeassistant.components.camera import Camera
from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['blink']
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
ATTR_VIDEO_CLIP = 'video'
ATTR_IMAGE = 'image'
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a Blink Camera."""
if discovery_info is None:
return
data = hass.data[DOMAIN].blink
devs = list()
for name in data.cameras:
devs.append(BlinkCamera(hass, config, data, name))
data = hass.data[BLINK_DATA]
devs = []
for name, camera in data.sync.cameras.items():
devs.append(BlinkCamera(data, name, camera))
add_entities(devs)
@@ -36,15 +32,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class BlinkCamera(Camera):
"""An implementation of a Blink Camera."""
def __init__(self, hass, config, data, name):
def __init__(self, data, name, camera):
"""Initialize a camera."""
super().__init__()
self.data = data
self.hass = hass
self._name = name
self.notifications = self.data.cameras[self._name].notifications
self._name = "{} {}".format(BLINK_DATA, name)
self._camera = camera
self.response = None
self.current_image = None
self.last_image = None
_LOGGER.debug("Initialized blink camera %s", self._name)
@property
@@ -52,30 +48,29 @@ class BlinkCamera(Camera):
"""Return the camera name."""
return self._name
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def request_image(self):
"""Request a new image from Blink servers."""
_LOGGER.debug("Requesting new image from blink servers")
image_url = self.check_for_motion()
header = self.data.cameras[self._name].header
self.response = requests.get(image_url, headers=header, stream=True)
@property
def device_state_attributes(self):
"""Return the camera attributes."""
return self._camera.attributes
def check_for_motion(self):
"""Check if motion has been detected since last update."""
self.data.refresh()
notifs = self.data.cameras[self._name].notifications
if notifs > self.notifications:
# We detected motion at some point
self.data.last_motion()
self.notifications = notifs
# Returning motion image currently not working
# return self.data.cameras[self._name].motion['image']
elif notifs < self.notifications:
self.notifications = notifs
def enable_motion_detection(self):
"""Enable motion detection for the camera."""
self._camera.set_motion_detect(True)
return self.data.camera_thumbs[self._name]
def disable_motion_detection(self):
"""Disable motion detection for the camera."""
self._camera.set_motion_detect(False)
@property
def motion_detection_enabled(self):
"""Return the state of the camera."""
return self._camera.armed
@property
def brand(self):
"""Return the camera brand."""
return DEFAULT_BRAND
def camera_image(self):
"""Return a still image response from the camera."""
self.request_image()
return self.response.content
return self._camera.image_from_cache.content

View File

@@ -75,35 +75,33 @@ class CanaryCamera(Camera):
"""Return the camera motion detection status."""
return not self._location.is_recording
@asyncio.coroutine
def async_camera_image(self):
async def async_camera_image(self):
"""Return a still image response from the camera."""
self.renew_live_stream_session()
from haffmpeg import ImageFrame, IMAGE_JPEG
ffmpeg = ImageFrame(self._ffmpeg.binary, loop=self.hass.loop)
image = yield from asyncio.shield(ffmpeg.get_image(
image = await asyncio.shield(ffmpeg.get_image(
self._live_stream_session.live_stream_url,
output_format=IMAGE_JPEG,
extra_cmd=self._ffmpeg_arguments), loop=self.hass.loop)
return image
@asyncio.coroutine
def handle_async_mjpeg_stream(self, request):
async def handle_async_mjpeg_stream(self, request):
"""Generate an HTTP MJPEG stream from the camera."""
if self._live_stream_session is None:
return
from haffmpeg import CameraMjpeg
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
yield from stream.open_camera(
await stream.open_camera(
self._live_stream_session.live_stream_url,
extra_cmd=self._ffmpeg_arguments)
yield from async_aiohttp_proxy_stream(
await async_aiohttp_proxy_stream(
self.hass, request, stream,
'multipart/x-mixed-replace;boundary=ffserver')
yield from stream.close()
await stream.close()
@Throttle(MIN_TIME_BETWEEN_SESSION_RENEW)
def renew_live_stream_session(self):

View File

@@ -27,9 +27,8 @@ _LOGGER = logging.getLogger(__name__)
_TIMEOUT = 10 # seconds
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the DoorBird camera platform."""
for doorstation in hass.data[DOORBIRD_DOMAIN]:
device = doorstation.device
@@ -66,8 +65,7 @@ class DoorBirdCamera(Camera):
"""Get the name of the camera."""
return self._name
@asyncio.coroutine
def async_camera_image(self):
async def async_camera_image(self):
"""Pull a still image from the camera."""
now = datetime.datetime.now()
@@ -77,9 +75,9 @@ class DoorBirdCamera(Camera):
try:
websession = async_get_clientsession(self.hass)
with async_timeout.timeout(_TIMEOUT, loop=self.hass.loop):
response = yield from websession.get(self._url)
response = await websession.get(self._url)
self._last_image = yield from response.read()
self._last_image = await response.read()
self._last_update = now
return self._last_image
except asyncio.TimeoutError:

View File

@@ -46,9 +46,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a generic IP Camera."""
async_add_entities([GenericCamera(hass, config)])
@@ -93,8 +92,7 @@ class GenericCamera(Camera):
return run_coroutine_threadsafe(
self.async_camera_image(), self.hass.loop).result()
@asyncio.coroutine
def async_camera_image(self):
async def async_camera_image(self):
"""Return a still image response from the camera."""
try:
url = self._still_image_url.async_render()
@@ -118,7 +116,7 @@ class GenericCamera(Camera):
_LOGGER.error("Error getting camera image: %s", error)
return self._last_image
self._last_image = yield from self.hass.async_add_job(
self._last_image = await self.hass.async_add_job(
fetch)
# async
else:
@@ -126,9 +124,9 @@ class GenericCamera(Camera):
websession = async_get_clientsession(
self.hass, verify_ssl=self.verify_ssl)
with async_timeout.timeout(10, loop=self.hass.loop):
response = yield from websession.get(
response = await websession.get(
url, auth=self._auth)
self._last_image = yield from response.read()
self._last_image = await response.read()
except asyncio.TimeoutError:
_LOGGER.error("Timeout getting camera image")
return self._last_image

View File

@@ -41,10 +41,17 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a MJPEG IP Camera."""
# Filter header errors from urllib3 due to a urllib3 bug
urllib3_logger = logging.getLogger("urllib3.connectionpool")
if not any(isinstance(x, NoHeaderErrorFilter)
for x in urllib3_logger.filters):
urllib3_logger.addFilter(
NoHeaderErrorFilter()
)
if discovery_info:
config = PLATFORM_SCHEMA(discovery_info)
async_add_entities([MjpegCamera(config)])
@@ -82,23 +89,22 @@ class MjpegCamera(Camera):
self._username, password=self._password
)
@asyncio.coroutine
def async_camera_image(self):
async def async_camera_image(self):
"""Return a still image response from the camera."""
# DigestAuth is not supported
if self._authentication == HTTP_DIGEST_AUTHENTICATION or \
self._still_image_url is None:
image = yield from self.hass.async_add_job(
image = await self.hass.async_add_job(
self.camera_image)
return image
websession = async_get_clientsession(self.hass)
try:
with async_timeout.timeout(10, loop=self.hass.loop):
response = yield from websession.get(
response = await websession.get(
self._still_image_url, auth=self._auth)
image = yield from response.read()
image = await response.read()
return image
except asyncio.TimeoutError:
@@ -141,3 +147,11 @@ class MjpegCamera(Camera):
def name(self):
"""Return the name of this camera."""
return self._name
class NoHeaderErrorFilter(logging.Filter):
"""Filter out urllib3 Header Parsing Errors due to a urllib3 bug."""
def filter(self, record):
"""Filter out Header Parsing Errors."""
return "Failed to parse headers" not in record.getMessage()

View File

@@ -10,10 +10,13 @@ import logging
import voluptuous as vol
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
from homeassistant.core import callback
from homeassistant.components import mqtt
from homeassistant.const import CONF_NAME
from homeassistant.components import mqtt, camera
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
from homeassistant.components.mqtt.discovery import MQTT_DISCOVERY_NEW
from homeassistant.helpers import config_validation as cv
_LOGGER = logging.getLogger(__name__)
@@ -31,13 +34,26 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MQTT Camera."""
if discovery_info is not None:
config = PLATFORM_SCHEMA(discovery_info)
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
async_add_entities, discovery_info=None):
"""Set up MQTT camera through configuration.yaml."""
await _async_setup_entity(hass, config, async_add_entities)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up MQTT camera dynamically through MQTT discovery."""
async def async_discover(discovery_payload):
"""Discover and add a MQTT camera."""
config = PLATFORM_SCHEMA(discovery_payload)
await _async_setup_entity(hass, config, async_add_entities)
async_dispatcher_connect(
hass, MQTT_DISCOVERY_NEW.format(camera.DOMAIN, 'mqtt'),
async_discover)
async def _async_setup_entity(hass, config, async_add_entities):
"""Set up the MQTT Camera."""
async_add_entities([MqttCamera(
config.get(CONF_NAME),
config.get(CONF_UNIQUE_ID),

View File

@@ -46,6 +46,7 @@ DIR_LEFT = "LEFT"
DIR_RIGHT = "RIGHT"
ZOOM_OUT = "ZOOM_OUT"
ZOOM_IN = "ZOOM_IN"
PTZ_NONE = "NONE"
SERVICE_PTZ = "onvif_ptz"
@@ -65,9 +66,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
SERVICE_PTZ_SCHEMA = vol.Schema({
ATTR_ENTITY_ID: cv.entity_ids,
ATTR_PAN: vol.In([DIR_LEFT, DIR_RIGHT]),
ATTR_TILT: vol.In([DIR_UP, DIR_DOWN]),
ATTR_ZOOM: vol.In([ZOOM_OUT, ZOOM_IN])
ATTR_PAN: vol.In([DIR_LEFT, DIR_RIGHT, PTZ_NONE]),
ATTR_TILT: vol.In([DIR_UP, DIR_DOWN, PTZ_NONE]),
ATTR_ZOOM: vol.In([ZOOM_OUT, ZOOM_IN, PTZ_NONE])
})

View File

@@ -110,8 +110,7 @@ class RingCam(Camera):
'video_url': self._video_url,
}
@asyncio.coroutine
def async_camera_image(self):
async def async_camera_image(self):
"""Return a still image response from the camera."""
from haffmpeg import ImageFrame, IMAGE_JPEG
ffmpeg = ImageFrame(self._ffmpeg.binary, loop=self.hass.loop)
@@ -119,13 +118,12 @@ class RingCam(Camera):
if self._video_url is None:
return
image = yield from asyncio.shield(ffmpeg.get_image(
image = await asyncio.shield(ffmpeg.get_image(
self._video_url, output_format=IMAGE_JPEG,
extra_cmd=self._ffmpeg_arguments), loop=self.hass.loop)
return image
@asyncio.coroutine
def handle_async_mjpeg_stream(self, request):
async def handle_async_mjpeg_stream(self, request):
"""Generate an HTTP MJPEG stream from the camera."""
from haffmpeg import CameraMjpeg
@@ -133,13 +131,13 @@ class RingCam(Camera):
return
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
yield from stream.open_camera(
await stream.open_camera(
self._video_url, extra_cmd=self._ffmpeg_arguments)
yield from async_aiohttp_proxy_stream(
await async_aiohttp_proxy_stream(
self.hass, request, stream,
'multipart/x-mixed-replace;boundary=ffserver')
yield from stream.close()
await stream.close()
@property
def should_poll(self):

View File

@@ -4,7 +4,6 @@ Support for Synology Surveillance Station Cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.synology/
"""
import asyncio
import logging
import requests
@@ -38,9 +37,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a Synology IP Camera."""
verify_ssl = config.get(CONF_VERIFY_SSL)
timeout = config.get(CONF_TIMEOUT)
@@ -87,15 +85,14 @@ class SynologyCamera(Camera):
"""Return bytes of camera image."""
return self._surveillance.get_camera_image(self._camera_id)
@asyncio.coroutine
def handle_async_mjpeg_stream(self, request):
async def handle_async_mjpeg_stream(self, request):
"""Return a MJPEG stream image response directly from the camera."""
streaming_url = self._camera.video_stream_url
websession = async_get_clientsession(self.hass, self._verify_ssl)
stream_coro = websession.get(streaming_url)
yield from async_aiohttp_proxy_web(self.hass, request, stream_coro)
await async_aiohttp_proxy_web(self.hass, request, stream_coro)
@property
def name(self):

View File

@@ -2,11 +2,11 @@
"config": {
"abort": {
"no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Google Cast \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.",
"single_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Google Cast."
"single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430."
},
"step": {
"confirm": {
"description": "\u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Google Cast?",
"description": "\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Google Cast?",
"title": "Google Cast"
}
},

View File

@@ -1,7 +1,7 @@
{
"config": {
"abort": {
"no_devices_found": "\u5728\u7db2\u8def\u4e0a\u627e\u4e0d\u5230 Google Cast \u8a2d\u5099\u3002",
"no_devices_found": "\u5728\u7db2\u8def\u4e0a\u627e\u4e0d\u5230 Google Cast \u88dd\u7f6e\u3002",
"single_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u6b21 Google Cast \u5373\u53ef\u3002"
},
"step": {

View File

@@ -10,7 +10,6 @@ import functools as ft
import voluptuous as vol
from homeassistant.loader import bind_hass
from homeassistant.helpers.temperature import display_temp as show_temp
from homeassistant.util.temperature import convert as convert_temperature
from homeassistant.helpers.entity_component import EntityComponent
@@ -20,7 +19,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_TURN_ON, SERVICE_TURN_OFF,
STATE_ON, STATE_OFF, STATE_UNKNOWN, TEMP_CELSIUS, PRECISION_WHOLE,
PRECISION_TENTHS, )
PRECISION_TENTHS)
DEFAULT_MIN_TEMP = 7
DEFAULT_MAX_TEMP = 35
@@ -142,107 +141,6 @@ SET_SWING_MODE_SCHEMA = vol.Schema({
})
@bind_hass
def set_away_mode(hass, away_mode, entity_id=None):
"""Turn all or specified climate devices away mode on."""
data = {
ATTR_AWAY_MODE: away_mode
}
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_AWAY_MODE, data)
@bind_hass
def set_hold_mode(hass, hold_mode, entity_id=None):
"""Set new hold mode."""
data = {
ATTR_HOLD_MODE: hold_mode
}
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_HOLD_MODE, data)
@bind_hass
def set_aux_heat(hass, aux_heat, entity_id=None):
"""Turn all or specified climate devices auxiliary heater on."""
data = {
ATTR_AUX_HEAT: aux_heat
}
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_AUX_HEAT, data)
@bind_hass
def set_temperature(hass, temperature=None, entity_id=None,
target_temp_high=None, target_temp_low=None,
operation_mode=None):
"""Set new target temperature."""
kwargs = {
key: value for key, value in [
(ATTR_TEMPERATURE, temperature),
(ATTR_TARGET_TEMP_HIGH, target_temp_high),
(ATTR_TARGET_TEMP_LOW, target_temp_low),
(ATTR_ENTITY_ID, entity_id),
(ATTR_OPERATION_MODE, operation_mode)
] if value is not None
}
_LOGGER.debug("set_temperature start data=%s", kwargs)
hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, kwargs)
@bind_hass
def set_humidity(hass, humidity, entity_id=None):
"""Set new target humidity."""
data = {ATTR_HUMIDITY: humidity}
if entity_id is not None:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_HUMIDITY, data)
@bind_hass
def set_fan_mode(hass, fan, entity_id=None):
"""Set all or specified climate devices fan mode on."""
data = {ATTR_FAN_MODE: fan}
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_FAN_MODE, data)
@bind_hass
def set_operation_mode(hass, operation_mode, entity_id=None):
"""Set new target operation mode."""
data = {ATTR_OPERATION_MODE: operation_mode}
if entity_id is not None:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_OPERATION_MODE, data)
@bind_hass
def set_swing_mode(hass, swing_mode, entity_id=None):
"""Set new target swing mode."""
data = {ATTR_SWING_MODE: swing_mode}
if entity_id is not None:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_SET_SWING_MODE, data)
async def async_setup(hass, config):
"""Set up climate devices."""
component = hass.data[DOMAIN] = \

Some files were not shown because too many files have changed in this diff Show More