Compare commits

..

567 Commits

Author SHA1 Message Date
Paulus Schoutsen
1ad495070d Bumped version to 0.94.0b1 2019-05-30 14:59:14 -07:00
Paulus Schoutsen
84719d944a Update hass-nabucasa (#24197) 2019-05-30 14:59:08 -07:00
Jc2k
4ca588deae homekit_controller no longer logs with transient network errors causing crypto failures as it will auto recover (#24193) 2019-05-30 14:59:07 -07:00
Otto Winter
325001933d Fix ESPHome discovered when already exists (#24187)
* Fix ESPHome discovered when already exists

* Update .coveragerc
2019-05-30 14:59:07 -07:00
Paulus Schoutsen
acc9fd0382 Dynamic panels (#24184)
* Don't require all panel urls to be registered

* Allow removing panels, fire event when panels updated
2019-05-30 14:59:06 -07:00
Pascal Vizeli
ca89d6184c Update azure-pipelines.yml for Azure Pipelines 2019-05-30 18:50:47 +02:00
Pascal Vizeli
2bfe7aa219 Update azure-pipelines.yml for check version (#24194) 2019-05-30 18:50:32 +02:00
Paulus Schoutsen
78ffb6f3e6 Updated frontend to 20190530.0 2019-05-30 09:32:37 -07:00
Paulus Schoutsen
c08862679d Bumped version to 0.94.0b0 2019-05-29 16:01:51 -07:00
Andre Lengwenus
50db622689 Add service calls for LCN component (#24105) 2019-05-29 15:59:38 -07:00
Jc2k
9303a56d8f Fix duplicated discovered homekit devices (#24178) 2019-05-29 15:49:59 -07:00
Paulus Schoutsen
6667138b73 Remove discovery from initial config (#24183) 2019-05-29 15:32:36 -07:00
Pascal Vizeli
d9852bc75d Support Hass.io wheels / docker env (#24175)
* Support Hass.io wheels / docker env

* address comments

* fix lint
2019-05-29 15:30:09 -07:00
Paulus Schoutsen
6aeccf0330 Merge remote-tracking branch 'origin/master' into dev 2019-05-29 15:16:05 -07:00
Anders Melchiorsen
f8572c1d71 Avoid slow updates with unavailable Sonos devices (#24180) 2019-05-29 15:05:12 -07:00
Robert Svensson
e2e001d042 Keep integrations in discovery (#24179)
* Keep integrations that have been migrated to new discovery methods to avoid breaking changes

* Additional migrated services
2019-05-29 14:34:44 -07:00
Paulus Schoutsen
e3307213b1 Deprecate Python 3.5.3 (#24177) 2019-05-29 14:30:00 -07:00
Robert Svensson
84baaa324c Revert Zeroconf back to previously used library (#24139)
* Revert back to previously used library

* Fix test

* Remove unused import

* Fix import

* Update __init__.py

* Update __init__.py

* Fix test after rebase
2019-05-29 14:20:06 -07:00
Robert Svensson
42ee8eef50 Move Homekit controller component to user zeroconf discovery (#24042) 2019-05-29 11:20:04 -07:00
Robert Svensson
3fef9a93cf Trådfri component to use new zeroconf discovery (#24041)
* Move tradfri component to use new zeroconf discovery

* Will this work?

* Remove prints

* Correct order in generated zeroconf

* Update test_init.py

* Update test_init.py

* Update test_init.py

* Update test_init.py
2019-05-29 11:19:50 -07:00
Paulus Schoutsen
4b256f3466 Reinstate passing loop to DSMR (#24127)
* Reinstate passing loop

* Also pass loop into other part
2019-05-29 11:13:29 -07:00
Anders Melchiorsen
bebfc3d16e Remove unused Sonos turn on/off methods (#24174) 2019-05-29 11:12:44 -07:00
Paulus Schoutsen
fd3902f7e7 update translations 2019-05-29 10:16:58 -07:00
Paulus Schoutsen
dfb992adb2 Updated frontend to 20190529.0 2019-05-29 09:41:35 -07:00
Robbie Trencheny
a252065f99 Fix calling notify.notify with mobile_app targets in play. Fixes #24064 (#24156) 2019-05-29 09:09:24 -07:00
Paulus Schoutsen
6947f8cb2e Cloud: Websocket API to manage Google assistant entity config (#24153)
* Extract exposed devices function

* Add might_2fa info to trait

* Do not filter with should_expose in Google helper func

* Cloud: allow setting if Google entity is exposed

* Allow disabling 2FA via config

* Cloud: allow disabling 2FA

* Lint

* More changes

* Fix typing
2019-05-29 08:39:12 -07:00
Morten Trab
85dfea1642 Add Repetier-Server Component (#21658)
* Bumped to version 2.0

* Updated requirements

* Updated requirements and coveragerc

* Removed long lines, changes to coveragerc and requirements

* Fixed under-indented lines

* Fixed invalid syntax

* Updated .coveragerc to include repetier/__init__.py and sensor.py

* Module update

* Rebased to latest dev

* Blank lines fix

* Add missing manifest.json

* Update requirements

* Bumped component to new API module style

* Removed whitespaces and line feeds

* Added missing newline

* Added missing heated chamber sensor

* Fixed wrong indentation

* Various fixes

* Various build fixes

* Clean up

* Load platform only once

* Sort imports

* Add printer api

* Clean up

* Build out sensor classes

* Clarify temperature sensor variable names

* Move constants

* Clean up name

* Run script/gen_requirements_all.py

* Working code, missing auto add of new sensors

* Updated code to return proper device_class and timestamp

* Removed unnessecary code

* Renamed elapsed and remaining sensors

* Dynamically adding sensors as they become available

* Rebased .coveragerc due to conflicts

* Code changes and cleanup

* Removed whitespace and code simplification
2019-05-29 08:31:04 -04:00
Otto Winter
015c8811a5 Use global imports for ESPHome (#24158)
* Use global import for ESPHome

* Add aioesphomeapi to test requirements

aioesphomeapi is also shipped as a pure-python wheel, so this should not impact test install time
2019-05-29 13:33:49 +02:00
Robbie Trencheny
d9c78b77cb Use device name for device_tracker entry (#24155) 2019-05-28 19:52:47 -07:00
chmielowiec
1b543cf538 Upgrade huawei-lte-api to 1.2.0 (#24165) 2019-05-28 19:51:07 -07:00
Alexei Chetroi
9fb8144031 Debug log when polling ZHA light. (#24167) 2019-05-28 19:50:48 -07:00
William Scanlon
f2033c418f Pubnub to 1.0.6 (#24159) 2019-05-28 12:09:30 -04:00
William Scanlon
aa266cb630 pubnubsub-handler to 1.0.5 (#24154) 2019-05-27 22:09:05 -04:00
Sylvia van Os
9a5d783537 Don't crash on first EAN without installations (#24137)
* Don't crash on first EAN without installations

* Remove duplicated values

* Switch from Exception to persistent notification

* Make pylint happy
2019-05-27 22:36:15 +02:00
Jesse Rizzo
5800b57791 bump dependency envoy_reader to 0.4 (#24145)
* bump envoy_reader version to 0.4

* bump dependency envoy_reader to 0.4
2019-05-27 19:48:00 +02:00
maheus
c840771c0a Add station name for creating the unique_id in netatmo platform (#24141) 2019-05-27 18:07:59 +02:00
Julien Brochet
9678752480 Retrieve wire and wireless devices with the SRM device tracker (#24117) 2019-05-27 18:00:21 +02:00
Robert Svensson
31b2f331db Library refactorization of deCONZ (#23725)
* Improved sensors

* Lib update signalling

* Replace reason with changed

* Move imports to top of file

* Add support for secondary temperature reported by some Xiaomi devices

* Bump dependency to v59
2019-05-27 06:56:00 +02:00
jjlawren
0ba54ee9b7 Use central polling to update entities (#24059)
* Use central polling to update entities

* Fix for line length

* Remove unnecessary import

* Use interval

* Trigger entity refreshes after commands

* Lint
2019-05-26 21:39:50 -07:00
Bram Kragten
5c86a51b45 Lovelace: Fire event on save (#24104)
* Lovelace: Fire event on save

* Add event to whitelist
2019-05-26 20:27:07 -07:00
Paulus Schoutsen
9debbfb1a8 Add SSDP integration (#24090)
* Add SSDP integration

* Fix tests

* Sort all the things

* Add netdisco to test requirements
2019-05-26 19:48:27 -07:00
Anders Melchiorsen
97b671171b Avoid useless Sonos state updates (#24135) 2019-05-26 12:49:26 -07:00
Paulus Schoutsen
179fb0f3b5 Use importlib metadata to check installed packages (#24114)
* Use importlib metadata

* Fix script

* Remove unused import

* Update requirements"
2019-05-26 11:58:42 -07:00
David Bonnes
96b7bb625d geniushub: fix sensor battery level, and bump client (#24123)
* Initial commit

* bump client
2019-05-26 14:01:29 +02:00
Eduard van Valkenburg
afeb13d980 Azure Event Hub history component (#23878)
* v1 of Azure Event Hub History component

* updates to EH

* small fix

* small updates and changed requirements_all

* new version of Event Hub component

* redid config to just ask names

* small edit

* latest version of EH component

* updated codeowners

* codeowner fix

* typo in domain

* updates based on reviews.

* using built-in jsonencoder for DT

* delete unused import
2019-05-26 13:55:40 +02:00
jgriff2
6e1728542e Add Remote RPi Component (#23518)
* Add Remote RPi Component

* Add Remote RPi Component

* fix imports

* Added support for setup as switch and binary_sensor

* remove pylint error handling

* Changed to domain config

* Changed to domain config

* Changed to domain config

* Changed to domain config

* Update __init__.py

* Update manifest.json

* Update requirements_all.txt

* Update switch.py

* Update binary_sensor.py

* Changed to domain config
2019-05-26 13:52:06 +02:00
Otto Winter
9438dd1cbd Use name in ESPHome discovery title (#24100)
* Use name in ESPHome discovery title

* Add test

* Lint
2019-05-26 13:48:05 +02:00
Andrew Sayre
0194905e97 Move imports to top (#24108) 2019-05-26 13:47:11 +02:00
jjlawren
25505dc1d4 Remove custom entity_id naming (#24072)
* Remove custom entity_id naming

* Set entity_ids with 'plex'

* Set name instead of entity_id

* Lint

* Use a name template
2019-05-26 12:28:29 +02:00
Jardi Martinez
ce219ac6c7 Set assumed_state property to True. (#24118) 2019-05-26 12:26:51 +02:00
cgtobi
fa20957e01 Bump pyatmo version to 1.12 (#24088) 2019-05-26 12:09:02 +02:00
Robin Wohlers-Reichel
7959c04d1e Solax Inverter Sensor Component (#22579)
* Solax inverter direct API

* Linter compliance

* lint++

* move api communication to external lib

* lint++

* requirements

* Revert "requirements"

This reverts commit 82a6c0c095.

* potentially?

* Addressing review comments

* Also update CODEOWNERS

* Only update sensor state if data has changed
2019-05-25 21:55:30 -05:00
Paulus Schoutsen
e6d7f6ed71 Config entry device tracker (#24040)
* Move zone helpers to zone root

* Add config entry support to device tracker

* Convert Geofency

* Convert GPSLogger

* Track unsub per entry

* Convert locative

* Migrate OwnTracks

* Lint

* location -> latitude, longitude props

* Lint

* lint

* Fix test
2019-05-25 13:34:53 -07:00
Alex Bahm
144b530045 Issue #23514 - fix invalid hue response (#23909)
Based on the discoveries in issue #23514, the periodic lack of response from emulated hue was due to an invalid value (null) being returned.
2019-05-25 13:07:23 -07:00
Kevin Fronczak
39ba99005a Fix broken blink motion detection (#24097) 2019-05-25 17:58:44 +02:00
Simon Nørager Sørensen
f867b025e5 Update code owner for Xiaomi TV (#24102)
* Update code owner

* Update CODEOWNERS
2019-05-25 17:57:16 +02:00
Andre Lengwenus
c928f82cbf Refactoring of LCN component (#23824)
* Moved helper functions to const.py

* Removed pypck attribute from LcnDevice

* Bump to pypck==0.6.0

* Added myself as a codeowner

* Moved helper functions to helpers.py
2019-05-25 11:40:44 +02:00
Joakim Plate
9d7aa8f05d Remove device tracker unnecessary separate except clause (#24081)
Handle exception where it can be thrown.
2019-05-25 11:29:19 +02:00
Daniel Høyer Iversen
02f927ae2d typo for ambiclimate (#24083) 2019-05-25 09:26:46 +02:00
Jardi Martinez
1d022522cd MCP23017 (#23127)
* Added support for MCP23017 I2C GPIO extender.

* Updated .coveragerc to exclude mcp23017 component from tests.

* Generated CODEOWNERS for mcp23017 usign script.

* Removed .svn folder that had been accidentally uploaded.

* Added link to www.home-assistant.io docs in manifest.json

* Fixed logic error in switch platform.

* Cleaned up code and removed unnecessary should_poll() function.

* Limited the options for pull mode to UP and DOWN

* Fixed line too long in binary sensor.

* Fixed line too long on switch.py

* Changed to setup_platform.

* Reorder constants
2019-05-25 08:09:53 +02:00
terual
bad9ac5395 Fix Hue bridge timeout (#24084)
* Change timeout from 5 seconds to 10 seconds
Underpowered platforms timeout during configuration/discovery of a Hue bridge on a new install. Increasing this timeout fixes this.
2019-05-24 15:55:13 -07:00
Joakim Plate
e9f561e7ab Adjust logging (#24082)
* Make sure we log full path to debug log

* Make sure we log the exception to debug log
2019-05-24 15:54:04 -07:00
Jeff Irion
14d169558f Add 'adb_response' attribute to Android TV / Fire TV (#23960)
* Add 'adb_response' attribute to Android TV / Fire TV

* Use None instead of empty string for empty ADB responses

* Initialize self._adb_response as None, not empty string

* Update the state after sending an ADB command

This ensures that the `'adb_response'` attribute contains the response to the latest command
2019-05-24 18:43:35 -04:00
P0L0
ca2a68217d Added possibility to define the data type of Homematic (#24078)
* Homematic: Added possibility to define the data type for set_device_value

* Fixed coding style

* Fixed variable name
2019-05-24 17:28:45 +02:00
dreed47
0a9a8ecc4e Update the name of Zestimate sensors (#23770)
* Zestimate: fix for issue #23757
Changed name property to return Zestimate
and the property address.  This will make it easier
distinguish multiple Zestimate sensor entities
in the UI.

Also removed MIN_TIME_BETWEEN_UPDATES in
favor of SCAN_INTERVAL per suggestion from
amelchio#9580 on Discord

* Zestimate fix for issue #23757

Changed name property to return Zestimate
and the property address.  This will make it easier
distinguish multiple Zestimate sensor entities
in the UI.

* Changed name property to return Zestimate
and the property address.  This will make it easier
distinguish multiple Zestimate sensor entities
in the UI.

* moved code fix to the correct function

* removed code change from unique_id function
2019-05-24 16:01:55 +02:00
Daniel Høyer Iversen
6cef850497 Rfxtrx, add data types (#24066)
* Rfxtrx, add data types

* fix style
2019-05-24 09:46:59 +02:00
Paulus Schoutsen
66af4bd011 Fix zeroconf sorting (#24068) 2019-05-23 14:41:57 -07:00
Jeff Irion
03253f4598 Better logging of method used for ADB connection (#24037) 2019-05-23 13:57:00 -07:00
Fredrik Erlandsson
aa5d8e5a81 Daikin airbase beta fixes (#24050)
* values are strings not integers

* pydaikin version bump
2019-05-23 13:55:22 -07:00
Paulus Schoutsen
206029eadc Update translations 2019-05-23 13:32:35 -07:00
Paulus Schoutsen
958c5ecbfe Updated frontend to 20190523.0 2019-05-23 13:32:16 -07:00
Troels Agergaard Jacobsen
3d79bf2bfe Fix entity id naming when not using first install (#23606)
* Fix entity id naming when not using first install

Currently, the verisure component will use the alias of the first
installation to decide entity id of the alarm_control_panel even though
a different installation is configured through a specified giid. This
fixes that

* Fixed pulled request review comments

* Remove trailing whitespace

* Fix remaining pylint errors
2019-05-23 19:27:42 +02:00
Paulus Schoutsen
1de0a0bbb9 Convert stream source to method (#23905)
* Convert stream source to method

* Use async with
2019-05-23 09:45:30 -07:00
jjlawren
8d22479d24 Always update all Plex client types (#24038) 2019-05-23 14:00:41 +02:00
Daniel Høyer Iversen
7f7435f003 Add support for available property for broadlink (#23981)
* Add support for available property for broadlink

* Broadlink, except oserror

* Broadlink, except oserror
2019-05-23 09:52:30 +02:00
Pascal Vizeli
d2eb5bb0f3 [skip ci] Update azure-pipelines.yml for Azure Pipelines 2019-05-23 09:46:40 +02:00
Robert Svensson
085303c349 ESPHome component to use zeroconf discovery (#24043)
* Move ESPHome component to use zeroconf discovery

* Remove esphome from discovery component
2019-05-23 08:55:08 +02:00
Daniel Høyer Iversen
9ac6f906ff Update ambiclimate library (#24049) 2019-05-23 08:53:38 +02:00
Paulus Schoutsen
f995ab9d54 Don't pass in loop (#23984)
* Don't pass in loop

* Revert some changes

* Lint + Axis revert

* reinstate loop

* Fix a test

* Set loop

* Update camera.py

* Lint
2019-05-22 21:09:59 -07:00
Paulus Schoutsen
77f595c9a4 Merge pull request #24047 from home-assistant/rc
0.93.2
2019-05-22 20:34:12 -07:00
Paulus Schoutsen
8d0b1588be Bumped version to 0.93.2 2019-05-22 20:00:34 -07:00
Daniel Høyer Iversen
70c5c82541 upgrade broadlink library (#23966) 2019-05-22 20:00:12 -07:00
Cyro
bf910ef383 Make Discord payload data key not required (#23964) 2019-05-22 20:00:11 -07:00
Julien Brochet
99c49c0993 Setup integration dependencies before loading it (#23957) 2019-05-22 20:00:10 -07:00
Joakim Sørensen
f6e6c21ba6 Fixes issue with multiple alerts (#23945)
* Fixes issue with multiple alerts

* Adds missing new line

* Remove whitespace
2019-05-22 20:00:10 -07:00
Joakim Sørensen
41b7f5ab1c Bump pytraccar (#23939) 2019-05-22 20:00:09 -07:00
Pascal Vizeli
c5bd6b3d6b Fix auto version update Hass.io (#23935) 2019-05-22 20:00:08 -07:00
Paulus Schoutsen
9e96397e6a Require core config detection to be triggerd manually (#24019)
* Detect core config

* Remove elevation

* Lint

* Lint

* Fix type
2019-05-22 17:24:46 -07:00
Fabian Affolter
f207e01510 Upgrade Mastodon.py to 1.4.2 (#24004)
* Upgrade Mastodon.py to 1.4.2

* Update
2019-05-22 23:05:03 +02:00
Daniel Høyer Iversen
6b3bb3347b Ambiclimate test, mock (#24034) 2019-05-22 15:00:05 +02:00
Paulus Schoutsen
806903ffe0 Downgrade Hue warning (#24033) 2019-05-22 14:59:16 +02:00
zewelor
fdf1fa48e3 Improve yeelight imports (#24020)
* Improve yeelight imports

* Move import on top

* Fix lint
2019-05-21 22:47:10 -04:00
Robert Svensson
636077c74d Zeroconf discovery for config entries (#23919)
* Proof of concept

* Follow comments

* Fix line length and bad imports

* Move imports to top

* Exception handling for unicode decoding
Create debug print for new service types
Add empty test files

* First try at a test

* Add type and name to service info
Fix static check

* Add aiozeroconf to test dependencies
2019-05-21 15:36:26 -07:00
David Bonnes
e047e4dcff bump geniushub-client to 0.4.9 (#24022) 2019-05-21 15:57:24 -04:00
Tyler Page
eae306c3f1 Fix iterating over NoneType exception (#23648)
* Fix iterating over NoneType exception

When self._dark_sky is None, don't try to return self._dark_sky.units

* Fix wrong check
2019-05-21 08:26:11 -04:00
David Bonnes
fbd7c72283 Add geniushub sensors for issues (#23976)
* Inital commit

* delint - use new string formatting
2019-05-21 08:23:38 -04:00
Erik Montnemery
fc58746bc3 Add websocket API for updating core config (#24009)
* Add websocket API for updating core config
2019-05-21 07:21:31 +02:00
Erik Montnemery
9ae878d8f2 Update CODEOWNERS (#24015) 2019-05-21 07:20:23 +02:00
Erik Montnemery
afe9fc221e Fire event when core config is updated (#23922)
* Fire event when core config is updated
2019-05-20 20:02:36 +02:00
Robert Svensson
eb912be47a Axis IO-port support (#23312)
Support digital inputs and supervised inputs, digital outputs and relays
2019-05-20 07:45:31 +02:00
Paulus Schoutsen
5c346e8fb6 Update owner frontend integrations [skip ci] (#24001) 2019-05-20 05:01:02 +02:00
Greg Dowling
8d388c5e79 Bump loopenergy library version - catches runtime exception. (#23989)
* Bump loopenergy library version - catches runtime exception.

* Update requirements_all.
2019-05-19 12:51:10 -04:00
Fredrik Erlandsson
314574fc84 daikin version bump (#23991) 2019-05-19 12:49:03 -04:00
Paulus Schoutsen
e356d0bcda Better handle file not found when loading YAML (#23908)
* Better handle file not found

* Lint
2019-05-19 12:01:29 +02:00
Penny Wood
f991ec15f2 Delete devices / entities when we remove a config entry. (#23983)
* Remove device when last config entry removed

* Remove entities when config entry removed

* Update tests to use new behaviour
2019-05-19 11:41:39 +02:00
Tomer Figenblat
d7d83c683d Updated non-blocking timout to 10 seconds for fixing timeout issues. (#23930)
* Updated non-blocking timout to 10 seconds for fixing timeout issues.

* Added failed bridge fixture for faster unit tests.
2019-05-19 11:24:59 +02:00
Joakim Sørensen
ff867a7d57 Use the timezone defined in Home Assistant when making the API call (#23284)
* Use HA defined timezone

* Cleanup

* Use homeassistant.util.dt.now to get the correct time.

* Update homeassistant/components/vasttrafik/sensor.py

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>
2019-05-19 11:23:55 +02:00
Charles Garwood
1282370ccb Entity Cleanup on Z-Wave node removal (#23633)
* Initial groundwork for entity cleanup on node removal

* Connect node_removed to dispatcher

* update docstring

* Add node_removal test

* Address review comments

* Use hass.add_job instead of run_coroutine_threadsafe
2019-05-19 11:14:11 +02:00
András Rutkai
eebd094423 Adding Watson TTS (IBM Cloud) (#23299)
* Adding Watson TTS (IBM Cloud)

* Code review changes
2019-05-18 23:05:59 +02:00
Joakim Sørensen
57bd4185d4 Fixes issue with multiple alerts (#23945)
* Fixes issue with multiple alerts

* Adds missing new line

* Remove whitespace
2019-05-18 22:59:33 +02:00
Martin Donlon
91ba35c68e Update russound_rio dependency to version 0.1.7 (#23973)
v0.1.7 fixes async import issues in python 3.7+
2019-05-18 22:56:34 +02:00
Cyro
a99e15343c Make Discord payload data key not required (#23964) 2019-05-18 13:14:53 -07:00
Daniel Høyer Iversen
4583638b92 upgrade broadlink library (#23966) 2019-05-18 13:14:11 -07:00
Matt Snyder
10a1b156e3 Doorbird Refactor (#23892)
* Remove schedule management. Allow custom HTTP events defined in the configuration

* Consolidate doorbird request handling.  Make token a per device configuration item.

* Lint fixes

* Do not register dummy listener

* Remove punctuation
2019-05-18 21:46:00 +02:00
Daniel Høyer Iversen
a8286535eb Upate xiaomi voltage parser, fix #23898 (#23962) 2019-05-18 11:01:30 +02:00
Adrian Schröter
05146badf1 show battery level also when vacuum has no map support (#23947) 2019-05-18 10:27:05 +02:00
Josef Schlehofer
c483e4479e Update requests to 2.22.0 (#23958) 2019-05-17 20:41:22 -05:00
Julien Brochet
4a70c725b4 Setup integration dependencies before loading it (#23957) 2019-05-17 19:17:26 -05:00
SiliconAvatar
33ed017851 Add unit of measurement to Tautulli sensor (#23873)
Adds unit of measurement ("Watching") to sensor, so it can be graphed properly.
This is the same unit of measurement as the Plex sensor.
2019-05-17 23:02:56 +02:00
Joakim Sørensen
fffc4dd3fd Bump pytraccar (#23939) 2019-05-17 09:56:04 -04:00
bouni
e072981295 Added support for sensor other than temperature and humidity (#23863)
* Added support for sensor other than temperature and humidity

* fixed lint errors

* fixed minor issues pointed out by @fabaff
2019-05-17 09:47:10 +02:00
Pascal Vizeli
5d983d0b61 Fix auto version update Hass.io (#23935) 2019-05-17 09:39:36 +02:00
Fredrik Erlandsson
727f667cbc Fix fan rates for Daikin (#23860) 2019-05-17 09:36:47 +02:00
Fredrik Erlandsson
1b4fc2ae8d Fix for non existing Daikin zones (#23792) 2019-05-17 09:25:07 +02:00
Jc2k
5b0d1415ad Have homekit_controller use device registry (#23874)
* Add device registry support

* HK doesn't use mac as a connection id
2019-05-17 08:41:20 +02:00
Paulus Schoutsen
7818c98c67 Merge pull request #23932 from home-assistant/rc
0.93.1
2019-05-17 08:03:45 +02:00
Paulus Schoutsen
e12222697c Bumped version to 0.93.1 2019-05-17 06:35:20 +02:00
karlkar
58f28f177d Fix problem with cameras that don't support time (#23924)
Some onvif cameras don't support Date management. In that case None is returned and script crashes when trying to obtain date
2019-05-17 06:35:09 +02:00
Joakim Plate
6030e419c5 Switch media player to SWITCH type (#23914)
MEDIA device type is being rejected by google now.
2019-05-17 06:33:20 +02:00
Paulus Schoutsen
8d2a784831 Update Honeywell warning (#23913) 2019-05-17 06:33:20 +02:00
Pascal Vizeli
5dc841ecae Fix Hassio-version for Azure Pipelines (#23895) 2019-05-17 06:33:19 +02:00
karlkar
edf34eea94 Fix problem with cameras that don't support time (#23924)
Some onvif cameras don't support Date management. In that case None is returned and script crashes when trying to obtain date
2019-05-17 06:29:52 +02:00
Paulus Schoutsen
a303f67d3b Merge branch 'master' into dev 2019-05-17 06:28:36 +02:00
Aaron Bach
1b5f526e09 Fix additional IQVIA data bug (#23931) 2019-05-16 18:30:09 -06:00
Jc2k
03a0a3572b Fix icons for homekit_controller sensors (#23921) 2019-05-16 22:30:48 +01:00
Aaron Bach
297d24c5b0 Fix bug when IQVIA API fails to return data (#23916)
* Fix bug when IQVIA API fails to return data

* Updated requirements

* Fixed tests

* Linting

* Removed impossible case

* Removed extraneous comment
2019-05-16 15:19:53 -06:00
Joakim Plate
c8cf06b8b7 Switch media player to SWITCH type (#23914)
MEDIA device type is being rejected by google now.
2019-05-16 22:34:40 +02:00
David McNett
49d6d7c656 Version bump insteonplm to 0.15.4 (#23918)
* Version bump insteonplm to 0.15.4

* Package-level version change
2019-05-16 22:34:06 +02:00
Robbie Trencheny
96fd874090 Add @Kane610 to zeroconf CODEOWNERS 2019-05-16 12:28:24 -07:00
Paulus Schoutsen
c9703872e2 Update Honeywell warning (#23913) 2019-05-16 13:21:38 -06:00
Robbie Trencheny
2f5d7d4522 [WIP] Simplify zeroconf (#23890)
* Simplify zeroconf

* Remove unused imports
2019-05-16 12:04:20 -07:00
Daniel Høyer Iversen
7716e8fb68 Netatmo, handle offline device (#23907)
* Netatmo, handle offline device

* style
2019-05-16 18:07:37 +02:00
Erik Montnemery
c2fc8a0d61 Load HA core config from storage (#23872)
* Load HA core config from storage

* Tweak

* Lint, review comments

* Fix test

* Add tests

* Lint

* Address comments
2019-05-16 16:27:53 +02:00
Markus Jankowski
9be384690a Enable Homematic IP cloud climate device with HeatingThermostat only (#23776)
* Enable climate device with HeatingThermostat only

* Fix after review
2019-05-16 15:10:30 +02:00
Jc2k
692eeb3687 Fix ecobee 3 homekit pairing (#23882) 2019-05-16 14:32:13 +02:00
Pascal Vizeli
213c91ae73 Update azure-pipelines.yml for Azure Pipelines 2019-05-16 09:28:08 +02:00
Pascal Vizeli
36b1a89f93 Fix Hassio-version for Azure Pipelines (#23895) 2019-05-16 08:57:43 +02:00
Paulus Schoutsen
584bfbaa76 Merge pull request #23864 from home-assistant/rc
0.93.0
2019-05-16 07:08:27 +02:00
Paulus Schoutsen
0f140751b2 Fix PS4 blocking startup (#23893) 2019-05-16 05:43:45 +02:00
Paulus Schoutsen
6b359c95da Fix PS4 blocking startup (#23893) 2019-05-16 05:43:19 +02:00
starkillerOG
1fec64a1b3 Update Pynetgear to v0.6.1 (#23886)
* Update Pynetgear to v0.6.1

* update pynetgear to v0.6.1
2019-05-15 23:53:02 +02:00
Paulus Schoutsen
70ed58a78d Restructure device tracker (#23862)
* Restructure device tracker

* Docstyle

* Fix typing

* Lint

* Lint

* Fix tests
2019-05-15 23:43:45 +02:00
Pascal Vizeli
6aa9844f8f Fix auto discovery if the monitor condition (#23880) 2019-05-15 16:28:35 +02:00
Pascal Vizeli
7a4238095d Fix auto discovery if the monitor condition (#23880) 2019-05-15 16:27:41 +02:00
Paulus Schoutsen
177594f02c Update sensor.py 2019-05-15 14:00:42 +02:00
Ville Skyttä
cf89f45697 Fix homekit test assert no messages (#23856) 2019-05-15 13:13:56 +02:00
Penny Wood
2dc78e6f0c Take code owner for sun.sun (#23877)
* Take code owner

* Post hassfest
2019-05-15 03:14:35 -05:00
Penny Wood
9da74dda43 Quiet the chatty sun.sun (#23832)
* Split up method to allow caching event

* Lower frequency of updates.

* Code review patches.

* Minor changes to test

* Skip end of period at fixed multiple of delta.
Improved documentation.
2019-05-15 15:02:29 +08:00
David Bonnes
18149dcb8c Add geniushub sensor and binary_sensor (#23811)
* Initial commit

* add lastComms and de-lint

* dummy commit

* dummy commit 2

* refactor to temp in favour of battery

* back to battery, and no temp

* use snake_case

* Bump client

* only v3 API exposes device attributes

* delint

* delint2

* Change GeniusSwitch to GensiusBinarySensor
2019-05-14 23:30:26 +02:00
Pascal Vizeli
3f841a36a5 Update azure-pipelines.yml for Azure Pipelines
Automated version updates
2019-05-14 22:59:12 +02:00
damarco
80ae02cc49 Fix zha timed off (#23849) 2019-05-14 13:41:27 +02:00
Paulus Schoutsen
421b2962c6 Bumped version to 0.93.0 2019-05-14 13:18:36 +02:00
Paulus Schoutsen
bde5a9ef01 Bumped version to 0.93.0b4 2019-05-14 13:12:30 +02:00
Robbie Trencheny
b79886ad85 Fix improper usage of body attribute on web.Response. Should be text since we arent sending bytes (#23857) 2019-05-14 13:12:24 +02:00
Paulus Schoutsen
94a2fd542e Fix aiohttp response serialize (#23858)
* Fix aiohttp response serialize

* Suport bytes

* Handle None
2019-05-14 11:59:27 +02:00
Paulus Schoutsen
6fa8556033 Use Cloudhooks for OwnTracks (#23847)
* Use Cloudhooks for OwnTracks

* Update config_flow.py

* Update config_flow.py
2019-05-14 11:59:11 +02:00
Pascal Vizeli
19cfa8cf22 Update azure-pipelines.yml for Azure Pipelines
Automated version updates
2019-05-14 10:18:01 +02:00
Paulus Schoutsen
a859997190 Allow deletion of automations and scripts (#23845) 2019-05-14 09:16:36 +02:00
Robbie Trencheny
6f9860b25e Fix improper usage of body attribute on web.Response. Should be text since we arent sending bytes (#23857) 2019-05-14 09:12:05 +02:00
Paulus Schoutsen
f083abbed1 Bumped version to 0.93.0b3 2019-05-14 07:19:37 +02:00
David F. Mulcahey
4dd8423b9b bump zha-quirks (#23855) 2019-05-14 07:19:31 +02:00
David F. Mulcahey
8ba2ab567e Fix ZHA battery when readings produce an unknown value (#23854)
* check for unknown readings

* only publish valid readings

* remove unused constant
2019-05-14 07:19:30 +02:00
David F. Mulcahey
3d821b9148 Correct ZHA illumination conversion (#23853)
* fix illumination values

* correct formula

* update illuminance calculation

* update test
2019-05-14 07:19:30 +02:00
Jason Hunter
04720175b9 fix onvif wsdl import - take 2 (#23807) 2019-05-14 07:19:29 +02:00
Alexei Chetroi
93ad7b2e45 Do not add coordinator to the ZHA entities. (#23803) 2019-05-14 07:19:28 +02:00
David F. Mulcahey
128ce589e1 Correct ZHA illumination conversion (#23853)
* fix illumination values

* correct formula

* update illuminance calculation

* update test
2019-05-14 07:16:41 +02:00
David F. Mulcahey
9b21774392 Fix ZHA battery when readings produce an unknown value (#23854)
* check for unknown readings

* only publish valid readings

* remove unused constant
2019-05-14 07:16:21 +02:00
David F. Mulcahey
eaf4a75402 bump zha-quirks (#23855) 2019-05-14 07:15:31 +02:00
Paulus Schoutsen
a1a6d4a631 Updated frontend to 20190514.0 2019-05-14 07:14:40 +02:00
Paulus Schoutsen
de1fd5a7fa WS: Improve service calling errors (#23840)
* WS: Improve service calling errors

* Docstyle

* Types

* Update text
2019-05-14 07:09:11 +02:00
Paulus Schoutsen
9b12dd66e4 Updated frontend to 20190514.0 2019-05-14 07:08:06 +02:00
Robert Svensson
0d96095646 Zeroconf - replace library (#23835)
* Use aiozeroconf in preparation for new zeroconf discovery

* Update requirements

* Remove sleep

* Make stop zeroconf a coroutine

* Remove unused import

* Fix aiozeroconf dependency in default_config tests
2019-05-14 05:58:13 +02:00
Paulus Schoutsen
45085dd97f Better handle large amounts of data being sent over WS (#23842)
* Better handle large amounts of data being sent over WS

* Lint
2019-05-14 05:57:47 +02:00
sander76
b2a1204bc5 Fix for battery device: new_device referenced before assignment. (#23793)
* Fix for battery device: new_device referenced before assignment.

* Fix buttons and switches mixup

* Update __init__.py

* Update binary_sensor.py

* Update __init__.py

* Update __init__.py

* Update binary_sensor.py

* Update __init__.py

* Update binary_sensor.py

* typo and indentation fixes

* low_bat and lowbat to uppercase.
2019-05-13 20:52:55 +02:00
damarco
990a9e80a2 Fix zha timed off (#23849) 2019-05-13 13:13:57 -04:00
Fredrik Erlandsson
0ffcc197d4 Daikin adaptions for AirBase units (#23734)
* updated list of supported fan_modes

* AirBase units does not support Holiday-mode

* AirBase units does not support outside temp

* pydaikin version bump

* don't modify constant
2019-05-13 15:38:33 +02:00
Baptiste Candellier
1a051f038d Add new SmartHab light and cover platform (#21225)
* Add SmartHab platform

* Remove url config entry, improve error handling

* Upgrade smarthab dependency

* Address comments

* Lint
2019-05-13 03:35:31 -07:00
Paulus Schoutsen
1e22c8daca Automatically generate config flow list (#23802)
* Add config flow to manifest.json

* Still load config flows via config flow platform

* Fix typo

* Lint

* Update config_flows.py"

* Catch import error when setting up entry

* Lint

* Fix tests

* Fix imports

* Lint

* Fix Unifi tests

* Fix translation test

* Add homekit_controller config flow
2019-05-13 01:16:55 -07:00
Jc2k
b8cbd39985 HomeKit Controller: Adopt config entries for pairing with homekit accessories (#23825)
* Fix user initiated pairing + show more user friendly name

* Add lock around async_refresh_entity_map

* Migrate homekit_controller to config entries.

* Improve docstring

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Add dummy async_setup_platform

* add_service -> async_add_service

* Add missing returns

* Enable coverage checks for homekit_controller
2019-05-12 23:56:05 -07:00
Paulus Schoutsen
3508622e3b Remove badges from README [skipci] (#23815) 2019-05-12 23:55:16 -07:00
Paulus Schoutsen
b8f6d824fd Catch import error when processing config (#23833) 2019-05-12 23:54:55 -07:00
akloeckner
e687848152 Make broadlink switch restore its state (#23829)
* Make broadlink switch restore its state

Method copied from pilight switch

* style
2019-05-12 19:28:33 +02:00
David Bonnes
2a9fd9ae26 Add incomfort climate and bump client (#23830)
* Initial commit

* bump client for bugfix

* bump client for bugfix 2

* de-lint
2019-05-12 13:40:10 +02:00
Paulus Schoutsen
3ec4070d8c Fix patching right import (#23816) 2019-05-11 19:29:29 +02:00
mvn23
6f8038992c Bump pyotgw to 0.4b4, fix Opentherm Gateway name in manifest.json (#23810) 2019-05-11 16:15:35 +02:00
Fabian Affolter
5c9a58f3e6 Upgrade youtube_dl to 2019.05.11 (#23808) 2019-05-11 16:15:09 +02:00
Stephen Benjamin
d34214ad32 Bump venstarcolortouch to v0.7 (#23806) 2019-05-11 10:33:18 +02:00
Andre Lengwenus
2b7021407c Add LCN climate platform (#22542)
* Add LCN climate component

* Updates of ha_state are done async

* Changes due to manifest.json
2019-05-11 10:24:02 +02:00
Jason Hunter
03cd4480df fix onvif wsdl import - take 2 (#23807) 2019-05-10 23:15:21 -07:00
Alexei Chetroi
910825580e Do not add coordinator to the ZHA entities. (#23803) 2019-05-10 18:57:08 -04:00
Paulus Schoutsen
6d40980de1 Bumped version to 0.93.0b2 2019-05-10 14:32:51 -07:00
Anders Melchiorsen
d4f79fc88a Synchronize Sonos service calls (#23791) 2019-05-10 14:32:43 -07:00
Paulus Schoutsen
2d724f5cc9 Updated frontend to 20190510.0 2019-05-10 14:23:09 -07:00
Paulus Schoutsen
c8d479e594 Updated frontend to 20190510.0 2019-05-10 14:22:38 -07:00
Anders Melchiorsen
34f6245e74 Synchronize Sonos service calls (#23791) 2019-05-10 22:37:03 +02:00
Paulus Schoutsen
e9ea5c2ccb Move tests to right folder (#23790)
* Move tests to right folder

* Fix test leaving files behind
2019-05-10 13:20:50 -07:00
David Bonnes
4347a0f6b7 Centralize geniushub updates (#23764)
* add hub/parent/manager

* add hub/parent/manager 2

* working now

* delint

* add back water heater

* make water_heater a child

* make water_heater a child - delint

* make water_heater a child - delint 2

* improve turn_on logic, and small tidy-up

* improve turn_on logic 2

* improve turn_on logic 3 - better docstring

* improve turn_on logic 3 - better docstring

* remove unnecessary DICT.get()s

* remove unnecessary DICT.get()s 2

* code tidy-up

* de-lint

* refactor for GeniusData

* refactor for GeniusData 2

* code tidy-up

* add missing should_poll = False
2019-05-10 18:34:28 +02:00
Paulus Schoutsen
5888e32360 Add support for an external step in config flow (#23782)
* Add support for an external step in config flow

* Types

* Lint
2019-05-10 14:33:49 +02:00
Andrey Kupreychik
4214a354a7 Bumped keenetic NDMS2 client version (#23786) 2019-05-10 11:43:43 +02:00
Pascal Vizeli
61ed604fda Bump version 0.93.0b1 2019-05-10 06:17:26 +00:00
Paulus Schoutsen
f17259c705 Updated frontend to 20190509.0 2019-05-10 06:16:54 +00:00
Jason Hunter
d5533cc10f Beta Fix: ONVIF (#23787)
* bump package to include wsdl

* update requirements all
2019-05-10 06:16:02 +00:00
dreed47
e6c5cc92d1 Fix for issue #23739. Added unique_id property so (#23769)
that entities will always get mapped to the same
property ZPID code.
2019-05-10 06:16:00 +00:00
cgtobi
0caa27094e Bump pyatmo to v1.11 (#23766) 2019-05-10 06:16:00 +00:00
Steven Looman
01578f78f1 Sort discovered entries by 'st' to ensure getting the same device each discovery (#23763) 2019-05-10 06:15:59 +00:00
Paulus Schoutsen
369afd7ddd Update sensor.py 2019-05-09 22:01:37 -07:00
dreed47
281445917b Fix for issue #23739. Added unique_id property so (#23769)
that entities will always get mapped to the same
property ZPID code.
2019-05-09 20:18:28 -07:00
Jason Hunter
df6846344d Beta Fix: ONVIF (#23787)
* bump package to include wsdl

* update requirements all
2019-05-09 20:17:55 -07:00
Steven Looman
05960fa29c Sort discovered entries by 'st' to ensure getting the same device each discovery (#23763) 2019-05-09 16:17:46 -07:00
Pawel
068749bcbe fix two times creating JWT headers. (#23777) 2019-05-09 16:13:13 -07:00
Paulus Schoutsen
f21f32778f Updated frontend to 20190509.0 2019-05-09 15:49:12 -07:00
sander76
8ef3c6d4d3 Add battery binary sensor to homematic (#23067)
* first proposal

* parameter rename

* retrigger CI

* remove separate binary sensor

* remove batter_sensor

* battery device distinction at binary sensor discovery
2019-05-09 10:38:51 -07:00
Joakim Plate
c7a78ed522 Add stepped volume to demo (#23759)
* Add stepped volume to demo

* Simplify somewhat to avoid extra check
2019-05-09 10:18:22 -07:00
Aaron Bach
45adb5c9c7 Add config entry for IQVIA (#23765)
* Add config entry for IQVIA

* Updated tests and requirements

* Removed unnecessary dependency

* Fixed tests

* Reverted unintended change
2019-05-09 09:11:51 -07:00
Ties de Kock
4004867eda Split up yaml loaders into multiple files (#23774)
* Start moving parts of yaml utils to own module

Move parts of yaml loader out of the single large file and start
to create the structure of the yaml loaders in Ansible [0].

[0]: https://github.com/ansible/ansible/tree/devel/lib/ansible/parsing/yaml

* Finish yaml migration, update tests and mocks

  * Move code around to finish the migration
  * Update the mocks so that `open` is patched in
    `homeassistant.util.yaml.loader` instead of
    `homeassistant.util.yaml`.
  * Updated mypy ignores
  * Updated external API of `homeasistant.util.yaml`, see below:

Checked what part of the api of `homeassistant.util.yaml` was actually
called from outside the tests and added an `__ALL__` that contains only
these elements.

Updated the tests so that references to internal parts of the API (e.g.
the yaml module imported into `homeassistant.util.yaml.loader`) are
referenced directly from `homeassistant.util.yaml.loader`.

In `tests/test_yaml.py` the import `yaml` refers to
`homeassistant.util.yaml` and `yaml_loader` refers to `~.loader`.

Future work that remains for the next iteration is to create a custom
SafeConstructor and refers to that instead of monkey patching `yaml` with
custom loaders.

* Update mocks in yaml dumper, check_config
2019-05-09 09:07:56 -07:00
Markus Jankowski
118d3bc11c Add Presence Detector Indoor to Homematic IP (#23755)
* Add presence detector indoor

use device classes constants

* Add illuminance

* isort
2019-05-09 09:57:02 +02:00
cgtobi
0e9d71f232 Bump pyatmo to v1.11 (#23766) 2019-05-08 21:08:07 -07:00
Paulus Schoutsen
b552fbe312 Version bump to 0.94.0.dev0 2019-05-08 20:23:31 -07:00
Paulus Schoutsen
07b7d7b074 Bumped version to 0.93.0b0 2019-05-08 20:22:36 -07:00
Paulus Schoutsen
fb7343ecd2 Merge remote-tracking branch 'origin/master' into dev 2019-05-08 20:22:08 -07:00
Paulus Schoutsen
e51925fc58 Update translations 2019-05-08 20:20:58 -07:00
Paulus Schoutsen
d507adf13d Updated frontend to 20190508.0 2019-05-08 20:20:26 -07:00
Pascal Vizeli
c5230f7585 Update azure-pipelines.yml for Azure Pipelines 2019-05-08 23:47:01 +02:00
Paulus Schoutsen
cc13713abd No longer rely on requests (#23685)
* No longer rely on requests

* Lint

* Missed a few parts

* Fix types

* Fix more types

* Update __main__.py

* Fix tests

* Lint

* Fix script
2019-05-08 11:15:04 -07:00
Josef Schlehofer
f019e2a204 Upgrade zeroconf to 0.22.0 (#23524) 2019-05-08 08:40:00 -07:00
Jerry Chong
07126266dd Update Sesame component to use Candy House's library using the V3 API (#23621)
* Update Sesame component to use Candy House's library using the V3 API

* Updated requirements_all.txt

* Fix pylint warning

* Revert back to ATTR_DEVICE_ID
2019-05-08 08:34:00 -07:00
Martin Hjelmare
c26af22edd Refactor child validation (#23482)
* Try to make the process more readable and paritioned.
* Validate child values using set message.
* Only validate using relevant schemas.
* Extract node validation.
* Rework const types and schemas.
* Rework child validator.
* Enhance warning logging message.
2019-05-08 08:26:40 -07:00
Ville Skyttä
c384adeef4 Upgrade defusedxml to 0.6.0 (#23651) 2019-05-08 08:04:36 -07:00
Penny Wood
7f0953766b Prompt for pin only on open / unlock (#23751)
* Prompt for pin only on open / unlock

* Fixed test cases
2019-05-08 07:55:30 -07:00
Pascal Vizeli
ce1974b014 Update azure-pipelines.yml for Azure Pipelines 2019-05-08 16:02:19 +02:00
carstenschroeder
8822f0140d New cover platform for ADS integration (#23377)
* new cover platform

* improve logging II

* remove dependencies

* fix comment

* fix review findings
2019-05-08 14:08:26 +02:00
Fabian Affolter
45c041884a Upgrade Mastodon.py to 1.4.0 (#23753) 2019-05-08 11:20:22 +02:00
Fabian Affolter
1ecb3de643 Upgrade numpy to 1.16.3 (#23673) 2019-05-08 09:17:41 +02:00
cgtobi
f0f6787bf9 Merge netatmo_public sensor into the netatmo integration (#23531)
* Merge netatmo public into netatmo integration

* Remove netatmo_public platform

* Remove dev log messages

* Improve error handling

* Check config for unsupported conditions

* Fix linter

* Reduce nested blocks
2019-05-08 08:26:52 +02:00
Paulus Schoutsen
3e788aa1d6 Updated frontend to 20190507.0 2019-05-07 22:55:59 -07:00
Paulus Schoutsen
f4016b4aad Add integration step to onboarding (#23732)
* Return an extra oauth2 auth code during onboarding

* Areas in const

* Add integration step

* Lint

* Fix tests

* Fix test

* Verify integration added to done

* Verify step is marked as done
2019-05-07 22:51:24 -07:00
Paulus Schoutsen
07ee3b2eb9 Add update events to registries (#23746)
* Add update events to registries

* Add to websocket
2019-05-07 20:04:57 -07:00
Steven Looman
6e7a7ba4a0 Fix upnp logger name (#23724)
* Fix upnp logger name

* Fix more loggers
2019-05-07 15:52:48 -07:00
David Bonnes
7181d639fd Add Intergas InComfort Lan2RF gateway (#23736)
* fixed __init__.py

* add sensors

* switch to parent-child architecture

* make binary_sensor the parent

* revert parent - to water_heater

* first working version

* working, delinted (except TODO)

* update to latest client library

* remove debug code

* delint

* tweak device_state_attributes

* tweak device_state_attrbutes

* minor tweaks

* bump client library for bugfix

* improve state attributes for pumping

* update .coverage

* bugfix - binary sensors not updating

* rename to incomfort from intouch

* fix coveragerc regression

* bump client (bugfix for /protected URL)

* bump client (bugfix for /protected URL) 2

* bump client

* remove debug code

* ready for PR

* fix regression

* use xx._boiler instead of xx._objref

* improve current_temperature and delint

* use current_operation instead of state

* refactor vol.Schema

* remove unneeded instance attribute

* remove unneeded instance attribute 2

* refactor device_state_attributes

* change 'boiler' to 'heater'

* change 'boiler' to 'heater' 2

* correct a typo

* bugfix: add missing comma

* small tidy-up
2019-05-07 23:53:55 +02:00
Paulus Schoutsen
0f174250cc Update PR template (#23520)
* Update PR template

* Update config, PR template
2019-05-07 14:18:40 -07:00
Maciej Bieniek
16a27c3f2d Add abbreviation for position_topic (#23740) 2019-05-07 22:20:55 +02:00
Fabian Affolter
b253c7499d Upgrade aiodns to 2.0.0 (#23743) 2019-05-07 15:32:04 -04:00
Markus Jankowski
264e70922b Fix effects on HUE integration for Osram bulbs (#22789)
* Fix hue effect for others

* New suggestion

* switched implementation to remove colorloop for osram bulbs

* Check ATTR_EFFECT in kwargs

* Fix  tests
2019-05-07 09:53:14 -07:00
Richard Mitchell
482cb0146a Fix Hue sensor integration with multiple bridges. (#23713) 2019-05-07 09:45:04 -07:00
Andrew Sayre
02d8731a61 Add HEOS sign-in/out services (#23729)
* Add HEOS sign-in/out services

* Fix typo in comment
2019-05-07 09:39:42 -07:00
Erik Montnemery
102beaa044 Add debug prints to sun (#23598)
* Add debug prints to sun

* Review comment
2019-05-07 09:37:08 -07:00
David Bonnes
6611d585e6 Add water_heater to geniushub, bump client library (#23384)
* add water_heater

* add geniushub/water_heater.py

* de-lint

* de-lint 2

* remove temperature from device state attribs

* update to latest client library

* add me as CODEOWNER

* bump client

* bump client

* delint/refactor

* Update homeassistant/components/geniushub/water_heater.py

Co-Authored-By: zxdavb <david@bonnes.me>
2019-05-07 17:37:47 +02:00
unixko
f386088def add abbreviation for current_temperature_template (#23733) 2019-05-07 08:27:35 +02:00
rolfberkenbosch
c07c557298 Added new binary sensor meteoalarm to get weather alerts in Europe (#23663)
* Added new component meteoalarm

* Update sensor.py

* Update manifest.json

* Update manifest.json

* Update manifest.json

* Added file CODEOWNERS

* Modified some code, thanks @amelchio

* removed Throttle because is not being used anymore

* Update _attributes ad _state

* some cleanup

* Update sensor.py

Change sensor to binarysensor

* Rename sensor.py to binary_sensor.py

rename the file

* Update binary_sensor.py

Removed BinarySensorDevice from class

* Update binary_sensor.py

Made a mistake with BinarySensorDevice

* Update binary_sensor.py

clean up white spaces

* Update binary_sensor.py

Fix BinarySensorDevice

* Update binary_sensor.py

cleanup the import libs

* modified __init__

* fix

* final fix, thanks @amelchio

* forgot to change the sensor.py

* correct some typo in text

* fix typos

* fix another typo

* fix typo
2019-05-07 08:19:29 +02:00
Pawel
1f551e5f6f Add TTL support and custom headers support. (#22988)
* Add TTL custom support and custom headers support.

* fix pywebpush version

* removed whitespaces surrounding docstrings.

* fixes for tests

* priority option to data

* checking of ATTR_ENDPOINT

* change checking of target to vol.Schema

* more tests
2019-05-06 16:37:05 -07:00
Fabian Affolter
b60c815cde Share snmp constants across all platforms (#23678)
* Share constants across all platforms

* Update .coveragerc
2019-05-06 23:31:03 +02:00
Andrew Sayre
074142400a Fix SmartThings Samsung Air Conditioner Support (#23706)
* Bump pysmartthings to 0.6.8

* Fix AC climate device

* Fix stale comment
2019-05-06 10:21:16 -07:00
Daniel Høyer Iversen
d8a219fe0e Upgrade switchbot , fixes #23702 (#23716) 2019-05-06 10:18:50 -07:00
William Scanlon
a0230482bd Use the URL provided by the Wink API for subscriptions. (#23710)
* Use the URL provided by the Wink API for subscriptions.

* Changed python-wink version
2019-05-06 10:18:17 -07:00
Ville Skyttä
b9a72034f9 huawei_lte: handle icons for None sensor values gracefully (#23649) 2019-05-06 10:15:28 -07:00
Andrew Sayre
bf649e373c Update IDs after firmware upgrade in HEOS (#23641)
* Initial work

* Update tests
2019-05-06 17:53:11 +02:00
David F. Mulcahey
73aadbe8bc bump zha-quirks (#23714) 2019-05-06 08:35:11 -04:00
Fabian Affolter
e2afeca4fd Upgrade sendgrid to 6.0.5 (#23711) 2019-05-06 07:13:16 -05:00
Fredrik Erlandsson
0dfa5f9ffd Use local constant in Daikin for STATE_OFF (#23712) 2019-05-06 13:43:35 +02:00
Fabian Affolter
b331b081f0 Catch thethingsnetwork TypeError (#23667)
* Catch TypeError (fixes #23097)

* Re-add return values

* Update homeassistant/components/thethingsnetwork/sensor.py

Co-Authored-By: fabaff <mail@fabian-affolter.ch>
2019-05-06 09:47:46 +02:00
Andrew Sayre
cf03e42773 Bump pyheos to 0.5.2 (#23708) 2019-05-06 07:07:41 +02:00
droopanu
f87209605b Add a TCP timeout of 5 seconds to ffmpeg (#23617)
Add a TCP timeout of 5 seconds to ffmpeg to fix stream getting stuck when network connectivity is lost
https://github.com/home-assistant/home-assistant/issues/22741
2019-05-05 20:59:56 -04:00
ktnrg45
3e59e7f347 Add media_type_app to media_player (#23666)
* Add media_type_app

* Add MEDIA_TYPE_APP

* Bump 0.7.3

* Bump 0.7.3

* Bump 0.7.3

* typo
2019-05-05 18:53:08 -05:00
David F. Mulcahey
3dd1d3c418 Add additional single input cluster entries - ZHA (#23697)
* more profiles

* remove from binary sensor profile

* remove sensor profile mapping
2019-05-05 19:10:19 -04:00
Alexei Chetroi
8328ea6bd7 Bump ZHA modules versions. (#23705)
* Bump ZHA modules versions.

Bump bellows-homeassistant version.
Bump zigpy-homeassistant version.
Bump zigpy-xbee-homeassistant version.

* Update requirements_*.txt
2019-05-05 17:15:34 -04:00
Fredrik Erlandsson
9c1bbd1d9d Add support for SET_AWAY_MODE and TURN_ON/OFF on Daikin Climate (#23585)
* add support for on/off on daikin climate

* add support for away mode on daikin climate
2019-05-05 15:17:01 -05:00
Martin Hjelmare
8500244f8c Move owntracks device tracker test under owntracks (#23701) 2019-05-05 21:39:51 +02:00
Anders Melchiorsen
2efc1de349 Move Sonos services to sonos domain (#23670) 2019-05-05 14:25:57 -05:00
Martin Hjelmare
4796d674e6 Clean up device tracker tests (#23695)
* Clean up device tracker tests

* Fix async load config in device tracker tests.
* Clean up lint in device tracker tests.
* Sort device tracker tests imports.
* Patch config saving in device tracker tests.
* Rename fixture.
* Rename some tests that had long cryptic names.

* Replace calls  to device_tracker.async_setup
2019-05-05 14:14:46 -05:00
Martin Hjelmare
4fe0cd76f8 Clean up mqtt device tracker tests (#23700)
* Move mqtt device tracker test under mqtt dir

* Patch config file load and save

* Clean up

* Sort imports

* Put expected value last in assertions
2019-05-05 11:50:38 -07:00
Julius Mittenzwei
c0f9ccfdbb Update requirements for pyvlx. (#23694) 2019-05-05 19:19:35 +02:00
Martin Hjelmare
b9fda078a4 Clean and fix google calendar tests (#23608)
* Clean and fix google calendar tests

* Extract test calendar constant for google test
* Rewrite google calendar tests
* Clean and fix google calendar tests
* Clean and fix google component tests
* Add google conftest
* Skip flaky google calendar test

* Fix google calendar bug

* Fix yield fixture

* Set fixture names to avoid lint warning

* Fix yield fixture
2019-05-05 18:38:55 +02:00
Austin Drummond
e24d56aa5b Add HomeKit Television functionality (#22968) 2019-05-05 17:51:47 +02:00
UgaitzEtxebarria
8da600adff Add Bizkaibus, Biscays (Spain) bus service component (#22934)
* Updated to the current version of dev

* Added the component to .coveragerc

* Added __init__.py and manifest.json

* Changed the manifest to comply the json format

* Changes in for complete the PEP8 Code

* Fixed the api call to use PyPI package

* Fixed API correrct call

* Fixes for complete the requirements

* Added dependencies in manifest.json

* Changed the __init__.py to complete PEP8

* Simplified the __init__.py

* Runned codeowner script

* executed gen_requirements_all.py

* Direct call for dicts and unit changed to minutes

* Fixed the optional dict call, sorry, my bad, I did not that

* Deleted unused vars

* Changed optional parameter to required

* Remove blank first line
2019-05-05 11:00:15 +02:00
Fabian Affolter
9712bbc91c Upgrade spotcrime to 1.0.4 (fixes #13189) (#23679) 2019-05-05 07:29:04 +02:00
Fabian Affolter
fca0891320 Upgrade pysnmp to 4.4.9 (#23677) 2019-05-05 07:26:13 +02:00
Aaron Bach
1d2c5cb53c Remove extraneous update call in SimpliSafe (#23680) 2019-05-04 17:32:33 -06:00
Fabian Affolter
c309bd9ff0 Upgrade sqlalchemy to 1.3.3 (#23674) 2019-05-05 01:06:47 +02:00
Fabian Affolter
2f416b15c5 Upgrade tapsaff to 0.2.1 (#23676) 2019-05-05 00:07:55 +02:00
Fabian Affolter
85cd4ad022 Upgrade slacker to 0.13.0 (#23672) 2019-05-05 00:06:39 +02:00
Fabian Affolter
c8690865ec Upgrade shodan to 1.13.0 (#23675) 2019-05-05 00:05:01 +02:00
Fabian Affolter
8d8d2b6de9 Upgrade psutil to 5.6.2 (#23671) 2019-05-05 00:04:04 +02:00
SNoof85
97b5a38cb1 Bump pyteleloisirs version (#23661)
* Bump pyteleloisirs version

* requirements update
2019-05-04 12:53:06 +02:00
Geert van Horrik
8fc30569a9 Fix bad request for some IP ONVIF camera (#22972)
* Onvif camera improvements using zeep

* Fix static code checks

* Make obtain_input_uri async

* Convert several methods to async

* Fix static checks

* Fix static checks

* Fix requirements_all.txt

* Lint improvements

* Async services

* Use onvif-zeep-async and check if PTZ service is available before creating it

* Remove some hacks that are now defined in onvif-zeep-async

* Don't log input, it might contain sensitive information

* Static code analysis fixes

* Run requirements stuff

* Fix

* Remove suds requirement

* Onvif camera improvements using zeep

* Fix static code checks

* Make obtain_input_uri async

* Convert several methods to async

* Fix static checks

* Fix static checks

* Fix requirements_all.txt

* Lint improvements

* Async services

* Use onvif-zeep-async and check if PTZ service is available before creating it

* Remove some hacks that are now defined in onvif-zeep-async

* Don't log input, it might contain sensitive information

* Static code analysis fixes

* Run requirements stuff

* Fix

* Remove suds requirement

* Use dt_util.utcnow

* Platform setup should not have a return value

* Remove explicit dependency to zeep[async]

* Bump onvif-zeep-async to 0.1.2

* Update requirements_all.txt

* Add exception handling

* Fix static checks

* Don't catch generic exceptions

* Update camera.py
2019-05-03 10:01:12 -07:00
ThaStealth
0702407fac Added option to select photoblack cartridge (#23433)
* Added option to select photoblack cartridge

* Update sensor.py

* Name change
2019-05-03 18:57:41 +02:00
Robert Svensson
6e34015420 deCONZ - Retry on BridgeBusy errors (#23436) 2019-05-03 17:55:42 +02:00
Philippe Delodder
df9a9a1fec Add "soc-thermal 1" as CPU Temp label to Glances (#23635) 2019-05-03 15:43:51 +02:00
Daniel Høyer Iversen
9761c504eb update switchbot library (#23643) 2019-05-03 08:46:19 -04:00
Andrew Sayre
b30afde8ab Extend play_media support (#23580) 2019-05-02 19:54:36 -05:00
David Bonnes
6130831a43 Refactor evohome to prepare for water_heater (#23489)
* refactor - add const.py, change order of propertys, methods

* import client at top of file

* remove debug line

* de-lint

* delint

* add me as CODEOWNER

* remove lint hint

* delint
2019-05-03 01:43:19 +02:00
Penny Wood
3338f5c9b4 Further patch to fix of #22890 (#23627) 2019-05-02 14:05:16 -07:00
Paulus Schoutsen
592e99947d Convert frontend to do client-side modern JS detection (#23618)
* Convert frontend to do client-side async pick

* Further cleanup

* Updated frontend to 20190502.0

* Fix template caching

* Remove es5 test

* Lint

* Update description
2019-05-02 13:59:24 -07:00
Max
7331eb1f71 Allow removing Telegram reply keyboard (#23467)
*  Allow removing telegram reply keyboard by setting `keyboard` to an empty list

* Telegram keyboard: [] clearing in services.yaml
2019-05-02 15:14:40 -04:00
Ville Skyttä
f434e24252 Upgrade mypy (#23586)
* Upgrade mypy to 0.701

* Enable strict equality checks

* Strict equality error fixes

* StateMachine.is_state docstring fix
2019-05-02 21:18:20 +03:00
Ville Skyttä
b79d71065c Upgrade pytest to 4.4.1 (#23584) 2019-05-02 21:17:36 +03:00
Ville Skyttä
0a75a2c080 Clean up redundant same-package ..package imports (#23587) 2019-05-02 20:11:37 +03:00
Pascal Vizeli
41357965de Update azure-pipelines.yml for Azure Pipelines 2019-05-02 19:00:39 +02:00
Jc2k
1e6babe796 Loosen discovery config validation to avoid breaking changes (#23625)
* Allow optional service handlers to be promoted to config flow without a breaking change

* Updated wording

* Remove period
2019-05-02 16:57:42 +02:00
Daniel Høyer Iversen
04b680d9d0 Updgrade Tibber library (#23630)
* update tibber library

* update tibber library
2019-05-02 16:03:51 +02:00
Fabian Affolter
5267635d2c Polling is default (#23622) 2019-05-02 16:00:32 +02:00
Fabian Affolter
a6b898d702 Order imports (#23623) 2019-05-02 08:36:41 -04:00
Fabian Affolter
5c413eb497 Update docstrings (#23624) 2019-05-02 08:35:22 -04:00
Magnus Brange
21575938ef Prevent turning on tellduslive lights with 0 brightness (#23135)
* Prevent turning on tellduslive lights with 0 brightness

It was possible for the light compontent to get in a state where the last_brightness was set to zero, and when turning on (by calling turn_on) it would call the TellStick with 0 dim level, ergo not turning on the light.

With this, it will fall back on a 75% dim level if the level is set to zero.

* Wrap long log line over two lines

And using a more proper way of formatting the message

* Fallback to 100% instead of 75%
2019-05-02 12:53:32 +02:00
Pascal Vizeli
a7ef1eabb0 Update azure-pipelines.yml for Azure Pipelines 2019-05-02 10:29:16 +02:00
Pascal Vizeli
6124a6f7e5 Update azure-pipelines.yml for Azure Pipelines 2019-05-02 10:04:44 +02:00
Pascal Vizeli
d4ae73ce38 Merge pull request #23620 from home-assistant/rc
0.92.2
2019-05-02 09:49:23 +02:00
Brett T. Warden
2fbf29cda6 Update pyvesync_v2 version to 0.9.7 (#23603) 2019-05-02 09:48:22 +02:00
Erik Montnemery
3c5abcc71a Improve sun automation tests (#23588)
* Improve sun automation tests

* Lint

* Restore timezone after test
2019-05-02 09:46:32 +02:00
Martin Hjelmare
447440adc3 Clean caldav calendar tests (#23609) 2019-05-02 09:46:12 +02:00
Aaron Bach
daa1d103d4 Add support for flow sensor metrics in RainMachine (#23221)
* Initial commit

* In the clear
2019-05-02 09:45:51 +02:00
Paulus Schoutsen
58cde6b497 Bumped version to 0.92.2 2019-05-01 22:43:25 -07:00
Andrew Sayre
741d0fd09b Bump pyheos (#23616) 2019-05-01 22:43:17 -07:00
Robbie Trencheny
bc9548fdaf Fix unexpected error thrown if instance_domain is not set (#23615) 2019-05-01 22:43:17 -07:00
ehendrix23
35e9505ad5 Fix authentication issue (#23600)
Update to pymy1 version 1.2.1 to fix authentication issue
2019-05-01 22:43:16 -07:00
Klaas Schoute
38aa7d2c95 Fix problem with using Traccar event (#23543) 2019-05-01 22:43:15 -07:00
Pascal Vizeli
55a7ea6cc5 Fix media_player alexa power control bug (#23537) 2019-05-01 22:43:14 -07:00
Paulus Schoutsen
04bca7be6b Only include agent user ID in SYNC responses (#23497) 2019-05-01 22:43:14 -07:00
Paulus Schoutsen
8180797d2f Fix Hue sensors returning None value (#23478) 2019-05-01 22:43:13 -07:00
Erik Montnemery
0fe573ecc0 Fix cleanup of dynamic group (#23475) 2019-05-01 22:43:12 -07:00
Erik Montnemery
185595c113 Bump pychromecast (#23463) 2019-05-01 22:43:12 -07:00
cgtobi
ffdf48b15a Fix netatmo_public sensor to use netatmo authentication (#23455) 2019-05-01 22:43:11 -07:00
David Bonnes
fa4264be3f update geniushub client library to fix issue #23444 (#23450) 2019-05-01 22:43:10 -07:00
Steven Looman
c7a34d0222 Don't create connections between sensors. Fixes #22787 (#23202) 2019-05-01 22:43:09 -07:00
Robbie Trencheny
e054d68565 Further improve IndieAuth redirect_uri lookup failure logs (#23183) 2019-05-01 22:43:08 -07:00
Andrew Sayre
f3925b7ede Bump pyheos (#23616) 2019-05-01 22:39:59 -07:00
Robbie Trencheny
d1e44e35df Fix unexpected error thrown if instance_domain is not set (#23615) 2019-05-01 22:35:12 -07:00
Jc2k
0fe21f2015 Support STATE_AUTO in homekit_controller climate (#23583) 2019-05-01 22:44:54 -05:00
Aaron Bach
75abfd49ef Fixed unhandled exception in OpenUV data update (#23611) 2019-05-01 21:15:10 -06:00
4lloyd
f0c582ebbd Added message to data_template at notify REST (#23108)
* Added message to data_template at notify rest

* Added missing newlines
2019-05-01 17:04:05 -06:00
Jc2k
7ff77936ad Add and improve Homekit controller pairing messages and errors (#23532)
* Be clear about pairing code format

* Handle more homekit errors while pairing

* Update en translation

* Fix log message feedback
2019-05-01 17:02:29 -06:00
teliov
44d0d0624b updated manifest.json with correct version of hangup (#23596) 2019-05-01 17:02:03 -06:00
Paul Madden
a8c7804db2 Update bomradarloop to v0.1.3 (#23599) 2019-05-01 17:00:40 -06:00
Cyro
beb678e259 Move I/O to executor thread pool (#23589)
* Move I/O to executor thread pool

* Check if image is in whitelist_external_dir

* Move import to top of file

* Fix bad indentation
2019-05-01 17:00:17 -06:00
ehendrix23
d9d5c91adc Fix authentication issue (#23600)
Update to pymy1 version 1.2.1 to fix authentication issue
2019-05-01 16:05:35 -06:00
Daniel Høyer Iversen
19aee50bbc Ambiclimate (#22827)
* Ambiclimate

* Ambiclimate

* style

* Add config flow to ambicliamte

* Add config flow to ambicliamte

* update requirements_all.txt

* ambiclimate

* tests

* typo

* ambiclimate

* coverage

* add manifest.json

* services

* codeowner

* req

* ambicliamte

* style

* ambicliamte

* add to requirements all tests

* add to requirements all tests

* .coveragerc

* Add tests

* add doc

* style

* fix test

* update tests

* update tests

* update tests

* update tests

* update tests

* tests

* tests

* fix comment
2019-05-01 22:05:40 +02:00
Pascal Vizeli
bb6300efe3 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 21:49:08 +02:00
Markus Jankowski
dd53434742 Redesign AlarmControlPanel for Homematic IP (#23565)
* redesign AlarmControlPanel

* Fix lint

* Fixes after review
2019-05-01 21:35:57 +02:00
cdce8p
db2904624a Fix low_battery_threshold issue HomeKit (#23593) 2019-05-01 16:48:56 +02:00
Pascal Vizeli
d3cbd5b5e4 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 16:46:15 +02:00
Ville Skyttä
f9205d0ccc Simplify Travis cache config (#23592) 2019-05-01 16:08:57 +02:00
Pascal Vizeli
127cc5f942 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:49:12 +02:00
Pascal Vizeli
ab60235811 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:47:38 +02:00
Pascal Vizeli
7faa061b29 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:42:52 +02:00
Pascal Vizeli
c7d49a0c6a Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:38:51 +02:00
Pascal Vizeli
ac731a817a Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:28:35 +02:00
Pascal Vizeli
f0a34ddf46 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:23:54 +02:00
Pascal Vizeli
918ce74b26 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:14:26 +02:00
Pascal Vizeli
e8f496c016 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 14:09:34 +02:00
Pascal Vizeli
9b57075c3b Update azure-pipelines.yml for Azure Pipelines 2019-05-01 13:58:43 +02:00
William Scanlon
09cd302b46 Bumpped the pyeconet version (#23578) 2019-05-01 12:28:37 +02:00
Pascal Vizeli
bf25b74bf1 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 11:04:11 +02:00
Pascal Vizeli
3269da16f6 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 11:01:51 +02:00
Pascal Vizeli
0a428868fe Update azure-pipelines.yml for Azure Pipelines 2019-05-01 10:14:51 +02:00
Pascal Vizeli
8cfc316e06 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 10:06:08 +02:00
Pascal Vizeli
31e3c563b5 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 09:57:21 +02:00
Pascal Vizeli
f28ca34307 Update azure-pipelines.yml for Azure Pipelines 2019-05-01 09:56:09 +02:00
Pascal Vizeli
09296b4fd4 Set up CI with Azure Pipelines
[skip ci]
2019-05-01 09:54:48 +02:00
Fabian Affolter
0b9302ac3d Upgrade youtube_dl to 2019.04.30 (#23579) 2019-05-01 08:31:24 +02:00
Penny Wood
5b9d01139d render_with_collect method for template (#23283)
* Make entity_filter be a modifiable builder

* Add render_with_collect method

* Use sync render_with_collect and non-class based test case

* Refactor: Template renders to RenderInfo

* Freeze with exception too

* Finish merging test changes

* Removed unused sync interface

* Final bits of the diff
2019-05-01 10:54:25 +08:00
etheralm
581b16e9fa Fix failing state update tests (#23575) 2019-04-30 16:47:40 -07:00
Jc2k
1c4367e5a9 Fix min/max temp and humidity for homekit_controller climate (#23421)
* Fix min/max temp and humidity for homekit_controller climate.

* Fix typo
2019-05-01 00:08:30 +02:00
Penny Wood
b0843f4a38 Ptvsd debugger component. (#23336)
* ptvsd debugger component.

* Add test case

* ptvsd as test dependency

* Fix for 3.5

* Fixed bootstrap test

* Use dict direct lookup.

* Don't need to load dependencies.

* Get the test working.

* 3.5 fix

* Set mock return value

* Put tests back, but skip them

* Change log level
2019-05-01 00:07:34 +02:00
Jonas Pedersen
24060e0fb5 Add bypass and automatic bypass switch for Danfor Air. (#23572)
Add bypass and automatic bypass switch for Danfoss Air
2019-04-30 23:07:49 +02:00
Martin Hjelmare
5ded0dd3fa Update mysensors sensor icons (#23491)
* Add some icons.
* Sort sensor types according to mysensors serial api numbering.
2019-04-30 23:06:44 +02:00
Mike Miller
09012e7baa Always pad mac addresses from nmap tracker with leading zeros (#23492) 2019-04-30 22:43:21 +02:00
Cyro
75a2c057f2 Upgrade discord.py to v1.0.1 (#23523) 2019-04-30 22:12:39 +02:00
Sylvia van Os
603e2cd961 Essent sensor (#23513)
* Initial commit for Essent

* Cleanup Essent component

* Update CODEOWNERS

* Move stuff to PyEssent

* Update requirements_all

* Fix PyEssent

* Move meter list to PyEssent library

* Update requirements_all

* Only check for updates once an hour

* Use PyEssent 0.10

* Fixing up Essent component

* Fix crash

* Don't add unused meter/tariff combos

* Fix lint

* Get tariffs per meter

* Don't hammer Essent API

* Fix linting errors

* Fix old description

* Fix old call

* Cleanup Essent component
2019-04-30 21:02:16 +02:00
Andrew Sayre
cfaaae661a Add core APIs to migrate device identifiers and entity unique_id (#23481)
* Add device identifiers migration

* Add entity unique_id migration

* Update per arch issue

* Move to existing update methods
2019-04-30 10:04:37 -07:00
David F. Mulcahey
41f0066e76 bump zha-quirks version (#23568) 2019-04-30 12:57:06 -04:00
Erik Montnemery
407e0c58f9 Migrate tests to pytest (#23544)
* Migrate tests to pytest

* Fixup

* Use loop fixture in test_check_config

* Lint
2019-04-30 09:20:38 -07:00
David F. Mulcahey
d71424f285 Clean up ZHA discovery logic (#23563)
* use domain constants from HA

* cleanup endpoint processing in discovery

* Whitespace.
2019-04-30 10:40:52 -04:00
Anders Melchiorsen
6a6a999833 Upgrade pysonos to 0.0.12 (#23560) 2019-04-30 08:45:56 -04:00
Jc2k
7612703092 Bump homekit_python to 0.14.0 (#23562) 2019-04-30 08:44:48 -04:00
Klaas Schoute
5d5f073cff Fix problem with using Traccar event (#23543) 2019-04-30 08:02:45 +02:00
etheralm
1d70005b01 Add sensor support for dyson 2018 models (#22578)
fix check for already created entities

remove hepa and carbon filter

add AQI attribute

initial commit

fix check for already created entities

remove hepa and carbon filter

add AQI attribute

add air quality component tests

fix method call tests

fix line lengths

fix pylint issues

fix docstrings

revert fan related changes

remove whitespace change

fix fan update state test

add for loop for platform initialization

add requested changes to aiq platform

change string concatenation to new style string formatting

update air quality tests

update air quality tests

refactor sensor component changes

fix pylint issues

fix debug string in the air quality component

replace failing tests for older devices

fix line length fan tests

remove dependencies const and move imports

move back imports to methods

remove whitespace from blank line
2019-04-30 02:24:05 +02:00
Austin Drummond
b4e2a0ef84 Add HomeKit low battery threshold config (#23363) 2019-04-30 02:02:53 +02:00
David F. Mulcahey
2aee31ec6a Don't use zigpy profiles for ZHA entities (#22844)
* don't use zigpy profiles
* use sets as they're the correct structure to use
2019-04-29 19:31:27 -04:00
Erik Montnemery
8d775caaac Always print invalid configuration data (#21972)
* Always print invalide configuration data

* Print offending data as yaml

* Revert "Print offending data as yaml"

This reverts commit 01721a21a9ff918ed2c8595151ebfe55eb2f7d36.

* Do not print sensitive data

* Print MQTT topic

* Add line break

* Review comments

* review comments
2019-04-29 13:45:53 -07:00
Pascal Vizeli
4c4f0e38d4 Fix media_player alexa power control bug (#23537) 2019-04-29 22:40:55 +02:00
Paulus Schoutsen
5e3e730496 Install requirements when checking config (#23500)
* Install requirements when checking config

* PyLint
2019-04-29 09:54:42 -07:00
Erik Montnemery
84f778d23c Improve logging of exceptions in async_create_task (#22689)
* Improve logging of exceptions in async_create_task

* Move wrapping+logging to util.logging

* Minor refactor, fix typing

* Add test

* Remove useless @wraps, fix confusing parameter name

* Review comment
2019-04-29 09:53:22 -07:00
David F. Mulcahey
75f53b2799 Allow direct binding via ZHA for the ZLL profile (#23536)
* allow binding for zll profile
* update check - review comment
2019-04-29 11:35:18 -04:00
Aaron Bach
e08f2ad18d Add current disease data to IQVIA (#23052)
* Add current and historical disease data to IQVIA

* Added fetcher

* Added disease sensor mapping

* Changed incorrect key

* Removed other extraneous const usage
2019-04-29 09:06:23 -06:00
David F. Mulcahey
5aa9a1a7c2 limit concurrent updates to avoid network flood (#23534) 2019-04-29 09:39:37 -04:00
Penny Wood
5e045f3df2 Allow device_class for template covers
* #23486. Allows device_class to be set for template covers
2019-04-29 20:38:59 +08:00
Anders Melchiorsen
471a26bde1 Do not log tracebacks for influxdb write errors (#23522)
* Do not log influxdb write exceptions

* Log exception name
2019-04-29 06:39:45 -05:00
Anders Melchiorsen
2245ee98e3 Ignore stale directories (#23464)
* Ignore stale directories

* Remove redundant tests

* Revert "Remove redundant tests"

* Print warning when skipping directories

* Suggest to remove stale directory
2019-04-29 10:53:27 +02:00
Anders Melchiorsen
0ecf152153 Continuous discovery of Sonos speakers (#23484) 2019-04-29 10:20:09 +02:00
mcc05
5529bcc114 Fixed AlexaPowerController to report power state for thermostats (#23468)
Fixed AlexaPowerController to report power state for thermostats, to look if state is OFF return OFF, otherwise report ON as thermostats have multiple values for ON
2019-04-28 21:29:12 -04:00
Joakim Plate
b4a7980084 Update Philips js to v0.0.8 (#23462)
* Don't send volume on volume set

This needs updated lib

* Bump version and avoid getting channels explicitly

* Add myself as codeowner

* Use version 0.0.8 instead which doesn't reuse session

Some TV's doesn't play nice with HTTP/1.1 connection
re-use.

* Add new requirement to requirements_all.txt
2019-04-28 21:27:35 -04:00
Paulus Schoutsen
0f49a9cb7b Return state when changing optimistic covers (#23498) 2019-04-28 12:09:20 -07:00
Erik Montnemery
2f45a7e3b9 Fix cleanup of dynamic group (#23475) 2019-04-28 12:09:06 -07:00
Wojciech Mamak
b60c7ce479 Fixed bug with max_result (#23507)
The config option 'max_result' was assigned to not existing 'max_result' variable, it should be assigned to 'maxResult'.
The current version causes an error when max_result option is used.
2019-04-28 21:01:33 +02:00
Anders Melchiorsen
41d9bd42af Catch RequestException in influxdb writer (#23508) 2019-04-28 20:57:58 +02:00
Alok Saboo
2fecc7d5a4 Update aiolifx_effects to 0.2.2 (#23473) 2019-04-28 20:46:49 +02:00
Robin
687bbce900 Fixes local_file camera service (#23479)
* Fixes service

Fixes service so only the target camera is updated

* Update test_camera.py

* fix lint
2019-04-28 19:32:02 +01:00
chmielowiec
54c34bb224 Display person component as occupancy sensor HomeKit (#23451) 2019-04-28 18:38:21 +02:00
Anders Melchiorsen
37badbbf09 Skip flaky stream tests (#23493)
* Skip flaky test_hls tests

* Skip flaky test_recorder tests
2019-04-28 13:58:19 +02:00
Paulus Schoutsen
b09f5b6743 Only include agent user ID in SYNC responses (#23497) 2019-04-28 09:42:05 +02:00
Paulus Schoutsen
2dbe6d3289 Updated frontend to 20190427.0 2019-04-27 22:18:18 -07:00
Paulus Schoutsen
300d1f44a6 Updated frontend to 20190427.0 2019-04-27 22:18:05 -07:00
David Bonnes
7458f1f6ef Add a warning that honeywell/EU is to be deprecated (#23469)
* Add a warning that honeywell/EU is to be deprecated

* improve warning
2019-04-27 22:27:41 +02:00
Paulus Schoutsen
26bf1b2173 Fix Hue sensors returning None value (#23478) 2019-04-27 13:27:17 -07:00
Andrew Sayre
f1b2622d78 Use remote image for HEOS (#23420) 2019-04-27 13:02:42 -07:00
Anders Melchiorsen
5efe089699 Improve handling of unavailable Sonos speakers (#23472) 2019-04-27 19:05:50 +02:00
Erik Montnemery
b6a13262da Bump pychromecast (#23463) 2019-04-27 09:17:50 -07:00
Anders Melchiorsen
148860587c No longer promote imports inside methods (#23471) 2019-04-27 09:16:44 -07:00
anrudolph
6be798bffc Added option to use self-signed certificates (#23139)
* Added option to use self-signed certificates

I defined a new option for configuration.yaml, 'verify_ssl', which is set to 'True' by default for obvious security reasons. However, in order to work with self-signed certificates, it is now possible to disable the certificate validation.(eg, I use a nextcloud instance with self-signed certificates)
Credit for code in line 57 goes to user 'gen2' on the homeassistant community, who suggested this solution. 
https://community.home-assistant.io/t/caldav-configuration/38198/25
I only took it a step further and made it a config option.

* Update calendar.py

* Added the import of CONF_VERIFY_SSL

I hope this passes the test now...

* Update homeassistant/components/caldav/calendar.py

Cool! Didn't know about that possibility, my coding experience is literally two weeks. Thanks for sharing!

Co-Authored-By: anrudolph <49680492+anrudolph@users.noreply.github.com>

* Removed some lines of code

I think, in order for the last commit to work, these lines have to be removed. Correct?

* Trying to get this passing the checks

Trying around to get the simplified code to work
2019-04-27 10:40:20 -05:00
Phil Bruckner
1dbfa8f3be Bump amcrest to 1.4.0 and use new storage_all method (#23446)
Improve sdcard sensor so it only sends one command to camera per update as opposed to the four it used to send to reduce network traffic and make data consistent. Also better handle returned values of 'unknown'.
2019-04-27 10:24:07 -05:00
cgtobi
96fb311f6b Fix netatmo_public sensor to use netatmo authentication (#23455) 2019-04-27 10:18:55 -05:00
Aaron Bach
bdc95e76d0 Fix broken forecast trend attribute in IQVIA (#23454) 2019-04-27 10:17:57 -05:00
Anders Melchiorsen
c174b83f54 Return of travis (#23409)
* Return .travis.yml

This reverts commit a5b03541e9.

* Remove coveralls

* Remove deploy

* Support only the extreme Python versions

* Ignore bleeding edge

* Remove docker service
2019-04-27 12:30:24 +02:00
Aaron Bach
bf050adcf3 Remove historical allergen and asthma sensors from IQVIA (#23258)
* Remove historical sensors from IQVIA

* Removed old imports

* Removed "Yesterday" sensors
2019-04-26 23:28:55 -06:00
Ian
c2e7445271 Add new nextbus sensor (#20197)
* Added new nextbus sensor

* Fix order in requirements_all after merge

* Add more flexible parsing of JSON lists

* Undo tox change
2019-04-26 19:51:58 -05:00
David Bonnes
f25183ba30 update geniushub client library to fix issue #23444 (#23450) 2019-04-26 18:18:30 -04:00
Paulus Schoutsen
d6f6273ac2 Make setup more robust (#23414)
* Make setup more robust

* Fix typing
2019-04-26 21:41:29 +02:00
Fredrik Erlandsson
61ea6256c6 Fix point setup (#23441)
Fix point setup
2019-04-26 20:56:55 +02:00
Fredrik Erlandsson
08c36e0089 Fix daikin setup (#23440)
Fix daikin setup
2019-04-26 20:24:01 +02:00
Aaron Bach
8fe95f4bab Additional cleanup of IQVIA integration (#23403)
* Additional cleanup of IQVIA integration

* Task

* Moved import

* Fixed exception

* Member comments (round 1)

* Member comments (round 2)

* Member comments
2019-04-26 11:06:46 -06:00
Toon Willems
606dbb85d2 Fix Flux component (#23431)
* Fix Flux component

* Update manifest.json

* Update manifest.json
2019-04-26 08:55:30 -07:00
cgtobi
b84ba93c42 Refactor netatmo to use hass.data (#23429)
* Refactor NETATMO_AUTH to use hass.data

* Minor cleanup

* Rename conf to auth and other suggestions by Martin

* Revert webhook name change

* Rename constant

* Move auth

* Don't use hass.data.get()

* Fix auth string
2019-04-26 17:15:37 +02:00
Anders Melchiorsen
5dbf58d67f Remove support for deprecated Sonos configuration (#23385) 2019-04-26 08:56:43 +02:00
Andrew Sayre
d038d2426b Add missing feature support flag (#23417) 2019-04-26 08:47:40 +02:00
Andrew Sayre
b5725f8f19 Fix supported features gates in media_player volume up/down services (#23419)
* Correct media player feature gates

* Fix failing test

* Lint...
2019-04-25 21:42:39 -07:00
Tom Schneider
eefb9406c2 restore battery_quantity for zha devices (#23320) 2019-04-25 22:44:38 -05:00
Robert Svensson
c229a314c6 Bump requirement to v55 (#23410) 2019-04-25 22:42:07 -05:00
Joakim Plate
7d5c1ede72 Broadlink fixup unintended breakage from service refactor (#23408)
* Allow host/ipv6 address for broadlink service

This matches switch config and is a regression fix

* Restore padding of packets for broadlink

* Drop unused import

* Fix comment on test
2019-04-25 21:33:05 -05:00
Evan Bruhn
7a6acca6bb Add device info for Logi Circle camera and sensor entities (#23373) 2019-04-25 15:21:04 -07:00
Markus Jankowski
9d67c9feb6 Add Types to Homematic IP (#23401) 2019-04-25 15:13:07 -07:00
Markus Jankowski
cef7ce11ad check if sabotage attr is in device (#23397) 2019-04-25 15:12:36 -07:00
panosmz
e182b95921 add key parameter (#23381) 2019-04-25 23:35:30 +02:00
cgtobi
d2e0c6dbc2 Bump youtube-dl version to 2019.04.24 (#23398) 2019-04-25 23:21:23 +02:00
Joakim Plate
39932d132d Add device classes for media player and map to google types (#23236)
* Add device classes for media player and map to google types

* Switch default class for media_player to media
2019-04-25 13:12:11 -07:00
Jason Hu
7e8f2d72b6 Add error handling for migration failure (#23383) 2019-04-25 12:58:10 -07:00
Daniel Høyer Iversen
4816a24b3c Update xiaomi library (#23391) 2019-04-25 14:25:32 -04:00
Chuang Zheng
3d91d76d3d async_setup_component stage_1_domains (#23375) 2019-04-25 05:50:28 -07:00
Erik Montnemery
5376e15286 Convert some test helpers to coroutines and adjust tests (#23352)
* Convert some test helpers to coroutines

* Fix tests
2019-04-25 10:14:16 +02:00
Phil Bruckner
86b017e2f0 Add amcrest camera services and deprecate switches (#22949)
* Add amcrest camera services and deprecate switches

- Implement enabling and disabling motion detection from camera platform.
- Add amcrest specific camera services for controlling audio stream, motion recording, continuous recording and camera color mode, as well as moving camera to PTZ preset and starting and stopping PTZ tour function.
- Add camera attributes to indicate the state of the various camera settings controlled by the new services.
- Deprecate switches in favor of camera services and attributes.

* Rename services and move service handling to __init__.py

Rename services from 'camera.amcrest_xxx' to 'amcrest.xxx'. This allows services to be documented in services.yaml.

Add services.yaml.

Reorganize hass.data[DATA_AMCREST] and do some general cleanup to make various platform modules more consistent.

Move service handling code to __init__.py from camera.py.

* Update per review comments, part 1

- Rebase
- Add permission checking to services
- Change cv.ensure_list_csv to cv.ensure_list
- Add comment for "pointless-statement" in setup
- Change handler_services to handled_services
- Remove check if services have alreaday been registered
- Pass ffmpeg instead of hass to AmcrestCam __init__
- Remove writing motion_detection attr from device_state_attributes
- Change service methods from callbacks to coroutines

* Update per review comments, part 2

- Use dispatcher to signal camera entities to run services.
- Reorganize a bit, including moving a few things to new modules const.py & helpers.py.

* Update per review comments, part 3

Move call data extraction from camera.py to __init__.py.
2019-04-24 22:39:49 -07:00
Richard Mitchell
c216ac7260 Fix race condition. (#21244)
If the updater is running at the same time, this can result in this dict changing size during iteration, which Python does not like.
2019-04-24 22:38:10 -07:00
Paulus Schoutsen
de6fdb09f4 Add media player external url (#23337)
* Add media player external url

* Lint

* Simplify

* Update __init__.py

* Update __init__.py

* Use 302
2019-04-24 22:37:29 -07:00
Andrew Sayre
e3e7fb5ff6 Bump pyheos to 0.4.1 (#23360)
* Bump pyheos==0.4.1

* Refresh player after reconnection
2019-04-24 21:31:31 -07:00
Ian
6fb5b8467b Fix tox.ini lint target (#23359)
tox fails due to being unable to reference the `script` module when
trying to run `script/gen_requirements_all.py`. Instead it needs to be
run as a module.
2019-04-24 21:30:46 -07:00
Steven Looman
24766df179 Upgrade to pyubee==0.6 (#23355) 2019-04-24 21:13:31 -07:00
dreed47
ec9db7f9a2 fix for issue #21381 (#23306) 2019-04-24 21:11:07 -07:00
Aaron Bach
0d796a0fb9 Convert Pollen.com sensor into IQVIA component (#22986)
* Moved pollen integration to iqvia

* Stitched in new library

* Added __init__

* Completed component v1

* Updated requirements

* Updated CODEOWNERS

* Updated .coveragerc

* Removed requirements

* Static check
2019-04-24 21:09:01 -06:00
Beat
96735e41af Add support for a wider variety of EnOcean devices (#22052)
* Implement EnOcean temperature and humidity sensors.

* Bump EnOcean version to 0.50
* Refactor components for more generic device handling
* Move radio packet data interpretation to specific devices

* Update CODEOWNERS

* Implement code review changes
2019-04-25 00:30:46 +02:00
Greg Laabs
fef1dc8c54 Bump ecovacs lib 2 (#23354)
* Bump Ecovacs dependency (sucks)

Update to new version of sucks, which switches to a custom-built SleekXMPP that turns off certificate validation. This is to fix issues caused by Ecovacs serving invalid certificates.

* Update requirements file
2019-04-24 14:47:22 -07:00
Niels Mündler
ef5ca63bf0 Fix non-syncthru supporting printers (#21482)
* Fix non syncthru-syncthru supporting printers

* Formatting

* Update requirements_all

* Update syncthru.py

* Fix component to be async (as is the used SyncThru implementation)

* Add async syntax

* Omit loop passing

* Don't await async_add_platform

* Generate new all requirements

* Explain, why exception is caught in setuExplain, why exception is caught in setupp

* Handle failing initial setup correctly

* Formatting

* Formatting

* Fix requested changes

* Update requirements and add nielstron as codeowner

* Run codeowners script

* Make notification about missing syncthru support a warning

* Revert pure formatting

* Fix logging
2019-04-24 23:39:31 +02:00
Paulus Schoutsen
d218ba98e7 Fix config test when current version is 92 (#23356) 2019-04-24 13:37:08 -07:00
Paulus Schoutsen
d53a00d054 Updated frontend to 20190424.0 2019-04-24 11:15:56 -07:00
Joakim Plate
62fcb1895e Device type garage for binary sensor garage_door (#23345)
* Switch binary sensor to garage for garage_door

* Add test for cover garage device type
2019-04-24 09:56:22 -07:00
Jason Hu
843bad83fa Remove ghost folder (#23350) 2019-04-24 09:55:48 -07:00
Penny Wood
e850ccb82c Fixed test (#23343) 2019-04-24 09:55:37 -07:00
Pascal Vizeli
f4e7364651 Netatmo 5min fetch interval (#23341) 2019-04-24 09:54:51 -07:00
Fabian Affolter
82ff5cbe0f Upgrade ruamel.yaml to 0.15.94 (#23344) 2019-04-24 09:52:29 -07:00
Joakim Plate
e11e6e1b04 Volume trait for google assistant (#23237)
* Add action.devices.traits.Volume

* Drop media player from brightness trait

* Factor out commands into separate functions

* Drop support for explicit mute
2019-04-24 09:08:41 -07:00
Markus Jankowski
2863ac1068 Fix Homematic IP Cloud remaining light imports (#23339)
* Fix missing impor reorg

* Add brackets

* Removed trailing whitespaces
2019-04-24 13:27:45 +02:00
Fabian Affolter
3d04856cbd Upgrade youtube_dl to 2019.04.17 (#23342) 2019-04-24 11:56:43 +02:00
Joakim Plate
7c55b9f087 Expose door cover/binary_sensor as door type (#23307)
* Expose door cover/binary_sensor as door type

More logical to ask "What doors are open" than "What sensors are open"

* Add test for binary_sensor device_classes

* Cosmetic flake8

* Add test for device class for cover
2019-04-23 19:25:20 -07:00
Kyle Pinette
6681605c34 Added override for kwikset 888. (#23327) 2019-04-23 22:24:43 -04:00
Daniel Høyer Iversen
95bbea20a8 Fix Switchbot restore state (#23325)
* switchbot library

* req

* req

* issue #23039
2019-04-23 19:23:52 -07:00
Andre Lengwenus
662375bdd7 Changes due to manifest.json. Awaiting coroutines instead of creating tasks (#23321) 2019-04-23 19:20:20 -07:00
Paulus Schoutsen
aa26f90420 Add sensor and binary senseor to default expose (#23332) 2019-04-23 19:19:23 -07:00
Jason Hu
c61b6cf616 Support unicode in configuration migration (#23335) 2019-04-23 17:47:09 -07:00
Markus Jankowski
16d8e92b06 Reorg Homematic IP Cloud imports and minor fixes (#23330)
* reorg HmiP Imports after introduction of manifests

* add type to some functions

* fix usage of dimLevel (HomematicipDimmer,HomematicipNotificationLight)

* align naming to HomematicipMultiSwitch: channel_index -> channel for (HomematicipNotificationLight)

* fix lint

* Fix is_on for dimmers

* fix lint
2019-04-24 01:47:31 +02:00
ktnrg45
68d3e624e6 Fix ps4 not able to use different PSN accounts (#22799)
* Remove skipping of creds step.

* Check for device added per account

* typo

* lint

* Pylint

* Fix test

* Fix test

* Typo

* Add auto location

* blank space

* Add new identifier handling + fix select source

* Add cred_timeout error

* add credential timeout error

* Fix Tests

* patch decorator

* Update test_config_flow.py

* add test

* Revert

* Rename vars

* fix tests

* Add attr location

* Bump 0.6.0

* Bump 0.6.0

* Bump 0.6.0

* Update handling exception

* Update remove method

* Update tests

* Refactoring

* Pylint

* revert

* chmod

* 0.6.1

* 0.6.1

* 0.6.1

* Remove func

* Add migration

* Version 3

* Remove redefinition

* Add format unique id

* Add format unique id

* pylint

* pylint

* 0.7.1

* 0.7.1

* 0.7.1

* Changes with media_art call

* Add library exception

* 0.7.2

* 0.7.2

* 0.7.2

* Version and entry_version update

* Revert list comprehension

* Corrected exception handling

* Update media_player.py

* Update media_player.py

* white space
2019-04-24 01:32:36 +02:00
Paulus Schoutsen
d505f1c5f2 Always set latest pin (#23328) 2019-04-23 13:13:00 -07:00
dreed47
b252d8e2cd Zestimate - Added check for the existence of data in response (#23310) 2019-04-23 11:44:13 -07:00
Josef Schlehofer
c040f7abc0 Upgrade attrs to 19.1.0 (#23323) 2019-04-23 10:14:02 -07:00
Joakim Sørensen
2871a650f6 Handle traccar connection errors (#23289)
* Handle connection errors

* Fix lint issue E127

* Remove periods from logs

* Merge connection checks

* Fail with bad credentials

* Move stuff around for async_init

* Fix E128 linting issue

* Simplify
2019-04-23 08:46:11 -04:00
Paulus Schoutsen
5b0ee473b6 Add get_states faster (#23315) 2019-04-23 12:46:22 +02:00
Paulus Schoutsen
00d26b3049 Random hassfest fixes (#23314) 2019-04-23 08:34:36 +02:00
Joakim Sørensen
ddb5ff3b71 Show correct version for stable (#23291) 2019-04-22 22:07:56 -07:00
Paulus Schoutsen
72bbe2203e Dont cache integrations that are not found (#23316) 2019-04-22 22:06:58 -07:00
Pascal Vizeli
2a720efbd4 Fix hass.io panel_custom/frontend (#23313)
* Fix hass.io panel_custom/frontend

* Update manifest.json
2019-04-22 21:47:12 -07:00
Jc2k
baeb3cddc6 Set placeholders in homekit config flow title (#23311) 2019-04-22 21:32:39 -07:00
VDRainer
ee88433fb1 Create services.yaml for input_datetime (#23303)
* Create services.yaml for input_datetime

* HA error while parsing a flow mapping
2019-04-22 21:29:34 -07:00
Richard Mitchell
845d81bdae Correct calculation and units of light level values. (#23309) 2019-04-22 21:28:40 -07:00
Anders Melchiorsen
d0f9595ad9 Add connection control for netgear_lte (#22946) 2019-04-22 22:44:46 +02:00
Pawel
9007e17c3e MQTT Vacuum State Device (#23171)
* add StateVacuum MQTT
2019-04-22 21:49:15 +02:00
Joakim Plate
e85af58e43 RFC: Upgrade philips_js component version and support channels and sources (#23061)
* Drop unused constant

* Don't default to localhost

A philips tv will never run on localhost

* Use library internal state

* Add play media support for channels

* Control update manually

This allow us to delay update of state when we perform
and action.

* Bump version for support for api v1 again

* Consider missing source and only channels as channels

* Fix some flake8 tasks

* Fix some pylint errors

* Adjust requirements_all file

* Switch to async_add_executor_job

* Assume device turns of off a sucessfull standby call
2019-04-22 12:26:15 -07:00
Otto Winter
0c90bfb936 Fix ESPHome setup errors in beta (#23242)
* Fix ESPHome setup errors in beta

* Update requirements_all.txt
2019-04-22 12:13:21 -07:00
Andrew Sayre
8daba68dc1 Add support to play url (#23273) 2019-04-22 12:10:55 -07:00
Austin Mroczek
e3981b6498 Bump skybellpy to 0.4.0 (#23294)
* Bump skybellpy to 0.4.0

* Bump skybellpy to 0.4.0 in requirements_all.txt
2019-04-22 12:09:55 -07:00
Erik Montnemery
a89c7f8feb Improve MQTT tests (#23296)
* Improve MQTT tests

* Tweak
2019-04-22 08:48:50 -04:00
Markus Jankowski
357631d659 Add homematicip cloud temperature sensor from thermostats (#23263) 2019-04-22 09:30:49 +02:00
Josef Schlehofer
3b0660ae89 Upgrade pyotp to 2.2.7 (#23274) 2019-04-21 09:03:17 +02:00
Josef Schlehofer
a8632480ff Upgrade xmltodict to 0.12.0 (#23277) 2019-04-21 13:52:20 +09:00
Aaron Bach
80653824d9 Add ctags file to .gitignore (#23279) 2019-04-20 21:15:19 -06:00
damarco
b3c7142030 Bump zigpy and zigpy-xbee (#23275) 2019-04-20 18:04:30 -04:00
damarco
df32830f17 Bump zigpy-deconz (#23270) 2019-04-20 10:12:28 -04:00
Andrew Sayre
b697bb7a26 Update pyheos and log service errors in HEOS integration (#23222)
* Update pyheos and command error handling

* Correct comment and remove unnecessary autospec
2019-04-19 22:22:40 -04:00
Paulus Schoutsen
a3ecde01ee Updated frontend to 20190419.0 2019-04-19 16:57:45 -07:00
Andrew Sayre
e2ed2ecdc0 Return 0 instead of None (#23261) 2019-04-19 16:56:34 -07:00
Erik Montnemery
1e0bc97f56 Drop unnecessary block_till_done (#23256) 2019-04-19 16:08:11 -07:00
Erik Montnemery
eebb452fb5 Drop unnecessary block_till_done, improve tests for MQTT Cover tests (#23255) 2019-04-19 16:07:28 -07:00
Erik Montnemery
2c42e1a5cb Drop unnecessary block_till_done for MQTT tests (#23254)
* Drop unnecessary block_till_done

* Drop unnecessary block_till_done
2019-04-19 14:59:16 -07:00
Erik Montnemery
28c411c742 Drop unnecessary block_till_done for MQTT fan tests (#23253) 2019-04-19 14:58:44 -07:00
Tomer Figenblat
9d8d8afa82 Added component named switcher_kis switcher water heater integration. (#22325)
* Added component named switcher_kis switcher water heater integration.

* Fixed conflicts.

* Updated requirements.

* Added manifest.json file and updated CODEOWNERS.

* Fixed requirements_all.txt.

* Better component tests.

* Removed unnecessary parameter from fixture function.

* Removed tests section from mypy.ini.

* Remove unused ENTITY_ID_FORMAT.

* Stop udp bridge when failed to setup the component.

* Replace DISCOVERY_ constants prefix with DATA_.

* Various change requests.

* Fixed constant name change remifications.

* Added explicit name to fixture.

* Various change requests.

* More various change requests.

* Added EventType for homeassistant.core.Event.

* Switched from event driven data distribution to dispatcher type plus clean-ups.

* Removed name and icon keys from the component configuration.

* Various change requests.

* Various change reqeusts and clean-ups.

* Removed unnecessary DEPENDENCIES constant from swith platform.

* Replaced configuration data guard with assert.

* Removed unused constants.

* Removed confusing type casting for mypy sake.

* Refactor property device_name to name.

* Removed None guard effecting mypy only.

* Removed unnecessary function from switch entity.

* Removed None guard in use by mypy only.

* Removed unused constant.

* Removed unnecessary context manager.

* Stopped messing around with mypy.ini.

* Referring to typing.TYPE_CHECKING for non-runtime imports.

* Added test requierment correctyly.

* Replaced queue.get() with queue.get_nowait() to avoid backing up intervals requests.

* Revert changes in mypy.ini.

* Changed attributes content to device properties instead of entity properties.

* Fixed typo in constant name.

* Remove unnecessary async keyword from callable.

* Waiting for tasks on event loop to end.

* Added callback decorator to callable.
2019-04-19 16:54:48 -05:00
cgtobi
31e514ec15 Add missing services.yaml file for hue (#23217)
* Add hue services.yaml

* Add lifx services.yaml

* Add lutron services.yaml

* Update lifx services.yaml

* Update hue services.yaml

* Revert lifx services.yaml as it is not necessary

* Remove hue from lights/services.yaml
2019-04-19 14:53:58 -07:00
Erik Montnemery
73a7d5e6f4 Drop unnecessary block_till_done, improve tests (#23252) 2019-04-19 14:52:23 -07:00
Erik Montnemery
f584878204 Drop unnecessary block_till_done (#23251) 2019-04-19 14:51:48 -07:00
Paulus Schoutsen
0533f56fe3 Ask users for a pin when interacting with locks/garage doors (#23223)
* Ask users for a pin when interacting with locks/garage doors

* Deprecate allow_unlock option
2019-04-19 14:50:21 -07:00
Erik Montnemery
416af5cf57 Drop unnecessary block_till_done (#23250) 2019-04-19 14:10:48 -07:00
Erik Montnemery
557211240e Drop unnecessary block_till_done, improve tests (#23249) 2019-04-19 14:08:54 -07:00
Erik Montnemery
13e0691c90 Drop unnecessary block_till_done, improve tests (#23248) 2019-04-19 14:08:02 -07:00
Erik Montnemery
0e429cca33 Drop unnecessary block_till_done, improve tests (#23247) 2019-04-19 12:26:56 -07:00
Erik Montnemery
887e1cd8e3 Drop unnecessary block_till_done, improve tests (#23246) 2019-04-19 12:19:46 -07:00
Richard Mitchell
c899e2a662 Name sensors correctly (#23208)
* Hue motion senors are motion sensors, not presence sensors.

* Name the sensors 'motion' instead of 'presence' - match the HA paradigm.
2019-04-19 11:01:54 -07:00
Jc2k
e7054e0fd2 Avoid calling async code in sync context (#23235) 2019-04-19 10:59:54 -07:00
GoNzCiD
9cf9be8850 Add accuracy and status for Traccar (#23180)
* Fix read gps position accuracy & read device status

* Fix: W291 trailing whitespace & E501 line too long (80 > 79 characters)

* Upgrade pytraccar dependency to 0.7.0

* met snake case
2019-04-19 18:42:27 +02:00
Christopher Viel
b1b269b302 Add more CPU temp. labels to Glances (#23179) 2019-04-19 15:21:16 +02:00
Maciej Bieniek
6e300bd438 Add missing service for persistent_notification (#23230) 2019-04-19 15:14:48 +02:00
Jc2k
21a194f9d8 Review feedback from #23191 (#23233) 2019-04-19 08:39:06 -04:00
Jc2k
b3a8b0056b Add and use an async_fire_service_discovered helper (#23232) 2019-04-19 08:38:50 -04:00
Pascal Roeleven
b2a7699cdf Change configuration for orangepi (#23231) 2019-04-19 13:26:53 +02:00
Pascal Vizeli
3e443d253c Hass.io Add-on panel support for Ingress (#23185)
* Hass.io Add-on panel support for Ingress

* Revert part of discovery startup handling

* Add type

* Fix tests

* Add tests

* Fix lint

* Fix lint on test
2019-04-19 09:43:47 +02:00
Aaron Bach
6a7bd19a5a Remove archived 17track packages from the entity registry (#23049)
* Remove archived 17track packages from the entity registry

* Fix incorrect __init__.py

* Member comments

* Member comments

* Fix too many params

* Member comments

* Member comments
2019-04-19 09:14:14 +02:00
Paulus Schoutsen
dbe0ba87a3 Async fix for bluetooth stopping (#23225) 2019-04-19 08:56:24 +02:00
Erik Montnemery
bea7e2a7fa Fix clearing error message for MQTT vacuum (#23206)
* Fix clearing error message

* Remove redundant hass.async_block_till_done
2019-04-18 21:01:19 -07:00
Tsvi Mostovicz
eac2388d49 Set default value for input_datetime (#21919)
* Set default value for input_datetime

If no initial value is set and no value is available to be restored, set the default value as specified in the docs to 1970-01-01 00:00.

* Use regular if statement

Ternary statements can be tricky if you try to keep the value the same if not something

* Add test for default values

Check that if no initial value is set, state returns 1970-01-01 at 00:00

* Fix tests - was passing wrong args to time/date

* Verify we get a timestamp attribute for input_datetime

This adds a check that when using the default timestamp of 1970-1-1 00:00:00, we
get a timestamp attribute. This is waht prompted this PR in the first place, as
when specifying an automation trying to access the timestamp attribute for a non-
initialized input_datetime HASS wouldn't start.

* Simplify the change for a default value

Based on @balloob comment. Simplifying the code

* Revert "Simplify the change for a default value"

This reverts commit c2d67f19a6.
2019-04-18 21:00:35 -07:00
Erik Montnemery
7a84cfb0be Fix optimistic mode + other bugs, tests (#22976) 2019-04-18 20:59:41 -07:00
Paulus Schoutsen
b0ce3dc683 Only comment with changed coverage on release PRs [skip-ci] (#23224) 2019-04-18 20:58:35 -07:00
Erik Montnemery
70ba5eb0ef Add json_attributes_template (#22981) 2019-04-18 20:55:10 -07:00
Paulus Schoutsen
1761b25879 Remove copy paste error 2019-04-18 20:31:53 -07:00
David F. Mulcahey
c2b4e24372 update zha-quirks (#23215) 2019-04-18 20:23:48 -04:00
David F. Mulcahey
5e363d124e fix bindable devices (#23216) 2019-04-18 20:21:30 -04:00
Paulus Schoutsen
a52f96b23a Add stub services.yaml and make validation mandatory (#23213) 2019-04-18 15:13:35 -07:00
Raman Gupta
620c6a22ac Update vizio component to support latest pyvizio with soundbar support (#22294)
* update vizio component to support latest pyvizio with soundbar support

* Resolved Hound issues

* Additional Hound issue

* Updated based on feedback

* Style updates

* Additional code styling changes

* Added check for auth token not being set for tv device_class

* Limited lines to 80 characters

* moved MAX_VOLUME into base package

* fixed supported commands

* styling changes

* fix styling yet again

* remove unnecessary elif

* removed play/pause since I can't get current state

* changed value access method from config dict

* fixed flake failures

* try to fix docstring

* try to fix docstring

* fixed auth token validation

* rebase and regenerate requirements_all.txt

* updated log text

* line length fix

* added config validation to handle conditionally optional parameter

* updated validate setup log message and string formatting based on review

* fix pylint error

* less ugly
2019-04-18 22:48:05 +02:00
Steven Looman
e1d1f21a74 Don't create connections between sensors. Fixes #22787 (#23202) 2019-04-18 13:47:17 -07:00
Robbie Trencheny
66b2ed930c Set encoding before connecting (#23204) 2019-04-18 13:46:49 -07:00
Paulus Schoutsen
33b8241d26 Add services.yaml validator (#23205)
* Add services.yaml validator

* Fix path
2019-04-18 13:40:46 -07:00
Otto Winter
37cd711c96 Create empty services.yaml for esphome (#23200) 2019-04-18 13:10:36 -07:00
Alok Saboo
0eb8c77889 Create services.yaml for python_script and script (#23201)
* Create services.yaml for python_script

* Create services.yaml for script
2019-04-18 13:10:25 -07:00
Alok Saboo
4be30f7c88 create services.yaml for shell_command (#23210) 2019-04-18 13:10:10 -07:00
Alok Saboo
70c5bd4316 Create services.yaml for Tuya (#23209) 2019-04-18 13:09:41 -07:00
Florian Klien
daf2f30822 set myself as codeowner of xmpp, removed me from notify/* (#23207)
* set myself as codeowner of xmpp, removed me from notify/*

* changed the manifests as well
2019-04-18 12:26:02 -07:00
Paulus Schoutsen
fda483f482 Don't load component when fetching translations (#23196) 2019-04-18 11:11:43 -07:00
Robbie Trencheny
c2cce13e2a Migrating codeowners-mention to Heroku 2019-04-18 11:11:26 -07:00
David F. Mulcahey
38d23ba0af Misc. ZHA changes (#23190)
* handle the off part of on with timed off command

* use correct var

* only bind / configure cluster once

* clean up channel configuration

* additional debug logging

* add guard

* prevent multiple discoveries for a device

* cleanup and still configure on rejoin
2019-04-18 12:24:02 -04:00
Robbie Trencheny
5e1338a9e4 Further improve IndieAuth redirect_uri lookup failure logs (#23183) 2019-04-18 09:03:25 -07:00
Jc2k
4ac9a2e9de Add storage for cacheable homekit entity maps. (#23191) 2019-04-18 08:55:34 -07:00
Richard Mitchell
f57191e8dd Hue motion senors are motion sensors, not presence sensors. (#23193) 2019-04-18 08:53:02 -07:00
David Bonnes
11fb4866a8 Improve configuration schema for Geniushub integration (#23155)
* configuration for hub tokens are now separate from host addresses/credentials

* small change to docstring

* use *args **kwargs
2019-04-18 14:37:52 +02:00
Penny Wood
d9fb3c8c28 Potential None (#23187) 2019-04-18 14:04:30 +02:00
Pascal Roeleven
df475cb797 Adds Orange Pi GPIO platform (#22541)
* Adds Orange Pi GPIO platform

* Add manifest.json

* Remove cover platform

* Apply requested changes

* Remove switch platform

* Update CODEOWNERS

* Remove obsolete dependecies/requirements
2019-04-18 19:43:34 +09:00
Rohan Kapoor
f588fef3b4 Add minimum/maximum to counter (#22608)
* Added minimum/maximum to counter

* Added min/max testcases

* remove duplicate

* cosmetic changes

* removed blank lines at eof

* added newline at eof

* type cv -> vol

* more fixes

* - fixed min/max warnings
- fixed failing tests

* Added linewrap

* - Added cast to int
- Fixed double quotes

* - removed None check in __init__
- fixed failing test

* copy paste fix

* copy paste fix

* Added possibility to change counter properties trough service call

* fixed copy paste errors

* Added '.' to comment

* rephrased docstring

* Fix tests after rebase

* Clean up per previous code review comments

* Replace setup service with configure

* Update services description

* Update tests to use configure instead of setup
2019-04-18 19:02:01 +09:00
Dries De Peuter
6e4083d7f4 Fix niko home control dependency installation (#23176)
* Upgrade niko-home-control library

* Fix additional feedback

* Lint
2019-04-18 10:52:48 +02:00
Joakim Plate
4a2a130bfa Google assistant skip missing type (#23174)
* Skip entity if no device type found

* Add test for potentially skipped binary sensors

* Reorg code, add tests to ensure all exposed things have types

* Lint

* Fix tests

* Lint
2019-04-17 22:37:39 -07:00
Paulus Schoutsen
ce8ec3acb1 Don't warn for missing services (#23182) 2019-04-17 22:27:11 -07:00
Richard Mitchell
474ac8b09e Add basic support for native Hue sensors (#22598)
* Add basic support for native Hue sensors

* Update coveragerc

* Simplify attributes

* Remove config option

* Refactor and document device-ness and update mechanism

* Entity docstrings

* Remove lingering config for sensors

* Whitespace

* Remove redundant entity ID generation and hass assignment.

* More meaningful variable name.

* Add new 'not-darkness' pseudo-sensor.

* Refactor sensors into separate binary, non-binary, and shared modules.

* formatting

* make linter happy.

* Refactor again, fix update mechanism, and address comments.

* Remove unnecessary assignment

* Small fixes.

* docstring

* Another refactor: only call API once and make testing easier

* Tests & test fixes

* Flake & lint

* Use gather and dispatcher

* Remove unnecessary whitespace change.

* Move component related stuff out of the shared module

* Remove unused remnant of failed approach.

* Increase test coverage

* Don't get too upset if we're already trying to update an entity before it has finished adding

* relative imports
2019-04-17 22:13:03 -07:00
Paulus Schoutsen
77244eab1e Fix empty components (#23177) 2019-04-17 19:17:13 -07:00
Jc2k
6bb4199824 Add @Jc2k to codeowners for homekit_controller (#23173) 2019-04-17 19:16:20 -07:00
Richard Mitchell
f6349a6cf4 Kill bluetooth LE scanning gracefully when asked to shut down. (#22586)
* Kill bluetooth LE scanning gracefully when asked to shut down.

* Add missing argument.

* Refactor to use data instead of passing nonlocal variables about.

* Fix typo.
2019-04-17 13:48:17 -07:00
zewelor
fa73b8e37a Make less imports from yeelight (#23124) 2019-04-17 22:05:49 +02:00
Ingo Theiss
0afa01609c Pass configured host string instead of always forcing an ip-address (#23164)
* Pass host string instead of forcing an ip-address

Pass the configured host (https://www.home-assistant.io/components/homematic/#host) instead of always forcing an ip-address. This is required to get SSL certificate validation working.

* Remove unused 'socket' import
2019-04-17 21:35:16 +02:00
Paulus Schoutsen
723d00d33a Bumped version to 0.93.0.dev0 2019-04-17 10:49:25 -07:00
1046 changed files with 35219 additions and 18928 deletions

View File

@@ -57,7 +57,7 @@ commands:
<<# parameters.all >>pip install -q --progress-bar off -r requirements_all.txt -c homeassistant/package_constraints.txt<</ parameters.all>>
<<# parameters.test >>pip install -q --progress-bar off -r requirements_test.txt -c homeassistant/package_constraints.txt<</ parameters.test>>
<<# parameters.test_all >>pip install -q --progress-bar off -r requirements_test_all.txt -c homeassistant/package_constraints.txt<</ parameters.test_all>>
no_output_timeout: 15m
no_output_timeout: 15m
- save_cache:
paths:
- ./venv
@@ -90,7 +90,7 @@ jobs:
name: run static check
command: |
. venv/bin/activate
flake8
flake8 homeassistant tests script
- run:
name: run static type check

View File

@@ -13,3 +13,4 @@ coverage:
url: "secret:TgWDUM4Jw0w7wMJxuxNF/yhSOHglIo1fGwInJnRLEVPy2P2aLimkoK1mtKCowH5TFw+baUXVXT3eAqefbdvIuM8BjRR4aRji95C6CYyD0QHy4N8i7nn1SQkWDPpS8IthYTg07rUDF7s5guurkKv2RrgoCdnnqjAMSzHoExMOF7xUmblMdhBTWJgBpWEhASJy85w/xxjlsE1xoTkzeJu9Q67pTXtRcn+5kb5/vIzPSYg="
comment:
require_changes: yes
branches: master

View File

@@ -22,6 +22,7 @@ omit =
homeassistant/components/alarmdotcom/alarm_control_panel.py
homeassistant/components/alpha_vantage/sensor.py
homeassistant/components/amazon_polly/tts.py
homeassistant/components/ambiclimate/climate.py
homeassistant/components/ambient_station/*
homeassistant/components/amcrest/*
homeassistant/components/ampio/*
@@ -46,12 +47,14 @@ omit =
homeassistant/components/august/*
homeassistant/components/automatic/device_tracker.py
homeassistant/components/avion/light.py
homeassistant/components/azure_event_hub/*
homeassistant/components/baidu/tts.py
homeassistant/components/bbb_gpio/*
homeassistant/components/bbox/device_tracker.py
homeassistant/components/bbox/sensor.py
homeassistant/components/bh1750/sensor.py
homeassistant/components/bitcoin/sensor.py
homeassistant/components/bizkaibus/sensor.py
homeassistant/components/blink/*
homeassistant/components/blinksticklight/light.py
homeassistant/components/blinkt/light.py
@@ -169,10 +172,12 @@ omit =
homeassistant/components/esphome/camera.py
homeassistant/components/esphome/climate.py
homeassistant/components/esphome/cover.py
homeassistant/components/esphome/entry_data.py
homeassistant/components/esphome/fan.py
homeassistant/components/esphome/light.py
homeassistant/components/esphome/sensor.py
homeassistant/components/esphome/switch.py
homeassistant/components/essent/sensor.py
homeassistant/components/etherscan/sensor.py
homeassistant/components/eufy/*
homeassistant/components/everlights/light.py
@@ -247,7 +252,6 @@ omit =
homeassistant/components/hitron_coda/device_tracker.py
homeassistant/components/hive/*
homeassistant/components/hlk_sw16/*
homeassistant/components/homekit_controller/*
homeassistant/components/homematic/*
homeassistant/components/homematic/climate.py
homeassistant/components/homematic/cover.py
@@ -275,9 +279,11 @@ omit =
homeassistant/components/imap_email_content/sensor.py
homeassistant/components/influxdb/sensor.py
homeassistant/components/insteon/*
homeassistant/components/incomfort/*
homeassistant/components/ios/*
homeassistant/components/iota/*
homeassistant/components/iperf3/*
homeassistant/components/iqvia/*
homeassistant/components/irish_rail_transport/sensor.py
homeassistant/components/iss/binary_sensor.py
homeassistant/components/isy994/*
@@ -339,11 +345,13 @@ omit =
homeassistant/components/mastodon/notify.py
homeassistant/components/matrix/*
homeassistant/components/maxcube/*
homeassistant/components/mcp23017/*
homeassistant/components/media_extractor/*
homeassistant/components/mediaroom/media_player.py
homeassistant/components/message_bird/notify.py
homeassistant/components/met/weather.py
homeassistant/components/meteo_france/*
homeassistant/components/meteoalarm/*
homeassistant/components/metoffice/sensor.py
homeassistant/components/metoffice/weather.py
homeassistant/components/microsoft/tts.py
@@ -418,6 +426,7 @@ omit =
homeassistant/components/openweathermap/sensor.py
homeassistant/components/openweathermap/weather.py
homeassistant/components/opple/light.py
homeassistant/components/orangepi_gpio/*
homeassistant/components/orvibo/switch.py
homeassistant/components/osramlightify/light.py
homeassistant/components/otp/sensor.py
@@ -440,7 +449,6 @@ omit =
homeassistant/components/plum_lightpad/*
homeassistant/components/pocketcasts/sensor.py
homeassistant/components/point/*
homeassistant/components/pollen/sensor.py
homeassistant/components/postnl/sensor.py
homeassistant/components/prezzibenzina/sensor.py
homeassistant/components/proliphix/climate.py
@@ -449,6 +457,7 @@ omit =
homeassistant/components/proxy/camera.py
homeassistant/components/ps4/__init__.py
homeassistant/components/ps4/media_player.py
homeassistant/components/ptvsd/*
homeassistant/components/pulseaudio_loopback/switch.py
homeassistant/components/pushbullet/notify.py
homeassistant/components/pushbullet/sensor.py
@@ -480,6 +489,9 @@ omit =
homeassistant/components/reddit/*
homeassistant/components/rejseplanen/sensor.py
homeassistant/components/remember_the_milk/__init__.py
homeassistant/components/repetier/__init__.py
homeassistant/components/repetier/sensor.py
homeassistant/components/remote_rpi_gpio/*
homeassistant/components/rest/binary_sensor.py
homeassistant/components/rest/notify.py
homeassistant/components/rest/switch.py
@@ -532,14 +544,14 @@ omit =
homeassistant/components/slack/notify.py
homeassistant/components/sma/sensor.py
homeassistant/components/smappee/*
homeassistant/components/smarthab/*
homeassistant/components/smtp/notify.py
homeassistant/components/snapcast/media_player.py
homeassistant/components/snmp/device_tracker.py
homeassistant/components/snmp/sensor.py
homeassistant/components/snmp/switch.py
homeassistant/components/snmp/*
homeassistant/components/sochain/sensor.py
homeassistant/components/socialblade/sensor.py
homeassistant/components/solaredge/sensor.py
homeassistant/components/solax/sensor.py
homeassistant/components/somfy_mylink/*
homeassistant/components/sonarr/sensor.py
homeassistant/components/songpal/media_player.py
@@ -561,6 +573,7 @@ omit =
homeassistant/components/swiss_public_transport/sensor.py
homeassistant/components/swisscom/device_tracker.py
homeassistant/components/switchbot/switch.py
homeassistant/components/switcher_kis/switch.py
homeassistant/components/switchmate/switch.py
homeassistant/components/syncthru/sensor.py
homeassistant/components/synology/camera.py
@@ -645,6 +658,7 @@ omit =
homeassistant/components/waqi/sensor.py
homeassistant/components/waterfurnace/*
homeassistant/components/watson_iot/*
homeassistant/components/watson_tts/tts.py
homeassistant/components/waze_travel_time/sensor.py
homeassistant/components/webostv/*
homeassistant/components/wemo/*

View File

@@ -7,7 +7,7 @@
**Related issue (if applicable):** fixes #<home-assistant issue number goes here>
**Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** home-assistant/home-assistant.io#<home-assistant.io PR number goes here>
**Pull request with documentation for [home-assistant.io](https://github.com/home-assistant/home-assistant.io) (if applicable):** home-assistant/home-assistant.io#<home-assistant.io PR number goes here>
## Example entry for `configuration.yaml` (if applicable):
```yaml
@@ -18,21 +18,18 @@
- [ ] The code change is tested and works locally.
- [ ] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
- [ ] There is no commented out code in this PR.
- [ ] I have followed the [development checklist][dev-checklist]
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io)
If the code communicates with devices, web services, or third-party tools:
- [ ] [_The manifest file_][manifest-docs] has all fields filled out correctly ([example][ex-manifest]).
- [ ] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]).
- [ ] New dependencies are only imported inside functions that use them ([example][ex-import]).
- [ ] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
- [ ] New files were added to `.coveragerc`.
- [ ] [_The manifest file_][manifest-docs] has all fields filled out correctly. Update and include derived files by running `python3 -m script.hassfest`.
- [ ] New or updated dependencies have been added to `requirements_all.txt` by running `python3 -m script.gen_requirements_all`.
- [ ] Untested files have been added to `.coveragerc`.
If the code does not interact with devices:
- [ ] Tests have been added to verify that the new code works.
[ex-manifest]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json
[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json#L5
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
[manifest-docs]: https://developers.home-assistant.io/docs/en/development_checklist.html#_the-manifest-file_
[dev-checklist]: https://developers.home-assistant.io/docs/en/development_checklist.html
[manifest-docs]: https://developers.home-assistant.io/docs/en/creating_integration_manifest.html

14
.github/main.workflow vendored
View File

@@ -1,14 +0,0 @@
workflow "Mention CODEOWNERS of integrations when integration label is added to an issue" {
on = "issues"
resolves = "codeowners-mention"
}
workflow "Mention CODEOWNERS of integrations when integration label is added to an PRs" {
on = "pull_request"
resolves = "codeowners-mention"
}
action "codeowners-mention" {
uses = "home-assistant/codeowners-mention@master"
secrets = ["GITHUB_TOKEN"]
}

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
config/*
config2/*
tests/testing_config/deps
tests/testing_config/home-assistant.log
@@ -84,7 +85,7 @@ Scripts/
# vimmy stuff
*.swp
*.swo
tags
ctags.tmp
# vagrant stuff

33
.travis.yml Normal file
View File

@@ -0,0 +1,33 @@
sudo: false
dist: xenial
addons:
apt:
sources:
- sourceline: "ppa:jonathonf/ffmpeg-4"
packages:
- libudev-dev
- libavformat-dev
- libavcodec-dev
- libavdevice-dev
- libavutil-dev
- libswscale-dev
- libswresample-dev
- libavfilter-dev
matrix:
fast_finish: true
include:
- python: "3.5.3"
env: TOXENV=lint
- python: "3.5.3"
env: TOXENV=pylint
- python: "3.5.3"
env: TOXENV=typing
- python: "3.5.3"
env: TOXENV=py35
- python: "3.7"
env: TOXENV=py37
cache: pip
install: pip install -U tox
language: python
script: travis_wait 40 tox --develop

View File

@@ -21,6 +21,7 @@ homeassistant/components/airvisual/* @bachya
homeassistant/components/alarm_control_panel/* @colinodell
homeassistant/components/alpha_vantage/* @fabaff
homeassistant/components/amazon_polly/* @robbiet480
homeassistant/components/ambiclimate/* @danielhiversen
homeassistant/components/ambient_station/* @bachya
homeassistant/components/api/* @home-assistant/core
homeassistant/components/arduino/* @fabaff
@@ -31,7 +32,9 @@ homeassistant/components/automatic/* @armills
homeassistant/components/automation/* @home-assistant/core
homeassistant/components/aws/* @awarecan @robbiet480
homeassistant/components/axis/* @kane610
homeassistant/components/azure_event_hub/* @eavanvalkenburg
homeassistant/components/bitcoin/* @fabaff
homeassistant/components/bizkaibus/* @UgaitzEtxebarria
homeassistant/components/blink/* @fronzbot
homeassistant/components/bmw_connected_drive/* @ChristianKuehnel
homeassistant/components/braviatv/* @robbiet480
@@ -66,10 +69,13 @@ homeassistant/components/egardia/* @jeroenterheerdt
homeassistant/components/eight_sleep/* @mezz64
homeassistant/components/emby/* @mezz64
homeassistant/components/enigma2/* @fbradyirl
homeassistant/components/enocean/* @bdurrer
homeassistant/components/ephember/* @ttroy50
homeassistant/components/epsonworkforce/* @ThaStealth
homeassistant/components/eq3btsmart/* @rytilahti
homeassistant/components/esphome/* @OttoWinter
homeassistant/components/essent/* @TheLastProject
homeassistant/components/evohome/* @zxdavb
homeassistant/components/file/* @fabaff
homeassistant/components/filter/* @dgomes
homeassistant/components/fitbit/* @robbiet480
@@ -78,8 +84,9 @@ homeassistant/components/flock/* @fabaff
homeassistant/components/flunearyou/* @bachya
homeassistant/components/foursquare/* @robbiet480
homeassistant/components/freebox/* @snoof85
homeassistant/components/frontend/* @home-assistant/core
homeassistant/components/frontend/* @home-assistant/frontend
homeassistant/components/gearbest/* @HerrHofrat
homeassistant/components/geniushub/* @zxdavb
homeassistant/components/gitter/* @fabaff
homeassistant/components/glances/* @fabaff
homeassistant/components/gntp/* @robbiet480
@@ -99,6 +106,7 @@ homeassistant/components/history_graph/* @andrey-git
homeassistant/components/hive/* @Rendili @KJonline
homeassistant/components/homeassistant/* @home-assistant/core
homeassistant/components/homekit/* @cdce8p
homeassistant/components/homekit_controller/* @Jc2k
homeassistant/components/homematic/* @pvizeli @danielperna84
homeassistant/components/html5/* @robbiet480
homeassistant/components/http/* @home-assistant/core
@@ -106,6 +114,7 @@ homeassistant/components/huawei_lte/* @scop
homeassistant/components/huawei_router/* @abmantis
homeassistant/components/hue/* @balloob
homeassistant/components/ign_sismologia/* @exxamalte
homeassistant/components/incomfort/* @zxdavb
homeassistant/components/influxdb/* @fabaff
homeassistant/components/input_boolean/* @home-assistant/core
homeassistant/components/input_datetime/* @home-assistant/core
@@ -115,6 +124,7 @@ homeassistant/components/input_text/* @home-assistant/core
homeassistant/components/integration/* @dgomes
homeassistant/components/ios/* @robbiet480
homeassistant/components/ipma/* @dgomes
homeassistant/components/iqvia/* @bachya
homeassistant/components/irish_rail_transport/* @ttroy50
homeassistant/components/jewish_calendar/* @tsvi
homeassistant/components/knx/* @Julius2342
@@ -122,6 +132,7 @@ homeassistant/components/kodi/* @armills
homeassistant/components/konnected/* @heythisisnate
homeassistant/components/lametric/* @robbiet480
homeassistant/components/launch_library/* @ludeeus
homeassistant/components/lcn/* @alengwenus
homeassistant/components/lifx/* @amelchio
homeassistant/components/lifx_cloud/* @amelchio
homeassistant/components/lifx_legacy/* @amelchio
@@ -129,14 +140,16 @@ homeassistant/components/linux_battery/* @fabaff
homeassistant/components/liveboxplaytv/* @pschmitt
homeassistant/components/logger/* @home-assistant/core
homeassistant/components/logi_circle/* @evanjd
homeassistant/components/lovelace/* @home-assistant/core
homeassistant/components/lovelace/* @home-assistant/frontend
homeassistant/components/luci/* @fbradyirl
homeassistant/components/luftdaten/* @fabaff
homeassistant/components/mastodon/* @fabaff
homeassistant/components/matrix/* @tinloaf
homeassistant/components/mcp23017/* @jardiamj
homeassistant/components/mediaroom/* @dgomes
homeassistant/components/melissa/* @kennedyshead
homeassistant/components/met/* @danielhiversen
homeassistant/components/meteoalarm/* @rolfberkenbosch
homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel
homeassistant/components/mill/* @danielhiversen
homeassistant/components/min_max/* @fabaff
@@ -150,24 +163,28 @@ homeassistant/components/nello/* @pschmitt
homeassistant/components/ness_alarm/* @nickw444
homeassistant/components/nest/* @awarecan
homeassistant/components/netdata/* @fabaff
homeassistant/components/nextbus/* @vividboarder
homeassistant/components/nissan_leaf/* @filcole
homeassistant/components/nmbs/* @thibmaek
homeassistant/components/no_ip/* @fabaff
homeassistant/components/notify/* @flowolf
homeassistant/components/notify/* @home-assistant/core
homeassistant/components/nsw_fuel_station/* @nickw444
homeassistant/components/nuki/* @pschmitt
homeassistant/components/ohmconnect/* @robbiet480
homeassistant/components/onboarding/* @home-assistant/core
homeassistant/components/openuv/* @bachya
homeassistant/components/openweathermap/* @fabaff
homeassistant/components/orangepi_gpio/* @pascallj
homeassistant/components/owlet/* @oblogic7
homeassistant/components/panel_custom/* @home-assistant/core
homeassistant/components/panel_iframe/* @home-assistant/core
homeassistant/components/panel_custom/* @home-assistant/frontend
homeassistant/components/panel_iframe/* @home-assistant/frontend
homeassistant/components/persistent_notification/* @home-assistant/core
homeassistant/components/philips_js/* @elupus
homeassistant/components/pi_hole/* @fabaff
homeassistant/components/plant/* @ChristianKuehnel
homeassistant/components/point/* @fredrike
homeassistant/components/pollen/* @bachya
homeassistant/components/ps4/* @ktnrg45
homeassistant/components/ptvsd/* @swamp-ig
homeassistant/components/push/* @dgomes
homeassistant/components/pvoutput/* @fabaff
homeassistant/components/qnap/* @colinodell
@@ -176,6 +193,7 @@ homeassistant/components/qwikswitch/* @kellerza
homeassistant/components/raincloud/* @vanstinator
homeassistant/components/rainmachine/* @bachya
homeassistant/components/random/* @fabaff
homeassistant/components/repetier/* @MTrab
homeassistant/components/rfxtrx/* @danielhiversen
homeassistant/components/rmvtransport/* @cgtobi
homeassistant/components/roomba/* @pschmitt
@@ -191,20 +209,24 @@ homeassistant/components/shiftr/* @fabaff
homeassistant/components/shodan/* @fabaff
homeassistant/components/simplisafe/* @bachya
homeassistant/components/sma/* @kellerza
homeassistant/components/smarthab/* @outadoc
homeassistant/components/smartthings/* @andrewsayre
homeassistant/components/smtp/* @fabaff
homeassistant/components/solax/* @squishykid
homeassistant/components/sonos/* @amelchio
homeassistant/components/spaceapi/* @fabaff
homeassistant/components/spider/* @peternijssen
homeassistant/components/sql/* @dgomes
homeassistant/components/statistics/* @fabaff
homeassistant/components/stiebel_eltron/* @fucm
homeassistant/components/sun/* @home-assistant/core
homeassistant/components/sun/* @Swamp-Ig
homeassistant/components/supla/* @mwegrzynek
homeassistant/components/swiss_hydrological_data/* @fabaff
homeassistant/components/swiss_public_transport/* @fabaff
homeassistant/components/switchbot/* @danielhiversen
homeassistant/components/switcher_kis/* @tomerfi
homeassistant/components/switchmate/* @danielhiversen
homeassistant/components/syncthru/* @nielstron
homeassistant/components/synology_srm/* @aerialls
homeassistant/components/syslog/* @fabaff
homeassistant/components/sytadin/* @gautric
@@ -235,7 +257,9 @@ homeassistant/components/uptimerobot/* @ludeeus
homeassistant/components/utility_meter/* @dgomes
homeassistant/components/velux/* @Julius2342
homeassistant/components/version/* @fabaff
homeassistant/components/vizio/* @raman325
homeassistant/components/waqi/* @andrey-git
homeassistant/components/watson_tts/* @rutkai
homeassistant/components/weather/* @fabaff
homeassistant/components/weblink/* @home-assistant/core
homeassistant/components/websocket_api/* @home-assistant/core
@@ -244,14 +268,14 @@ homeassistant/components/worldclock/* @fabaff
homeassistant/components/xfinity/* @cisasteelersfan
homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi
homeassistant/components/xiaomi_miio/* @rytilahti @syssi
homeassistant/components/xiaomi_tv/* @fattdev
homeassistant/components/xmpp/* @fabaff
homeassistant/components/xiaomi_tv/* @simse
homeassistant/components/xmpp/* @fabaff @flowolf
homeassistant/components/yamaha_musiccast/* @jalmeroth
homeassistant/components/yeelight/* @rytilahti @zewelor
homeassistant/components/yeelightsunflower/* @lindsaymarkward
homeassistant/components/yessssms/* @flowolf
homeassistant/components/yi/* @bachya
homeassistant/components/zeroconf/* @robbiet480
homeassistant/components/zeroconf/* @robbiet480 @Kane610
homeassistant/components/zha/* @dmulcahey @adminiuga
homeassistant/components/zone/* @home-assistant/core
homeassistant/components/zoneminder/* @rohankapoorcom

View File

@@ -1,4 +1,4 @@
Home Assistant |Build Status| |CI Status| |Coverage Status| |Chat Status|
Home Assistant |Chat Status|
=================================================================================
Home Assistant is a home automation platform running on Python 3. It is able to track and control all devices at home and offer a platform for automating control.
@@ -27,12 +27,6 @@ components <https://developers.home-assistant.io/docs/en/creating_component_inde
If you run into issues while using Home Assistant or during development
of a component, check the `Home Assistant help section <https://home-assistant.io/help/>`__ of our website for further help and information.
.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=dev
:target: https://travis-ci.org/home-assistant/home-assistant
.. |CI Status| image:: https://circleci.com/gh/home-assistant/home-assistant.svg?style=shield
:target: https://circleci.com/gh/home-assistant/home-assistant
.. |Coverage Status| image:: https://img.shields.io/coveralls/home-assistant/home-assistant.svg
:target: https://coveralls.io/r/home-assistant/home-assistant?branch=master
.. |Chat Status| image:: https://img.shields.io/discord/330944238910963714.svg
:target: https://discord.gg/c5DvZ4e
.. |screenshot-states| image:: https://raw.github.com/home-assistant/home-assistant/master/docs/screenshots.png

210
azure-pipelines.yml Normal file
View File

@@ -0,0 +1,210 @@
# https://dev.azure.com/home-assistant
trigger:
batch: true
branches:
include:
- dev
tags:
include:
- '*'
variables:
- name: versionBuilder
value: '3.2'
- name: versionWheels
value: '0.3'
- group: docker
- group: wheels
- group: github
jobs:
- job: 'Wheels'
condition: eq(variables['Build.SourceBranchName'], 'dev')
timeoutInMinutes: 360
pool:
vmImage: 'ubuntu-16.04'
strategy:
maxParallel: 3
matrix:
amd64:
buildArch: 'amd64'
i386:
buildArch: 'i386'
armhf:
buildArch: 'armhf'
armv7:
buildArch: 'armv7'
aarch64:
buildArch: 'aarch64'
steps:
- script: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
qemu-user-static \
binfmt-support
sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
sudo update-binfmts --enable qemu-arm
sudo update-binfmts --enable qemu-aarch64
displayName: 'Initial cross build'
- script: |
mkdir -p .ssh
echo -e "-----BEGIN RSA PRIVATE KEY-----\n$(wheelsSSH)\n-----END RSA PRIVATE KEY-----" >> .ssh/id_rsa
ssh-keyscan -H $(wheelsHost) >> .ssh/known_hosts
chmod 600 .ssh/*
displayName: 'Install ssh key'
- script: sudo docker pull homeassistant/$(buildArch)-wheels:$(versionWheels)
displayName: 'Install wheels builder'
- script: |
cp requirements_all.txt requirements_hassio.txt
# Enable because we can build it
sed -i "s|# pytradfri|pytradfri|g" requirements_hassio.txt
sed -i "s|# pybluez|pybluez|g" requirements_hassio.txt
sed -i "s|# bluepy|bluepy|g" requirements_hassio.txt
sed -i "s|# beacontools|beacontools|g" requirements_hassio.txt
sed -i "s|# RPi.GPIO|RPi.GPIO|g" requirements_hassio.txt
sed -i "s|# raspihats|raspihats|g" requirements_hassio.txt
sed -i "s|# rpi-rf|rpi-rf|g" requirements_hassio.txt
sed -i "s|# blinkt|blinkt|g" requirements_hassio.txt
sed -i "s|# fritzconnection|fritzconnection|g" requirements_hassio.txt
sed -i "s|# pyuserinput|pyuserinput|g" requirements_hassio.txt
sed -i "s|# evdev|evdev|g" requirements_hassio.txt
sed -i "s|# smbus-cffi|smbus-cffi|g" requirements_hassio.txt
sed -i "s|# i2csense|i2csense|g" requirements_hassio.txt
sed -i "s|# python-eq3bt|python-eq3bt|g" requirements_hassio.txt
sed -i "s|# pycups|pycups|g" requirements_hassio.txt
sed -i "s|# homekit|homekit|g" requirements_hassio.txt
sed -i "s|# decora_wifi|decora_wifi|g" requirements_hassio.txt
sed -i "s|# decora|decora|g" requirements_hassio.txt
sed -i "s|# PySwitchbot|PySwitchbot|g" requirements_hassio.txt
sed -i "s|# pySwitchmate|pySwitchmate|g" requirements_hassio.txt
# Disable because of error
sed -i "s|insteonplm|# insteonplm|g" requirements_hassio.txt
displayName: 'Prepare requirements files for Hass.io'
- script: |
sudo docker run --rm -v $(pwd):/data:ro -v $(pwd)/.ssh:/root/.ssh:rw \
homeassistant/$(buildArch)-wheels:$(versionWheels) \
--apk "build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;linux-headers;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev" \
--index https://wheels.hass.io \
--requirement requirements_hassio.txt \
--upload rsync \
--remote wheels@$(wheelsHost):/opt/wheels
displayName: 'Run wheels build'
- job: 'VersionValidate'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python 3.7'
inputs:
versionSpec: '3.7'
- script: |
setup_version="$(python setup.py -V)"
branch_version="$(Build.SourceBranchName)"
if [ "${setup_version}" != "${branch_version}" ]; then
echo "Version of tag ${branch_version} don't match with ${setup_version}!"
exit 1
fi
displayName: 'Check version of branch/tag'
- job: 'Release'
condition: and(startsWith(variables['Build.SourceBranch'], 'refs/tags'), succeeded('VersionValidate'))
dependsOn:
- 'VersionValidate'
timeoutInMinutes: 120
pool:
vmImage: 'ubuntu-16.04'
strategy:
maxParallel: 5
matrix:
amd64:
buildArch: 'amd64'
buildMachine: 'qemux86-64,intel-nuc'
i386:
buildArch: 'i386'
buildMachine: 'qemux86'
armhf:
buildArch: 'armhf'
buildMachine: 'qemuarm,raspberrypi'
armv7:
buildArch: 'armv7'
buildMachine: 'raspberrypi2,raspberrypi3,odroid-xu,tinker'
aarch64:
buildArch: 'aarch64'
buildMachine: 'qemuarm-64,raspberrypi3-64,odroid-c2,orangepi-prime'
steps:
- script: sudo docker login -u $(dockerUser) -p $(dockerPassword)
displayName: 'Docker hub login'
- script: sudo docker pull homeassistant/amd64-builder:$(versionBuilder)
displayName: 'Install Builder'
- script: |
set -e
sudo docker run --rm --privileged \
-v ~/.docker:/root/.docker \
-v /run/docker.sock:/run/docker.sock:rw \
homeassistant/amd64-builder:$(versionBuilder) \
--homeassistant $(Build.SourceBranchName) "--$(buildArch)" \
-r https://github.com/home-assistant/hassio-homeassistant \
-t generic --docker-hub homeassistant
sudo docker run --rm --privileged \
-v ~/.docker:/root/.docker \
-v /run/docker.sock:/run/docker.sock:rw \
homeassistant/amd64-builder:$(versionBuilder) \
--homeassistant-machine "$(Build.SourceBranchName)=$(buildMachine)" \
-r https://github.com/home-assistant/hassio-homeassistant \
-t machine --docker-hub homeassistant
displayName: 'Build Release'
- job: 'ReleasePublish'
condition: and(startsWith(variables['Build.SourceBranch'], 'refs/tags'), succeeded('Release'))
dependsOn:
- 'Release'
pool:
vmImage: 'ubuntu-16.04'
steps:
- script: |
sudo apt-get install -y --no-install-recommends \
git jq
git config --global user.name "Pascal Vizeli"
git config --global user.email "pvizeli@syshack.ch"
git config --global credential.helper store
echo "https://$(githubToken):x-oauth-basic@github.com" > $HOME/.git-credentials
displayName: 'Install requirements'
- script: |
set -e
version="$(Build.SourceBranchName)"
git clone https://github.com/home-assistant/hassio-version
cd hassio-version
dev_version="$(jq --raw-output '.homeassistant.default' dev.json)"
beta_version="$(jq --raw-output '.homeassistant.default' beta.json)"
stable_version="$(jq --raw-output '.homeassistant.default' stable.json)"
if [[ "$version" =~ b ]]; then
sed -i "s|$dev_version|$version|g" dev.json
sed -i "s|$beta_version|$version|g" beta.json
else
sed -i "s|$dev_version|$version|g" dev.json
sed -i "s|$beta_version|$version|g" beta.json
sed -i "s|$stable_version|$version|g" stable.json
fi
git commit -am "Bump Home Assistant $version"
git push
displayName: 'Update version files'

View File

@@ -7,8 +7,9 @@ import platform
import subprocess
import sys
import threading
from typing import List, Dict, Any # noqa pylint: disable=unused-import
from typing import ( # noqa pylint: disable=unused-import
List, Dict, Any, TYPE_CHECKING
)
from homeassistant import monkey_patch
from homeassistant.const import (
@@ -18,6 +19,9 @@ from homeassistant.const import (
RESTART_EXIT_CODE,
)
if TYPE_CHECKING:
from homeassistant import core
def set_loop() -> None:
"""Attempt to use uvloop."""
@@ -86,10 +90,12 @@ def ensure_config_path(config_dir: str) -> None:
sys.exit(1)
def ensure_config_file(config_dir: str) -> str:
async def ensure_config_file(hass: 'core.HomeAssistant', config_dir: str) \
-> str:
"""Ensure configuration file exists."""
import homeassistant.config as config_util
config_path = config_util.ensure_config_exists(config_dir)
config_path = await config_util.async_ensure_config_exists(
hass, config_dir)
if config_path is None:
print('Error getting configuration path')
@@ -261,6 +267,7 @@ def cmdline() -> List[str]:
async def setup_and_run_hass(config_dir: str,
args: argparse.Namespace) -> int:
"""Set up HASS and run."""
# pylint: disable=redefined-outer-name
from homeassistant import bootstrap, core
hass = core.HomeAssistant()
@@ -275,7 +282,7 @@ async def setup_and_run_hass(config_dir: str,
skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days,
log_file=args.log_file, log_no_color=args.log_no_color)
else:
config_file = ensure_config_file(config_dir)
config_file = await ensure_config_file(hass, config_dir)
print('Config directory:', config_dir)
await bootstrap.async_from_config_file(
config_file, hass, verbose=args.verbose, skip_pip=args.skip_pip,
@@ -390,7 +397,7 @@ def main() -> int:
if exit_code == RESTART_EXIT_CODE and not args.runner:
try_to_restart()
return exit_code # type: ignore # mypy cannot yet infer it
return exit_code # type: ignore
if __name__ == "__main__":

View File

@@ -18,7 +18,7 @@ from homeassistant.helpers import config_validation as cv
from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \
MULTI_FACTOR_AUTH_MODULE_SCHEMA, SetupFlow
REQUIREMENTS = ['pyotp==2.2.6']
REQUIREMENTS = ['pyotp==2.2.7']
CONF_MESSAGE = 'message'

View File

@@ -12,7 +12,7 @@ from homeassistant.core import HomeAssistant
from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \
MULTI_FACTOR_AUTH_MODULE_SCHEMA, SetupFlow
REQUIREMENTS = ['pyotp==2.2.6', 'PyQRCode==1.2.1']
REQUIREMENTS = ['pyotp==2.2.7', 'PyQRCode==1.2.1']
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({
}, extra=vol.PREVENT_EXTRA)

View File

@@ -11,6 +11,7 @@ from .models import PermissionLookup
from .types import PolicyType
from .entities import ENTITY_POLICY_SCHEMA, compile_entities
from .merge import merge_policies # noqa
from .util import test_all
POLICY_SCHEMA = vol.Schema({
@@ -29,6 +30,10 @@ class AbstractPermissions:
"""Return a function that can test entity access."""
raise NotImplementedError
def access_all_entities(self, key: str) -> bool:
"""Check if we have a certain access to all entities."""
raise NotImplementedError
def check_entity(self, entity_id: str, key: str) -> bool:
"""Check if we can access entity."""
entity_func = self._cached_entity_func
@@ -48,6 +53,10 @@ class PolicyPermissions(AbstractPermissions):
self._policy = policy
self._perm_lookup = perm_lookup
def access_all_entities(self, key: str) -> bool:
"""Check if we have a certain access to all entities."""
return test_all(self._policy.get(CAT_ENTITIES), key)
def _entity_func(self) -> Callable[[str, str], bool]:
"""Return a function that can test entity access."""
return compile_entities(self._policy.get(CAT_ENTITIES),
@@ -65,6 +74,10 @@ class _OwnerPermissions(AbstractPermissions):
# pylint: disable=no-self-use
def access_all_entities(self, key: str) -> bool:
"""Check if we have a certain access to all entities."""
return True
def _entity_func(self) -> Callable[[str, str], bool]:
"""Return a function that can test entity access."""
return lambda entity_id, key: True

View File

@@ -3,6 +3,7 @@ from functools import wraps
from typing import Callable, Dict, List, Optional, Union, cast # noqa: F401
from .const import SUBCAT_ALL
from .models import PermissionLookup
from .types import CategoryType, SubCategoryDict, ValueType
@@ -96,3 +97,16 @@ def _gen_dict_test_func(
return schema.get(key)
return test_value
def test_all(policy: CategoryType, key: str) -> bool:
"""Test if a policy has an ALL access for a specific key."""
if not isinstance(policy, dict):
return bool(policy)
all_policy = policy.get(SUBCAT_ALL)
if not isinstance(all_policy, dict):
return bool(all_policy)
return all_policy.get(key, False)

View File

@@ -26,6 +26,7 @@ ERROR_LOG_FILENAME = 'home-assistant.log'
# hass.data key for logging information.
DATA_LOGGING = 'logging'
DEBUGGER_INTEGRATIONS = {'ptvsd', }
CORE_INTEGRATIONS = ('homeassistant', 'persistent_notification')
LOGGING_INTEGRATIONS = {'logger', 'system_log'}
STAGE_1_INTEGRATIONS = {
@@ -93,6 +94,13 @@ async def async_from_config_dict(config: Dict[str, Any],
stop = time()
_LOGGER.info("Home Assistant initialized in %.2fs", stop-start)
if sys.version_info[:3] < (3, 6, 0):
hass.components.persistent_notification.async_create(
"Python 3.5 support is deprecated and will "
"be removed in the first release after August 1. Please "
"upgrade Python.", "Python version", "python_version"
)
# TEMP: warn users for invalid slugs
# Remove after 0.94 or 1.0
if cv.INVALID_SLUGS_FOUND or cv.INVALID_ENTITY_IDS_FOUND:
@@ -306,6 +314,15 @@ async def _async_set_up_integrations(
"""Set up all the integrations."""
domains = _get_domains(hass, config)
# Start up debuggers. Start these first in case they want to wait.
debuggers = domains & DEBUGGER_INTEGRATIONS
if debuggers:
_LOGGER.debug("Starting up debuggers %s", debuggers)
await asyncio.gather(*[
async_setup_component(hass, domain, config)
for domain in debuggers])
domains -= DEBUGGER_INTEGRATIONS
# Resolve all dependencies of all components so we can find the logging
# and integrations that need faster initialization.
resolved_domains_task = asyncio.gather(*[
@@ -339,7 +356,7 @@ async def _async_set_up_integrations(
stage_2_domains = domains - logging_domains - stage_1_domains
if logging_domains:
_LOGGER.debug("Setting up %s", logging_domains)
_LOGGER.info("Setting up %s", logging_domains)
await asyncio.gather(*[
async_setup_component(hass, domain, config)

View File

@@ -31,9 +31,11 @@ CONF_ADS_TYPE = 'adstype'
CONF_ADS_VALUE = 'value'
CONF_ADS_VAR = 'adsvar'
CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness'
CONF_ADS_VAR_POSITION = 'adsvar_position'
STATE_KEY_STATE = 'state'
STATE_KEY_BRIGHTNESS = 'brightness'
STATE_KEY_POSITION = 'position'
DOMAIN = 'ads'

View File

@@ -0,0 +1,165 @@
"""Support for ADS covers."""
import logging
import voluptuous as vol
from homeassistant.components.cover import (
PLATFORM_SCHEMA, SUPPORT_OPEN, SUPPORT_CLOSE, SUPPORT_STOP,
SUPPORT_SET_POSITION, ATTR_POSITION, DEVICE_CLASSES_SCHEMA,
CoverDevice)
from homeassistant.const import (
CONF_NAME, CONF_DEVICE_CLASS)
import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, CONF_ADS_VAR_POSITION, DATA_ADS, \
AdsEntity, STATE_KEY_STATE, STATE_KEY_POSITION
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'ADS Cover'
CONF_ADS_VAR_SET_POS = 'adsvar_set_position'
CONF_ADS_VAR_OPEN = 'adsvar_open'
CONF_ADS_VAR_CLOSE = 'adsvar_close'
CONF_ADS_VAR_STOP = 'adsvar_stop'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_ADS_VAR_POSITION): cv.string,
vol.Optional(CONF_ADS_VAR_SET_POS): cv.string,
vol.Optional(CONF_ADS_VAR_CLOSE): cv.string,
vol.Optional(CONF_ADS_VAR_OPEN): cv.string,
vol.Optional(CONF_ADS_VAR_STOP): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the cover platform for ADS."""
ads_hub = hass.data[DATA_ADS]
ads_var_is_closed = config.get(CONF_ADS_VAR)
ads_var_position = config.get(CONF_ADS_VAR_POSITION)
ads_var_pos_set = config.get(CONF_ADS_VAR_SET_POS)
ads_var_open = config.get(CONF_ADS_VAR_OPEN)
ads_var_close = config.get(CONF_ADS_VAR_CLOSE)
ads_var_stop = config.get(CONF_ADS_VAR_STOP)
name = config[CONF_NAME]
device_class = config.get(CONF_DEVICE_CLASS)
add_entities([AdsCover(ads_hub,
ads_var_is_closed,
ads_var_position,
ads_var_pos_set,
ads_var_open,
ads_var_close,
ads_var_stop,
name,
device_class)])
class AdsCover(AdsEntity, CoverDevice):
"""Representation of ADS cover."""
def __init__(self, ads_hub,
ads_var_is_closed, ads_var_position,
ads_var_pos_set, ads_var_open,
ads_var_close, ads_var_stop, name, device_class):
"""Initialize AdsCover entity."""
super().__init__(ads_hub, name, ads_var_is_closed)
if self._ads_var is None:
if ads_var_position is not None:
self._unique_id = ads_var_position
elif ads_var_pos_set is not None:
self._unique_id = ads_var_pos_set
elif ads_var_open is not None:
self._unique_id = ads_var_open
self._state_dict[STATE_KEY_POSITION] = None
self._ads_var_position = ads_var_position
self._ads_var_pos_set = ads_var_pos_set
self._ads_var_open = ads_var_open
self._ads_var_close = ads_var_close
self._ads_var_stop = ads_var_stop
self._device_class = device_class
async def async_added_to_hass(self):
"""Register device notification."""
if self._ads_var is not None:
await self.async_initialize_device(self._ads_var,
self._ads_hub.PLCTYPE_BOOL)
if self._ads_var_position is not None:
await self.async_initialize_device(self._ads_var_position,
self._ads_hub.PLCTYPE_BYTE,
STATE_KEY_POSITION)
@property
def device_class(self):
"""Return the class of this cover."""
return self._device_class
@property
def is_closed(self):
"""Return if the cover is closed."""
if self._ads_var is not None:
return self._state_dict[STATE_KEY_STATE]
if self._ads_var_position is not None:
return self._state_dict[STATE_KEY_POSITION] == 0
return None
@property
def current_cover_position(self):
"""Return current position of cover."""
return self._state_dict[STATE_KEY_POSITION]
@property
def supported_features(self):
"""Flag supported features."""
supported_features = SUPPORT_OPEN | SUPPORT_CLOSE
if self._ads_var_stop is not None:
supported_features |= SUPPORT_STOP
if self._ads_var_pos_set is not None:
supported_features |= SUPPORT_SET_POSITION
return supported_features
def stop_cover(self, **kwargs):
"""Fire the stop action."""
if self._ads_var_stop:
self._ads_hub.write_by_name(self._ads_var_stop, True,
self._ads_hub.PLCTYPE_BOOL)
def set_cover_position(self, **kwargs):
"""Set cover position."""
position = kwargs[ATTR_POSITION]
if self._ads_var_pos_set is not None:
self._ads_hub.write_by_name(self._ads_var_pos_set, position,
self._ads_hub.PLCTYPE_BYTE)
def open_cover(self, **kwargs):
"""Move the cover up."""
if self._ads_var_open is not None:
self._ads_hub.write_by_name(self._ads_var_open, True,
self._ads_hub.PLCTYPE_BOOL)
elif self._ads_var_pos_set is not None:
self.set_cover_position(position=100)
def close_cover(self, **kwargs):
"""Move the cover down."""
if self._ads_var_close is not None:
self._ads_hub.write_by_name(self._ads_var_close, True,
self._ads_hub.PLCTYPE_BOOL)
elif self._ads_var_pos_set is not None:
self.set_cover_position(position=0)
@property
def available(self):
"""Return False if state has not been updated yet."""
if self._ads_var is not None or self._ads_var_position is not None:
return self._state_dict[STATE_KEY_STATE] is not None or \
self._state_dict[STATE_KEY_POSITION] is not None
return True

View File

@@ -1,7 +1,7 @@
"""Support for repeating alerts when conditions are met."""
import asyncio
import logging
from datetime import datetime, timedelta
from datetime import timedelta
import voluptuous as vol
@@ -13,6 +13,7 @@ from homeassistant.const import (
SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE, ATTR_ENTITY_ID)
from homeassistant.helpers import service, event
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.util.dt import now
_LOGGER = logging.getLogger(__name__)
@@ -117,7 +118,7 @@ async def async_setup(hass, config):
tasks = [alert.async_update_ha_state() for alert in entities]
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks)
return True
@@ -222,7 +223,7 @@ class Alert(ToggleEntity):
async def _schedule_notify(self):
"""Schedule a notification."""
delay = self._delay[self._next_delay]
next_msg = datetime.now() + delay
next_msg = now() + delay
self._cancel = \
event.async_track_point_in_time(self.hass, self._notify, next_msg)
self._next_delay = min(self._next_delay + 1, len(self._delay) - 1)

View File

@@ -39,7 +39,7 @@ class Auth:
self._prefs = None
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._get_token_lock = asyncio.Lock(loop=hass.loop)
self._get_token_lock = asyncio.Lock()
async def async_do_auth(self, accept_grant_code):
"""Do authentication with an AcceptGrant code."""
@@ -97,7 +97,7 @@ class Auth:
try:
session = aiohttp_client.async_get_clientsession(self.hass)
with async_timeout.timeout(DEFAULT_TIMEOUT, loop=self.hass.loop):
with async_timeout.timeout(DEFAULT_TIMEOUT):
response = await session.post(LWA_TOKEN_URI,
headers=LWA_HEADERS,
data=lwa_params,

View File

@@ -449,9 +449,9 @@ class _AlexaPowerController(_AlexaInterface):
if name != 'powerState':
raise _UnsupportedProperty(name)
if self.entity.state == STATE_ON:
return 'ON'
return 'OFF'
if self.entity.state == STATE_OFF:
return 'OFF'
return 'ON'
class _AlexaLockController(_AlexaInterface):
@@ -911,13 +911,17 @@ class _MediaPlayerCapabilities(_AlexaEntity):
return [_DisplayCategory.TV]
def interfaces(self):
yield _AlexaPowerController(self.entity)
yield _AlexaEndpointHealth(self.hass, self.entity)
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported & media_player.const.SUPPORT_VOLUME_SET:
yield _AlexaSpeaker(self.entity)
power_features = (media_player.SUPPORT_TURN_ON |
media_player.SUPPORT_TURN_OFF)
if supported & power_features:
yield _AlexaPowerController(self.entity)
step_volume_features = (media_player.const.SUPPORT_VOLUME_MUTE |
media_player.const.SUPPORT_VOLUME_STEP)
if supported & step_volume_features:
@@ -1428,7 +1432,7 @@ async def async_send_changereport_message(hass, config, alexa_entity):
try:
session = aiohttp_client.async_get_clientsession(hass)
with async_timeout.timeout(DEFAULT_TIMEOUT, loop=hass.loop):
with async_timeout.timeout(DEFAULT_TIMEOUT):
response = await session.post(config.endpoint,
headers=headers,
json=message_serialized,

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "S'ha produ\u00eft un error desconegut al generat un testimoni d'acc\u00e9s.",
"already_setup": "El compte d\u2019Ambi Climate est\u00e0 configurat.",
"no_config": "Necessites configurar Ambi Climate abans de poder autenticar-t'hi. Llegeix les [instruccions](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Autenticaci\u00f3 exitosa amb Ambi Climate."
},
"error": {
"follow_link": "V\u00e9s a l'enlla\u00e7 i autentica't abans de pr\u00e9mer Envia",
"no_token": "No autenticat amb Ambi Climate"
},
"step": {
"auth": {
"description": "V\u00e9s a l'[enlla\u00e7]({authorization_url}) i <b>Permet</b> l'acc\u00e9s al teu compte de Ambi Climate, despr\u00e9s torna i prem <b>Envia</b> (a sota).\n(Assegura't que l'enlla\u00e7 de retorn \u00e9s el seg\u00fcent {cb_url})",
"title": "Autenticaci\u00f3 amb Ambi Climate"
}
},
"title": "Ambi Climate"
}
}

View File

@@ -0,0 +1,15 @@
{
"config": {
"error": {
"follow_link": "N\u00e1sledujte odkaz a prove\u010fte ov\u011b\u0159en\u00ed p\u0159ed stisknut\u00edm tla\u010d\u00edtka Odeslat.",
"no_token": "Nen\u00ed ov\u011b\u0159en s Ambiclimate"
},
"step": {
"auth": {
"description": "N\u00e1sledujte tento [odkaz]({authorization_url}) a <b> Povolit </b> p\u0159\u00edstup k va\u0161emu \u00fa\u010dtu Ambiclimate, pot\u00e9 se vra\u0165te a stiskn\u011bte <b> Odeslat </b> n\u00ed\u017ee. \n (Ujist\u011bte se, \u017ee zadan\u00e1 adresa URL zp\u011btn\u00e9ho vol\u00e1n\u00ed je {cb_url} )",
"title": "Ov\u011b\u0159it Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Unbekannter Fehler beim Generieren eines Zugriffstokens.",
"already_setup": "Das Ambiclimate Konto ist konfiguriert.",
"no_config": "Ambiclimate muss konfiguriert sein, bevor die Authentifizierund durchgef\u00fchrt werden kann. [Bitte lies die Anleitung] (https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Erfolgreiche Authentifizierung mit Ambiclimate"
},
"error": {
"follow_link": "Bitte folge dem Link und authentifizieren dich, bevor du auf Senden klickst",
"no_token": "Nicht authentifiziert mit Ambiclimate"
},
"step": {
"auth": {
"description": "Bitte folge diesem [link] ({authorization_url}) und <b> Erlaube </b> Zugriff auf dein Ambiclimate-Konto, komme dann zur\u00fcck und dr\u00fccke <b> Senden </b> darunter.\n (Pr\u00fcfe, dass die Callback-URL {cb_url} ist.)",
"title": "Ambiclimate authentifizieren"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Unknown error generating an access token.",
"already_setup": "The Ambiclimate account is configured.",
"no_config": "You need to configure Ambiclimate before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Successfully authenticated with Ambiclimate"
},
"error": {
"follow_link": "Please follow the link and authenticate before pressing Submit",
"no_token": "Not authenticated with Ambiclimate"
},
"step": {
"auth": {
"description": "Please follow this [link]({authorization_url}) and <b>Allow</b> access to your Ambiclimate account, then come back and press <b>Submit</b> below.\n(Make sure the specified callback url is {cb_url})",
"title": "Authenticate Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Error desconocido al generar un token de acceso.",
"already_setup": "La cuenta de Ambiclimate est\u00e1 configurada.",
"no_config": "Es necesario configurar Ambiclimate antes de poder autenticarse con \u00e9l. [Por favor, lee las instrucciones](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Autenticado correctamente con Ambiclimate"
},
"error": {
"follow_link": "Accede al enlace e identif\u00edcate antes de pulsar Enviar.",
"no_token": "No autenticado con Ambiclimate"
},
"step": {
"auth": {
"description": "Accede al siguiente [enlace]({authorization_url}) y <b>permite</b> el acceso a tu cuenta de Ambiclimate, despu\u00e9s vuelve y pulsa en <b>enviar</b> a continuaci\u00f3n.\n(Aseg\u00farate que la url de devoluci\u00f3n de llamada es {cb_url})",
"title": "Autenticaci\u00f3n de Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Erreur inconnue lors de la g\u00e9n\u00e9ration d'un jeton d'acc\u00e8s.",
"already_setup": "Le compte Ambiclimate est configur\u00e9.",
"no_config": "Vous devez configurer Ambiclimate avant de pouvoir vous authentifier aupr\u00e8s de celui-ci. [Veuillez lire les instructions] (https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Authentifi\u00e9 avec succ\u00e8s avec Ambiclimate"
},
"error": {
"follow_link": "Veuillez suivre le lien et vous authentifier avant d'appuyer sur Soumettre.",
"no_token": "Non authentifi\u00e9 avec Ambiclimate"
},
"step": {
"auth": {
"description": "Suivez ce [lien] ( {authorization_url} ) et <b> Autorisez </b> l'acc\u00e8s \u00e0 votre compte Ambiclimate, puis revenez et appuyez sur <b> Envoyer </b> ci-dessous. \n (Assurez-vous que l'URL de rappel sp\u00e9cifi\u00e9 est {cb_url} )",
"title": "Authentifier Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "\uc561\uc138\uc2a4 \ud1a0\ud070 \uc0dd\uc131\uc5d0 \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.",
"already_setup": "Ambi Climate \uacc4\uc815\uc774 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
"no_config": "Ambi Climate \ub97c \uc778\uc99d\ud558\ub824\uba74 \uba3c\uc800 Ambi Climate \ub97c \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4. [\uc548\ub0b4](https://www.home-assistant.io/components/ambiclimate/) \ub97c \uc77d\uc5b4\ubcf4\uc138\uc694."
},
"create_entry": {
"default": "Ambi Climate \ub85c \uc131\uacf5\uc801\uc73c\ub85c \uc778\uc99d\ub418\uc5c8\uc2b5\ub2c8\ub2e4."
},
"error": {
"follow_link": "Submit \ubc84\ud2bc\uc744 \ub204\ub974\uae30 \uc804\uc5d0 \ub9c1\ud06c\ub97c \ub530\ub77c \uc778\uc99d\uc744 \ubc1b\uc544\uc8fc\uc138\uc694",
"no_token": "Ambi Climate \ub85c \uc778\uc99d\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4"
},
"step": {
"auth": {
"description": "[\ub9c1\ud06c]({authorization_url}) \ub97c \ud074\ub9ad\ud558\uc5ec Ambi Climate \uacc4\uc815\uc5d0 \ub300\ud574 <b>\ud5c8\uc6a9</b> \ud55c \ub2e4\uc74c, \ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c \ud558\ub2e8\uc758 <b>Submit</b> \ubc84\ud2bc\uc744 \ub20c\ub7ec\uc8fc\uc138\uc694. \n(\ucf5c\ubc31 url \uc744 {cb_url} \ub85c \uad6c\uc131\ud588\ub294\uc9c0 \ud655\uc778\ud574\uc8fc\uc138\uc694)",
"title": "Ambi Climate \uc778\uc99d"
}
},
"title": "Ambi Climate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Onbekannte Feeler beim gener\u00e9ieren vum Acc\u00e8s Jeton.",
"already_setup": "Den Ambiclimate Kont ass konfigur\u00e9iert.",
"no_config": "Dir musst Ambiclimate konfigur\u00e9ieren, ier Dir d\u00ebs Authentifiz\u00e9ierung k\u00ebnnt benotzen.[Liest w.e.g. d'Instruktioune](https://www.home-assistant.io/components/ambiclimatet/)."
},
"create_entry": {
"default": "Erfollegr\u00e4ich mat Ambiclimate authentifiz\u00e9iert."
},
"error": {
"follow_link": "Follegt w.e.g. dem Link an authentifiz\u00e9iert de Kont ier dir op ofsch\u00e9cken dr\u00e9ckt.",
"no_token": "Net mat Ambiclimate authentifiz\u00e9iert"
},
"step": {
"auth": {
"description": "Follegt d\u00ebsem [Link]({authorization_url}) an <b>erlaabtt</b> den Acc\u00e8s zu \u00e4rem Ambiclimate Kont , a kommt dann zer\u00e9ck heihin an dr\u00e9ck op <b>ofsch\u00e9cken</b> hei \u00ebnnen.\n(Stellt s\u00e9cher dass den Type vun Callback {cb_url} ass.)",
"title": "Ambiclimate authentifiz\u00e9ieren"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Ukjent feil ved oppretting av tilgangstoken.",
"already_setup": "Ambiclimate-kontoen er konfigurert.",
"no_config": "Du m\u00e5 konfigurere Ambiclimate f\u00f8r du kan autentisere med den. [Vennligst les instruksjonene](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Vellykket autentisering med Ambiclimate"
},
"error": {
"follow_link": "Vennligst f\u00f8lg lenken og godkjen f\u00f8r du trykker p\u00e5 Send",
"no_token": "Ikke autentisert med Ambiclimate"
},
"step": {
"auth": {
"description": "Vennligst f\u00f8lg denne [linken]({authorization_url}) og <b>Tillat</b> tilgang til din Ambiclimate konto, og kom s\u00e5 tilbake og trykk <b>Send</b> nedenfor.\n(Kontroller at den angitte URL-adressen for tilbakeringing er {cb_url})",
"title": "Autensiere Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Nieznany b\u0142\u0105d podczas generowania tokena dost\u0119pu.",
"already_setup": "Konto Ambiclimate jest skonfigurowane.",
"no_config": "Musisz skonfigurowa\u0107 Ambiclimate, zanim b\u0119dziesz m\u00f3g\u0142 si\u0119 z nim uwierzytelni\u0107. [Przeczytaj instrukcj\u0119](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Pomy\u015blnie uwierzytelniono z Ambiclimate"
},
"error": {
"follow_link": "Prosz\u0119 klikn\u0105\u0107 link i uwierzytelni\u0107 przed naci\u015bni\u0119ciem przycisku Prze\u015blij",
"no_token": "Nie uwierzytelniony z Ambiclimate"
},
"step": {
"auth": {
"description": "Kliknij poni\u017cszy [link]({authorization_url}) i <b>Zezw\u00f3l</b> na dost\u0119p do swojego konta Ambiclimate, a nast\u0119pnie wr\u00f3\u0107 i naci\u015bnij <b>Prze\u015blij</b> poni\u017cej. \n(Upewnij si\u0119, \u017ce podany adres URL to {cb_url})",
"title": "Uwierzytelnienie Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.",
"already_setup": "\u0423\u0447\u0435\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Ambi Climate \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430.",
"no_config": "\u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Ambi Climate \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. [\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e."
},
"error": {
"follow_link": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0438 \u043f\u0440\u043e\u0439\u0434\u0438\u0442\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0436\u0430\u0442\u044c \"\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c\".",
"no_token": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043d\u0435 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430."
},
"step": {
"auth": {
"description": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e [\u0441\u0441\u044b\u043b\u043a\u0435]({authorization_url}) \u0438 <b>\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435</b> \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0412\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Ambi Climate, \u0437\u0430\u0442\u0435\u043c \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u0441\u044e\u0434\u0430 \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 <b>\u041f\u041e\u0414\u0422\u0412\u0415\u0420\u0414\u0418\u0422\u042c</b>. \n(\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 URL \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 {cb_url})",
"title": "Ambi Climate"
}
},
"title": "Ambi Climate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Neznana napaka pri ustvarjanju \u017eetona za dostop.",
"already_setup": "Ra\u010dun Ambiclimate je konfiguriran.",
"no_config": "Ambiclimat morate konfigurirati, preden lahko z njo preverjate pristnost. [Preberite navodila] (https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Uspe\u0161no overjeno z funkcijo Ambiclimate"
},
"error": {
"follow_link": "Preden pritisnete Po\u0161lji, sledite povezavi in preverite pristnost",
"no_token": "Ni overjeno z Ambiclimate"
},
"step": {
"auth": {
"description": "Sledite temu povezavi ( {authorization_url} in <b> Dovoli </b> dostopu do svojega ra\u010duna Ambiclimate, nato se vrnite in pritisnite <b> Po\u0161lji </b> spodaj. \n (Poskrbite, da je dolo\u010den url za povratni klic {cb_url} )",
"title": "Overi Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "Ok\u00e4nt fel vid generering av \u00e5tkomsttoken.",
"already_setup": "Ambiclientkontot \u00e4r konfigurerat",
"no_config": "Du m\u00e5ste konfigurera Ambiclimate innan du kan autentisera med den. [V\u00e4nligen l\u00e4s instruktionerna] (https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Lyckad autentisering med Ambiclimate"
},
"error": {
"follow_link": "V\u00e4nligen f\u00f6lj l\u00e4nken och autentisera dig innan du trycker p\u00e5 Skicka",
"no_token": "Inte autentiserad med Ambiclimate"
},
"step": {
"auth": {
"description": "V\u00e4nligen f\u00f6lj denna [l\u00e4nk] ({authorization_url}) och <b> till\u00e5ta </b> till g\u00e5ng till ditt Ambiclimate konto, kom sedan tillbaka och tryck p\u00e5 <b> Skicka </b> nedan.\n(Kontrollera att den angivna callback url \u00e4r {cb_url})",
"title": "Autentisera Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,23 @@
{
"config": {
"abort": {
"access_token": "\u7522\u751f\u5b58\u53d6\u8a8d\u8b49\u78bc\u672a\u77e5\u932f\u8aa4\u3002",
"already_setup": "Ambiclimate \u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210",
"no_config": "\u5fc5\u9808\u5148\u8a2d\u5b9a Ambiclimate \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15]\uff08https://www.home-assistant.io/components/ambiclimate/\uff09\u3002"
},
"create_entry": {
"default": "\u5df2\u6210\u529f\u8a8d\u8b49 Ambiclimate \u88dd\u7f6e\u3002"
},
"error": {
"follow_link": "\u8acb\u65bc\u50b3\u9001\u524d\uff0c\u5148\u4f7f\u7528\u9023\u7d50\u4e26\u9032\u884c\u8a8d\u8b49\u3002",
"no_token": "Ambiclimate \u672a\u6388\u6b0a"
},
"step": {
"auth": {
"description": "\u8acb\u4f7f\u7528\u6b64[\u9023\u7d50]\uff08{authorization_url}\uff09\u4e26\u9ede\u9078<b>\u5141\u8a31</b>\u4ee5\u5b58\u53d6 Ambiclimate \u5e33\u865f\uff0c\u7136\u5f8c\u8fd4\u56de\u6b64\u9801\u9762\u4e26\u9ede\u9078\u4e0b\u65b9\u7684<b>\u50b3\u9001</b>\u3002\n\uff08\u78ba\u5b9a Callback url \u70ba {cb_url}\uff09",
"title": "\u8a8d\u8b49 Ambiclimate"
}
},
"title": "Ambiclimate"
}
}

View File

@@ -0,0 +1,44 @@
"""Support for Ambiclimate devices."""
import logging
import voluptuous as vol
from homeassistant.helpers import config_validation as cv
from . import config_flow
from .const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, DOMAIN
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN:
vol.Schema({
vol.Required(CONF_CLIENT_ID): cv.string,
vol.Required(CONF_CLIENT_SECRET): cv.string,
})
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass, config):
"""Set up Ambiclimate components."""
if DOMAIN not in config:
return True
conf = config[DOMAIN]
config_flow.register_flow_implementation(
hass, conf[CONF_CLIENT_ID],
conf[CONF_CLIENT_SECRET])
return True
async def async_setup_entry(hass, entry):
"""Set up Ambiclimate from a config entry."""
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
entry, 'climate'))
return True

View File

@@ -0,0 +1,230 @@
"""Support for Ambiclimate ac."""
import asyncio
import logging
import ambiclimate
import voluptuous as vol
from homeassistant.components.climate import ClimateDevice
from homeassistant.components.climate.const import (
SUPPORT_TARGET_TEMPERATURE,
SUPPORT_ON_OFF, STATE_HEAT)
from homeassistant.const import ATTR_NAME
from homeassistant.const import (ATTR_TEMPERATURE,
STATE_OFF, TEMP_CELSIUS)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (ATTR_VALUE, CONF_CLIENT_ID, CONF_CLIENT_SECRET,
DOMAIN, SERVICE_COMFORT_FEEDBACK, SERVICE_COMFORT_MODE,
SERVICE_TEMPERATURE_MODE, STORAGE_KEY, STORAGE_VERSION)
_LOGGER = logging.getLogger(__name__)
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE |
SUPPORT_ON_OFF)
SEND_COMFORT_FEEDBACK_SCHEMA = vol.Schema({
vol.Required(ATTR_NAME): cv.string,
vol.Required(ATTR_VALUE): cv.string,
})
SET_COMFORT_MODE_SCHEMA = vol.Schema({
vol.Required(ATTR_NAME): cv.string,
})
SET_TEMPERATURE_MODE_SCHEMA = vol.Schema({
vol.Required(ATTR_NAME): cv.string,
vol.Required(ATTR_VALUE): cv.string,
})
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Ambicliamte device."""
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the Ambicliamte device from config entry."""
config = entry.data
websession = async_get_clientsession(hass)
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
token_info = await store.async_load()
oauth = ambiclimate.AmbiclimateOAuth(config[CONF_CLIENT_ID],
config[CONF_CLIENT_SECRET],
config['callback_url'],
websession)
try:
_token_info = await oauth.refresh_access_token(token_info)
except ambiclimate.AmbiclimateOauthError:
_LOGGER.error("Failed to refresh access token")
return
if _token_info:
await store.async_save(_token_info)
token_info = _token_info
data_connection = ambiclimate.AmbiclimateConnection(oauth,
token_info=token_info,
websession=websession)
if not await data_connection.find_devices():
_LOGGER.error("No devices found")
return
tasks = []
for heater in data_connection.get_devices():
tasks.append(heater.update_device_info())
await asyncio.wait(tasks)
devs = []
for heater in data_connection.get_devices():
devs.append(AmbiclimateEntity(heater, store))
async_add_entities(devs, True)
async def send_comfort_feedback(service):
"""Send comfort feedback."""
device_name = service.data[ATTR_NAME]
device = data_connection.find_device_by_room_name(device_name)
if device:
await device.set_comfort_feedback(service.data[ATTR_VALUE])
hass.services.async_register(DOMAIN,
SERVICE_COMFORT_FEEDBACK,
send_comfort_feedback,
schema=SEND_COMFORT_FEEDBACK_SCHEMA)
async def set_comfort_mode(service):
"""Set comfort mode."""
device_name = service.data[ATTR_NAME]
device = data_connection.find_device_by_room_name(device_name)
if device:
await device.set_comfort_mode()
hass.services.async_register(DOMAIN,
SERVICE_COMFORT_MODE,
set_comfort_mode,
schema=SET_COMFORT_MODE_SCHEMA)
async def set_temperature_mode(service):
"""Set temperature mode."""
device_name = service.data[ATTR_NAME]
device = data_connection.find_device_by_room_name(device_name)
if device:
await device.set_temperature_mode(service.data[ATTR_VALUE])
hass.services.async_register(DOMAIN,
SERVICE_TEMPERATURE_MODE,
set_temperature_mode,
schema=SET_TEMPERATURE_MODE_SCHEMA)
class AmbiclimateEntity(ClimateDevice):
"""Representation of a Ambiclimate Thermostat device."""
def __init__(self, heater, store):
"""Initialize the thermostat."""
self._heater = heater
self._store = store
self._data = {}
@property
def unique_id(self):
"""Return a unique ID."""
return self._heater.device_id
@property
def name(self):
"""Return the name of the entity."""
return self._heater.name
@property
def device_info(self):
"""Return the device info."""
return {
'identifiers': {
(DOMAIN, self.unique_id)
},
'name': self.name,
'manufacturer': 'Ambiclimate',
}
@property
def temperature_unit(self):
"""Return the unit of measurement which this thermostat uses."""
return TEMP_CELSIUS
@property
def target_temperature(self):
"""Return the target temperature."""
return self._data.get('target_temperature')
@property
def target_temperature_step(self):
"""Return the supported step of target temperature."""
return 1
@property
def current_temperature(self):
"""Return the current temperature."""
return self._data.get('temperature')
@property
def current_humidity(self):
"""Return the current humidity."""
return self._data.get('humidity')
@property
def is_on(self):
"""Return true if heater is on."""
return self._data.get('power', '').lower() == 'on'
@property
def min_temp(self):
"""Return the minimum temperature."""
return self._heater.get_min_temp()
@property
def max_temp(self):
"""Return the maximum temperature."""
return self._heater.get_max_temp()
@property
def supported_features(self):
"""Return the list of supported features."""
return SUPPORT_FLAGS
@property
def current_operation(self):
"""Return current operation."""
return STATE_HEAT if self.is_on else STATE_OFF
async def async_set_temperature(self, **kwargs):
"""Set new target temperature."""
temperature = kwargs.get(ATTR_TEMPERATURE)
if temperature is None:
return
await self._heater.set_target_temperature(temperature)
async def async_turn_on(self):
"""Turn device on."""
await self._heater.turn_on()
async def async_turn_off(self):
"""Turn device off."""
await self._heater.turn_off()
async def async_update(self):
"""Retrieve latest state."""
try:
token_info = await self._heater.control.refresh_access_token()
except ambiclimate.AmbiclimateOauthError:
_LOGGER.error("Failed to refresh access token")
return
if token_info:
await self._store.async_save(token_info)
self._data = await self._heater.update_device()

View File

@@ -0,0 +1,153 @@
"""Config flow for Ambiclimate."""
import logging
import ambiclimate
from homeassistant import config_entries
from homeassistant.components.http import HomeAssistantView
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (AUTH_CALLBACK_NAME, AUTH_CALLBACK_PATH, CONF_CLIENT_ID,
CONF_CLIENT_SECRET, DOMAIN, STORAGE_VERSION, STORAGE_KEY)
DATA_AMBICLIMATE_IMPL = 'ambiclimate_flow_implementation'
_LOGGER = logging.getLogger(__name__)
@callback
def register_flow_implementation(hass, client_id, client_secret):
"""Register a ambiclimate implementation.
client_id: Client id.
client_secret: Client secret.
"""
hass.data.setdefault(DATA_AMBICLIMATE_IMPL, {})
hass.data[DATA_AMBICLIMATE_IMPL] = {
CONF_CLIENT_ID: client_id,
CONF_CLIENT_SECRET: client_secret,
}
@config_entries.HANDLERS.register('ambiclimate')
class AmbiclimateFlowHandler(config_entries.ConfigFlow):
"""Handle a config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
def __init__(self):
"""Initialize flow."""
self._registered_view = False
self._oauth = None
async def async_step_user(self, user_input=None):
"""Handle external yaml configuration."""
if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason='already_setup')
config = self.hass.data.get(DATA_AMBICLIMATE_IMPL, {})
if not config:
_LOGGER.debug("No config")
return self.async_abort(reason='no_config')
return await self.async_step_auth()
async def async_step_auth(self, user_input=None):
"""Handle a flow start."""
if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason='already_setup')
errors = {}
if user_input is not None:
errors['base'] = 'follow_link'
if not self._registered_view:
self._generate_view()
return self.async_show_form(
step_id='auth',
description_placeholders={'authorization_url':
await self._get_authorize_url(),
'cb_url': self._cb_url()},
errors=errors,
)
async def async_step_code(self, code=None):
"""Received code for authentication."""
if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason='already_setup')
token_info = await self._get_token_info(code)
if token_info is None:
return self.async_abort(reason='access_token')
config = self.hass.data[DATA_AMBICLIMATE_IMPL].copy()
config['callback_url'] = self._cb_url()
return self.async_create_entry(
title="Ambiclimate",
data=config,
)
async def _get_token_info(self, code):
oauth = self._generate_oauth()
try:
token_info = await oauth.get_access_token(code)
except ambiclimate.AmbiclimateOauthError:
_LOGGER.error("Failed to get access token", exc_info=True)
return None
store = self.hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
await store.async_save(token_info)
return token_info
def _generate_view(self):
self.hass.http.register_view(AmbiclimateAuthCallbackView())
self._registered_view = True
def _generate_oauth(self):
config = self.hass.data[DATA_AMBICLIMATE_IMPL]
clientsession = async_get_clientsession(self.hass)
callback_url = self._cb_url()
oauth = ambiclimate.AmbiclimateOAuth(config.get(CONF_CLIENT_ID),
config.get(CONF_CLIENT_SECRET),
callback_url,
clientsession)
return oauth
def _cb_url(self):
return '{}{}'.format(self.hass.config.api.base_url,
AUTH_CALLBACK_PATH)
async def _get_authorize_url(self):
oauth = self._generate_oauth()
return oauth.get_authorize_url()
class AmbiclimateAuthCallbackView(HomeAssistantView):
"""Ambiclimate Authorization Callback View."""
requires_auth = False
url = AUTH_CALLBACK_PATH
name = AUTH_CALLBACK_NAME
async def get(self, request):
"""Receive authorization token."""
code = request.query.get('code')
if code is None:
return "No code"
hass = request.app['hass']
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={'source': 'code'},
data=code,
))
return "OK!"

View File

@@ -0,0 +1,14 @@
"""Constants used by the Ambiclimate component."""
ATTR_VALUE = 'value'
CONF_CLIENT_ID = 'client_id'
CONF_CLIENT_SECRET = 'client_secret'
DOMAIN = 'ambiclimate'
SERVICE_COMFORT_FEEDBACK = 'send_comfort_feedback'
SERVICE_COMFORT_MODE = 'set_comfort_mode'
SERVICE_TEMPERATURE_MODE = 'set_temperature_mode'
STORAGE_KEY = 'ambiclimate_auth'
STORAGE_VERSION = 1
AUTH_CALLBACK_NAME = 'api:ambiclimate'
AUTH_CALLBACK_PATH = '/api/ambiclimate'

View File

@@ -0,0 +1,13 @@
{
"domain": "ambiclimate",
"name": "Ambiclimate",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ambiclimate",
"requirements": [
"ambiclimate==0.1.2"
],
"dependencies": [],
"codeowners": [
"@danielhiversen"
]
}

View File

@@ -0,0 +1,36 @@
# Describes the format for available services for ambiclimate
set_comfort_mode:
description: >
Enable comfort mode on your AC
fields:
Name:
description: >
String with device name.
example: Bedroom
send_comfort_feedback:
description: >
Send feedback for comfort mode
fields:
Name:
description: >
String with device name.
example: Bedroom
Value:
description: >
Send any of the following comfort values: too_hot, too_warm, bit_warm, comfortable, bit_cold, too_cold, freezing
example: bit_warm
set_temperature_mode:
description: >
Enable temperature mode on your AC
fields:
Name:
description: >
String with device name.
example: Bedroom
Value:
description: >
Target value in celsius
example: 22

View File

@@ -0,0 +1,23 @@
{
"config": {
"title": "Ambiclimate",
"step": {
"auth": {
"title": "Authenticate Ambiclimate",
"description": "Please follow this [link]({authorization_url}) and <b>Allow</b> access to your Ambiclimate account, then come back and press <b>Submit</b> below.\n(Make sure the specified callback url is {cb_url})"
}
},
"create_entry": {
"default": "Successfully authenticated with Ambiclimate"
},
"error": {
"no_token": "Not authenticated with Ambiclimate",
"follow_link": "Please follow the link and authenticate before pressing Submit"
},
"abort": {
"already_setup": "The Ambiclimate account is configured.",
"no_config": "You need to configure Ambiclimate before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/ambiclimate/).",
"access_token": "Unknown error generating an access token."
}
}
}

View File

@@ -1,6 +1,7 @@
{
"domain": "ambient_station",
"name": "Ambient station",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ambient_station",
"requirements": [
"aioambient==0.3.0"

View File

@@ -5,16 +5,30 @@ from datetime import timedelta
import aiohttp
import voluptuous as vol
from homeassistant.auth.permissions.const import POLICY_CONTROL
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
from homeassistant.components.camera import DOMAIN as CAMERA
from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.components.switch import DOMAIN as SWITCH
from homeassistant.const import (
CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD,
CONF_BINARY_SENSORS, CONF_SENSORS, CONF_SWITCHES, CONF_SCAN_INTERVAL,
HTTP_BASIC_AUTHENTICATION)
ATTR_ENTITY_ID, CONF_AUTHENTICATION, CONF_BINARY_SENSORS, CONF_HOST,
CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL, CONF_SENSORS,
CONF_SWITCHES, CONF_USERNAME, ENTITY_MATCH_ALL, HTTP_BASIC_AUTHENTICATION)
from homeassistant.exceptions import Unauthorized, UnknownUser
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.service import async_extract_entity_ids
from .binary_sensor import BINARY_SENSORS
from .camera import CAMERA_SERVICES, STREAM_SOURCE_LIST
from .const import DOMAIN, DATA_AMCREST
from .helpers import service_signal
from .sensor import SENSOR_MOTION_DETECTOR, SENSORS
from .switch import SWITCHES
_LOGGER = logging.getLogger(__name__)
CONF_AUTHENTICATION = 'authentication'
CONF_RESOLUTION = 'resolution'
CONF_STREAM_SOURCE = 'stream_source'
CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
@@ -22,12 +36,7 @@ CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
DEFAULT_NAME = 'Amcrest Camera'
DEFAULT_PORT = 80
DEFAULT_RESOLUTION = 'high'
DEFAULT_STREAM_SOURCE = 'snapshot'
DEFAULT_ARGUMENTS = '-pred 1'
TIMEOUT = 10
DATA_AMCREST = 'amcrest'
DOMAIN = 'amcrest'
NOTIFICATION_ID = 'amcrest_notification'
NOTIFICATION_TITLE = 'Amcrest Camera Setup'
@@ -43,70 +52,60 @@ AUTHENTICATION_LIST = {
'basic': 'basic'
}
STREAM_SOURCE_LIST = {
'mjpeg': 0,
'snapshot': 1,
'rtsp': 2,
}
BINARY_SENSORS = {
'motion_detected': 'Motion Detected'
}
# Sensor types are defined like: Name, units, icon
SENSOR_MOTION_DETECTOR = 'motion_detector'
SENSORS = {
SENSOR_MOTION_DETECTOR: ['Motion Detected', None, 'mdi:run'],
'sdcard': ['SD Used', '%', 'mdi:sd'],
'ptz_preset': ['PTZ Preset', None, 'mdi:camera-iris'],
}
# Switch types are defined like: Name, icon
SWITCHES = {
'motion_detection': ['Motion Detection', 'mdi:run-fast'],
'motion_recording': ['Motion Recording', 'mdi:record-rec']
}
def _deprecated_sensors(value):
if SENSOR_MOTION_DETECTOR in value:
def _deprecated_sensor_values(sensors):
if SENSOR_MOTION_DETECTOR in sensors:
_LOGGER.warning(
'sensors option %s is deprecated. '
'Please remove from your configuration and '
'use binary_sensors option motion_detected instead.',
SENSOR_MOTION_DETECTOR)
return value
"The 'sensors' option value '%s' is deprecated, "
"please remove it from your configuration and use "
"the 'binary_sensors' option with value 'motion_detected' "
"instead.", SENSOR_MOTION_DETECTOR)
return sensors
def _has_unique_names(value):
names = [camera[CONF_NAME] for camera in value]
def _deprecated_switches(config):
if CONF_SWITCHES in config:
_LOGGER.warning(
"The 'switches' option (with value %s) is deprecated, "
"please remove it from your configuration and use "
"camera services and attributes instead.",
config[CONF_SWITCHES])
return config
def _has_unique_names(devices):
names = [device[CONF_NAME] for device in devices]
vol.Schema(vol.Unique())(names)
return value
return devices
AMCREST_SCHEMA = vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION):
vol.All(vol.In(AUTHENTICATION_LIST)),
vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION):
vol.All(vol.In(RESOLUTION_LIST)),
vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE):
vol.All(vol.In(STREAM_SOURCE_LIST)),
vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS):
cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
cv.time_period,
vol.Optional(CONF_BINARY_SENSORS):
vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)]),
vol.Optional(CONF_SENSORS):
vol.All(cv.ensure_list, [vol.In(SENSORS)], _deprecated_sensors),
vol.Optional(CONF_SWITCHES):
vol.All(cv.ensure_list, [vol.In(SWITCHES)]),
})
AMCREST_SCHEMA = vol.All(
vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION):
vol.All(vol.In(AUTHENTICATION_LIST)),
vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION):
vol.All(vol.In(RESOLUTION_LIST)),
vol.Optional(CONF_STREAM_SOURCE, default=STREAM_SOURCE_LIST[0]):
vol.All(vol.In(STREAM_SOURCE_LIST)),
vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS):
cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
cv.time_period,
vol.Optional(CONF_BINARY_SENSORS):
vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)]),
vol.Optional(CONF_SENSORS):
vol.All(cv.ensure_list, [vol.In(SENSORS)],
_deprecated_sensor_values),
vol.Optional(CONF_SWITCHES):
vol.All(cv.ensure_list, [vol.In(SWITCHES)]),
}),
_deprecated_switches
)
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.All(cv.ensure_list, [AMCREST_SCHEMA], _has_unique_names)
@@ -117,21 +116,22 @@ def setup(hass, config):
"""Set up the Amcrest IP Camera component."""
from amcrest import AmcrestCamera, AmcrestError
hass.data.setdefault(DATA_AMCREST, {})
amcrest_cams = config[DOMAIN]
hass.data.setdefault(DATA_AMCREST, {'devices': {}, 'cameras': []})
devices = config[DOMAIN]
for device in amcrest_cams:
for device in devices:
name = device[CONF_NAME]
username = device[CONF_USERNAME]
password = device[CONF_PASSWORD]
try:
camera = AmcrestCamera(device[CONF_HOST],
device[CONF_PORT],
username,
password).camera
api = AmcrestCamera(device[CONF_HOST],
device[CONF_PORT],
username,
password).camera
# pylint: disable=pointless-statement
camera.current_time
# Test camera communications.
api.current_time
except AmcrestError as ex:
_LOGGER.error("Unable to connect to %s camera: %s", name, str(ex))
@@ -148,7 +148,7 @@ def setup(hass, config):
binary_sensors = device.get(CONF_BINARY_SENSORS)
sensors = device.get(CONF_SENSORS)
switches = device.get(CONF_SWITCHES)
stream_source = STREAM_SOURCE_LIST[device[CONF_STREAM_SOURCE]]
stream_source = device[CONF_STREAM_SOURCE]
# currently aiohttp only works with basic authentication
# only valid for mjpeg streaming
@@ -157,47 +157,97 @@ def setup(hass, config):
else:
authentication = None
hass.data[DATA_AMCREST][name] = AmcrestDevice(
camera, name, authentication, ffmpeg_arguments, stream_source,
hass.data[DATA_AMCREST]['devices'][name] = AmcrestDevice(
api, authentication, ffmpeg_arguments, stream_source,
resolution)
discovery.load_platform(
hass, 'camera', DOMAIN, {
hass, CAMERA, DOMAIN, {
CONF_NAME: name,
}, config)
if binary_sensors:
discovery.load_platform(
hass, 'binary_sensor', DOMAIN, {
hass, BINARY_SENSOR, DOMAIN, {
CONF_NAME: name,
CONF_BINARY_SENSORS: binary_sensors
}, config)
if sensors:
discovery.load_platform(
hass, 'sensor', DOMAIN, {
hass, SENSOR, DOMAIN, {
CONF_NAME: name,
CONF_SENSORS: sensors,
}, config)
if switches:
discovery.load_platform(
hass, 'switch', DOMAIN, {
hass, SWITCH, DOMAIN, {
CONF_NAME: name,
CONF_SWITCHES: switches
}, config)
return len(hass.data[DATA_AMCREST]) >= 1
if not hass.data[DATA_AMCREST]['devices']:
return False
def have_permission(user, entity_id):
return not user or user.permissions.check_entity(
entity_id, POLICY_CONTROL)
async def async_extract_from_service(call):
if call.context.user_id:
user = await hass.auth.async_get_user(call.context.user_id)
if user is None:
raise UnknownUser(context=call.context)
else:
user = None
if call.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL:
# Return all entity_ids user has permission to control.
return [
entity_id for entity_id in hass.data[DATA_AMCREST]['cameras']
if have_permission(user, entity_id)
]
call_ids = await async_extract_entity_ids(hass, call)
entity_ids = []
for entity_id in hass.data[DATA_AMCREST]['cameras']:
if entity_id not in call_ids:
continue
if not have_permission(user, entity_id):
raise Unauthorized(
context=call.context,
entity_id=entity_id,
permission=POLICY_CONTROL
)
entity_ids.append(entity_id)
return entity_ids
async def async_service_handler(call):
args = []
for arg in CAMERA_SERVICES[call.service][2]:
args.append(call.data[arg])
for entity_id in await async_extract_from_service(call):
async_dispatcher_send(
hass,
service_signal(call.service, entity_id),
*args
)
for service, params in CAMERA_SERVICES.items():
hass.services.async_register(
DOMAIN, service, async_service_handler, params[0])
return True
class AmcrestDevice:
"""Representation of a base Amcrest discovery device."""
def __init__(self, camera, name, authentication, ffmpeg_arguments,
def __init__(self, api, authentication, ffmpeg_arguments,
stream_source, resolution):
"""Initialize the entity."""
self.device = camera
self.name = name
self.api = api
self.authentication = authentication
self.ffmpeg_arguments = ffmpeg_arguments
self.stream_source = stream_source

View File

@@ -5,38 +5,39 @@ import logging
from homeassistant.components.binary_sensor import (
BinarySensorDevice, DEVICE_CLASS_MOTION)
from homeassistant.const import CONF_NAME, CONF_BINARY_SENSORS
from . import DATA_AMCREST, BINARY_SENSORS
from .const import BINARY_SENSOR_SCAN_INTERVAL_SECS, DATA_AMCREST
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=5)
SCAN_INTERVAL = timedelta(seconds=BINARY_SENSOR_SCAN_INTERVAL_SECS)
BINARY_SENSORS = {
'motion_detected': 'Motion Detected'
}
async def async_setup_platform(hass, config, async_add_devices,
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a binary sensor for an Amcrest IP Camera."""
if discovery_info is None:
return
device_name = discovery_info[CONF_NAME]
binary_sensors = discovery_info[CONF_BINARY_SENSORS]
amcrest = hass.data[DATA_AMCREST][device_name]
amcrest_binary_sensors = []
for sensor_type in binary_sensors:
amcrest_binary_sensors.append(
AmcrestBinarySensor(amcrest.name, amcrest.device, sensor_type))
async_add_devices(amcrest_binary_sensors, True)
name = discovery_info[CONF_NAME]
device = hass.data[DATA_AMCREST]['devices'][name]
async_add_entities(
[AmcrestBinarySensor(name, device, sensor_type)
for sensor_type in discovery_info[CONF_BINARY_SENSORS]],
True)
class AmcrestBinarySensor(BinarySensorDevice):
"""Binary sensor for Amcrest camera."""
def __init__(self, name, camera, sensor_type):
def __init__(self, name, device, sensor_type):
"""Initialize entity."""
self._name = '{} {}'.format(name, BINARY_SENSORS[sensor_type])
self._camera = camera
self._api = device.api
self._sensor_type = sensor_type
self._state = None
@@ -62,7 +63,7 @@ class AmcrestBinarySensor(BinarySensorDevice):
_LOGGER.debug('Pulling data from %s binary sensor', self._name)
try:
self._state = self._camera.is_motion_detected
self._state = self._api.is_motion_detected
except AmcrestError as error:
_LOGGER.error(
'Could not update %s binary sensor due to error: %s',

View File

@@ -2,18 +2,72 @@
import asyncio
import logging
import voluptuous as vol
from homeassistant.components.camera import (
Camera, SUPPORT_ON_OFF, SUPPORT_STREAM)
Camera, CAMERA_SERVICE_SCHEMA, SUPPORT_ON_OFF, SUPPORT_STREAM)
from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import CONF_NAME
from homeassistant.const import (
CONF_NAME, STATE_ON, STATE_OFF)
from homeassistant.helpers.aiohttp_client import (
async_aiohttp_proxy_stream, async_aiohttp_proxy_web,
async_get_clientsession)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT
from .const import CAMERA_WEB_SESSION_TIMEOUT, DATA_AMCREST
from .helpers import service_signal
_LOGGER = logging.getLogger(__name__)
STREAM_SOURCE_LIST = [
'snapshot',
'mjpeg',
'rtsp',
]
_SRV_EN_REC = 'enable_recording'
_SRV_DS_REC = 'disable_recording'
_SRV_EN_AUD = 'enable_audio'
_SRV_DS_AUD = 'disable_audio'
_SRV_EN_MOT_REC = 'enable_motion_recording'
_SRV_DS_MOT_REC = 'disable_motion_recording'
_SRV_GOTO = 'goto_preset'
_SRV_CBW = 'set_color_bw'
_SRV_TOUR_ON = 'start_tour'
_SRV_TOUR_OFF = 'stop_tour'
_ATTR_PRESET = 'preset'
_ATTR_COLOR_BW = 'color_bw'
_CBW_COLOR = 'color'
_CBW_AUTO = 'auto'
_CBW_BW = 'bw'
_CBW = [_CBW_COLOR, _CBW_AUTO, _CBW_BW]
_SRV_GOTO_SCHEMA = CAMERA_SERVICE_SCHEMA.extend({
vol.Required(_ATTR_PRESET): vol.All(vol.Coerce(int), vol.Range(min=1)),
})
_SRV_CBW_SCHEMA = CAMERA_SERVICE_SCHEMA.extend({
vol.Required(_ATTR_COLOR_BW): vol.In(_CBW),
})
CAMERA_SERVICES = {
_SRV_EN_REC: (CAMERA_SERVICE_SCHEMA, 'async_enable_recording', ()),
_SRV_DS_REC: (CAMERA_SERVICE_SCHEMA, 'async_disable_recording', ()),
_SRV_EN_AUD: (CAMERA_SERVICE_SCHEMA, 'async_enable_audio', ()),
_SRV_DS_AUD: (CAMERA_SERVICE_SCHEMA, 'async_disable_audio', ()),
_SRV_EN_MOT_REC: (
CAMERA_SERVICE_SCHEMA, 'async_enable_motion_recording', ()),
_SRV_DS_MOT_REC: (
CAMERA_SERVICE_SCHEMA, 'async_disable_motion_recording', ()),
_SRV_GOTO: (_SRV_GOTO_SCHEMA, 'async_goto_preset', (_ATTR_PRESET,)),
_SRV_CBW: (_SRV_CBW_SCHEMA, 'async_set_color_bw', (_ATTR_COLOR_BW,)),
_SRV_TOUR_ON: (CAMERA_SERVICE_SCHEMA, 'async_start_tour', ()),
_SRV_TOUR_OFF: (CAMERA_SERVICE_SCHEMA, 'async_stop_tour', ()),
}
_BOOL_TO_STATE = {True: STATE_ON, False: STATE_OFF}
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
@@ -21,28 +75,33 @@ async def async_setup_platform(hass, config, async_add_entities,
if discovery_info is None:
return
device_name = discovery_info[CONF_NAME]
amcrest = hass.data[DATA_AMCREST][device_name]
async_add_entities([AmcrestCam(hass, amcrest)], True)
name = discovery_info[CONF_NAME]
device = hass.data[DATA_AMCREST]['devices'][name]
async_add_entities([
AmcrestCam(name, device, hass.data[DATA_FFMPEG])], True)
class AmcrestCam(Camera):
"""An implementation of an Amcrest IP camera."""
def __init__(self, hass, amcrest):
def __init__(self, name, device, ffmpeg):
"""Initialize an Amcrest camera."""
super(AmcrestCam, self).__init__()
self._name = amcrest.name
self._camera = amcrest.device
self._ffmpeg = hass.data[DATA_FFMPEG]
self._ffmpeg_arguments = amcrest.ffmpeg_arguments
self._stream_source = amcrest.stream_source
self._resolution = amcrest.resolution
self._token = self._auth = amcrest.authentication
super().__init__()
self._name = name
self._api = device.api
self._ffmpeg = ffmpeg
self._ffmpeg_arguments = device.ffmpeg_arguments
self._stream_source = device.stream_source
self._resolution = device.resolution
self._token = self._auth = device.authentication
self._is_recording = False
self._motion_detection_enabled = None
self._model = None
self._audio_enabled = None
self._motion_recording_enabled = None
self._color_bw = None
self._snapshot_lock = asyncio.Lock()
self._unsub_dispatcher = []
async def async_camera_image(self):
"""Return a still image response from the camera."""
@@ -56,7 +115,7 @@ class AmcrestCam(Camera):
try:
# Send the request to snap a picture and return raw jpg data
response = await self.hass.async_add_executor_job(
self._camera.snapshot, self._resolution)
self._api.snapshot, self._resolution)
return response.data
except AmcrestError as error:
_LOGGER.error(
@@ -67,15 +126,16 @@ class AmcrestCam(Camera):
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']:
if self._stream_source == 'snapshot':
return await super().handle_async_mjpeg_stream(request)
if self._stream_source == STREAM_SOURCE_LIST['mjpeg']:
if self._stream_source == 'mjpeg':
# stream an MJPEG image stream directly from the camera
websession = async_get_clientsession(self.hass)
streaming_url = self._camera.mjpeg_url(typeno=self._resolution)
streaming_url = self._api.mjpeg_url(typeno=self._resolution)
stream_coro = websession.get(
streaming_url, auth=self._token, timeout=TIMEOUT)
streaming_url, auth=self._token,
timeout=CAMERA_WEB_SESSION_TIMEOUT)
return await async_aiohttp_proxy_web(
self.hass, request, stream_coro)
@@ -83,7 +143,7 @@ class AmcrestCam(Camera):
# streaming via ffmpeg
from haffmpeg.camera import CameraMjpeg
streaming_url = self._camera.rtsp_url(typeno=self._resolution)
streaming_url = self._api.rtsp_url(typeno=self._resolution)
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
await stream.open_camera(
streaming_url, extra_cmd=self._ffmpeg_arguments)
@@ -103,6 +163,19 @@ class AmcrestCam(Camera):
"""Return the name of this camera."""
return self._name
@property
def device_state_attributes(self):
"""Return the Amcrest-specific camera state attributes."""
attr = {}
if self._audio_enabled is not None:
attr['audio'] = _BOOL_TO_STATE.get(self._audio_enabled)
if self._motion_recording_enabled is not None:
attr['motion_recording'] = _BOOL_TO_STATE.get(
self._motion_recording_enabled)
if self._color_bw is not None:
attr[_ATTR_COLOR_BW] = self._color_bw
return attr
@property
def supported_features(self):
"""Return supported features."""
@@ -120,15 +193,19 @@ class AmcrestCam(Camera):
"""Return the camera brand."""
return 'Amcrest'
@property
def motion_detection_enabled(self):
"""Return the camera motion detection status."""
return self._motion_detection_enabled
@property
def model(self):
"""Return the camera model."""
return self._model
@property
def stream_source(self):
async def stream_source(self):
"""Return the source of the stream."""
return self._camera.rtsp_url(typeno=self._resolution)
return self._api.rtsp_url(typeno=self._resolution)
@property
def is_on(self):
@@ -137,6 +214,21 @@ class AmcrestCam(Camera):
# Other Entity method overrides
async def async_added_to_hass(self):
"""Subscribe to signals and add camera to list."""
for service, params in CAMERA_SERVICES.items():
self._unsub_dispatcher.append(async_dispatcher_connect(
self.hass,
service_signal(service, self.entity_id),
getattr(self, params[1])))
self.hass.data[DATA_AMCREST]['cameras'].append(self.entity_id)
async def async_will_remove_from_hass(self):
"""Remove camera from list and disconnect from signals."""
self.hass.data[DATA_AMCREST]['cameras'].remove(self.entity_id)
for unsub_dispatcher in self._unsub_dispatcher:
unsub_dispatcher()
def update(self):
"""Update entity status."""
from amcrest import AmcrestError
@@ -144,15 +236,21 @@ class AmcrestCam(Camera):
_LOGGER.debug('Pulling data from %s camera', self.name)
if self._model is None:
try:
self._model = self._camera.device_type.split('=')[-1].strip()
self._model = self._api.device_type.split('=')[-1].strip()
except AmcrestError as error:
_LOGGER.error(
'Could not get %s camera model due to error: %s',
self.name, error)
self._model = ''
try:
self.is_streaming = self._camera.video_enabled
self._is_recording = self._camera.record_mode == 'Manual'
self.is_streaming = self._api.video_enabled
self._is_recording = self._api.record_mode == 'Manual'
self._motion_detection_enabled = (
self._api.is_motion_detector_on())
self._audio_enabled = self._api.audio_enabled
self._motion_recording_enabled = (
self._api.is_record_on_motion_detection())
self._color_bw = _CBW[self._api.day_night_color]
except AmcrestError as error:
_LOGGER.error(
'Could not get %s camera attributes due to error: %s',
@@ -168,14 +266,71 @@ class AmcrestCam(Camera):
"""Turn on camera."""
self._enable_video_stream(True)
# Utility methods
def enable_motion_detection(self):
"""Enable motion detection in the camera."""
self._enable_motion_detection(True)
def disable_motion_detection(self):
"""Disable motion detection in camera."""
self._enable_motion_detection(False)
# Additional Amcrest Camera service methods
async def async_enable_recording(self):
"""Call the job and enable recording."""
await self.hass.async_add_executor_job(self._enable_recording, True)
async def async_disable_recording(self):
"""Call the job and disable recording."""
await self.hass.async_add_executor_job(self._enable_recording, False)
async def async_enable_audio(self):
"""Call the job and enable audio."""
await self.hass.async_add_executor_job(self._enable_audio, True)
async def async_disable_audio(self):
"""Call the job and disable audio."""
await self.hass.async_add_executor_job(self._enable_audio, False)
async def async_enable_motion_recording(self):
"""Call the job and enable motion recording."""
await self.hass.async_add_executor_job(self._enable_motion_recording,
True)
async def async_disable_motion_recording(self):
"""Call the job and disable motion recording."""
await self.hass.async_add_executor_job(self._enable_motion_recording,
False)
async def async_goto_preset(self, preset):
"""Call the job and move camera to preset position."""
await self.hass.async_add_executor_job(self._goto_preset, preset)
async def async_set_color_bw(self, color_bw):
"""Call the job and set camera color mode."""
await self.hass.async_add_executor_job(self._set_color_bw, color_bw)
async def async_start_tour(self):
"""Call the job and start camera tour."""
await self.hass.async_add_executor_job(self._start_tour, True)
async def async_stop_tour(self):
"""Call the job and stop camera tour."""
await self.hass.async_add_executor_job(self._start_tour, False)
# Methods to send commands to Amcrest camera and handle errors
def _enable_video_stream(self, enable):
"""Enable or disable camera video stream."""
from amcrest import AmcrestError
# Given the way the camera's state is determined by
# is_streaming and is_recording, we can't leave
# recording on if video stream is being turned off.
if self.is_recording and not enable:
self._enable_recording(False)
try:
self._camera.video_enabled = enable
self._api.video_enabled = enable
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera video stream due to error: %s',
@@ -183,3 +338,103 @@ class AmcrestCam(Camera):
else:
self.is_streaming = enable
self.schedule_update_ha_state()
def _enable_recording(self, enable):
"""Turn recording on or off."""
from amcrest import AmcrestError
# Given the way the camera's state is determined by
# is_streaming and is_recording, we can't leave
# video stream off if recording is being turned on.
if not self.is_streaming and enable:
self._enable_video_stream(True)
rec_mode = {'Automatic': 0, 'Manual': 1}
try:
self._api.record_mode = rec_mode[
'Manual' if enable else 'Automatic']
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera recording due to error: %s',
'enable' if enable else 'disable', self.name, error)
else:
self._is_recording = enable
self.schedule_update_ha_state()
def _enable_motion_detection(self, enable):
"""Enable or disable motion detection."""
from amcrest import AmcrestError
try:
self._api.motion_detection = str(enable).lower()
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera motion detection due to error: %s',
'enable' if enable else 'disable', self.name, error)
else:
self._motion_detection_enabled = enable
self.schedule_update_ha_state()
def _enable_audio(self, enable):
"""Enable or disable audio stream."""
from amcrest import AmcrestError
try:
self._api.audio_enabled = enable
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera audio stream due to error: %s',
'enable' if enable else 'disable', self.name, error)
else:
self._audio_enabled = enable
self.schedule_update_ha_state()
def _enable_motion_recording(self, enable):
"""Enable or disable motion recording."""
from amcrest import AmcrestError
try:
self._api.motion_recording = str(enable).lower()
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera motion recording due to error: %s',
'enable' if enable else 'disable', self.name, error)
else:
self._motion_recording_enabled = enable
self.schedule_update_ha_state()
def _goto_preset(self, preset):
"""Move camera position and zoom to preset."""
from amcrest import AmcrestError
try:
self._api.go_to_preset(
action='start', preset_point_number=preset)
except AmcrestError as error:
_LOGGER.error(
'Could not move %s camera to preset %i due to error: %s',
self.name, preset, error)
def _set_color_bw(self, cbw):
"""Set camera color mode."""
from amcrest import AmcrestError
try:
self._api.day_night_color = _CBW.index(cbw)
except AmcrestError as error:
_LOGGER.error(
'Could not set %s camera color mode to %s due to error: %s',
self.name, cbw, error)
else:
self._color_bw = cbw
self.schedule_update_ha_state()
def _start_tour(self, start):
"""Start camera tour."""
from amcrest import AmcrestError
try:
self._api.tour(start=start)
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera tour due to error: %s',
'start' if start else 'stop', self.name, error)

View File

@@ -0,0 +1,7 @@
"""Constants for amcrest component."""
DOMAIN = 'amcrest'
DATA_AMCREST = DOMAIN
BINARY_SENSOR_SCAN_INTERVAL_SECS = 5
CAMERA_WEB_SESSION_TIMEOUT = 10
SENSOR_SCAN_INTERVAL_SECS = 10

View File

@@ -0,0 +1,10 @@
"""Helpers for amcrest component."""
from .const import DOMAIN
def service_signal(service, entity_id=None):
"""Encode service and entity_id into signal."""
signal = '{}_{}'.format(DOMAIN, service)
if entity_id:
signal += '_{}'.format(entity_id.replace('.', '_'))
return signal

View File

@@ -3,7 +3,7 @@
"name": "Amcrest",
"documentation": "https://www.home-assistant.io/components/amcrest",
"requirements": [
"amcrest==1.3.0"
"amcrest==1.4.0"
],
"dependencies": [
"ffmpeg"

View File

@@ -5,11 +5,19 @@ import logging
from homeassistant.const import CONF_NAME, CONF_SENSORS
from homeassistant.helpers.entity import Entity
from . import DATA_AMCREST, SENSORS
from .const import DATA_AMCREST, SENSOR_SCAN_INTERVAL_SECS
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=10)
SCAN_INTERVAL = timedelta(seconds=SENSOR_SCAN_INTERVAL_SECS)
# Sensor types are defined like: Name, units, icon
SENSOR_MOTION_DETECTOR = 'motion_detector'
SENSORS = {
SENSOR_MOTION_DETECTOR: ['Motion Detected', None, 'mdi:run'],
'sdcard': ['SD Used', '%', 'mdi:sd'],
'ptz_preset': ['PTZ Preset', None, 'mdi:camera-iris'],
}
async def async_setup_platform(
@@ -18,30 +26,26 @@ async def async_setup_platform(
if discovery_info is None:
return
device_name = discovery_info[CONF_NAME]
sensors = discovery_info[CONF_SENSORS]
amcrest = hass.data[DATA_AMCREST][device_name]
amcrest_sensors = []
for sensor_type in sensors:
amcrest_sensors.append(
AmcrestSensor(amcrest.name, amcrest.device, sensor_type))
async_add_entities(amcrest_sensors, True)
name = discovery_info[CONF_NAME]
device = hass.data[DATA_AMCREST]['devices'][name]
async_add_entities(
[AmcrestSensor(name, device, sensor_type)
for sensor_type in discovery_info[CONF_SENSORS]],
True)
class AmcrestSensor(Entity):
"""A sensor implementation for Amcrest IP camera."""
def __init__(self, name, camera, sensor_type):
def __init__(self, name, device, sensor_type):
"""Initialize a sensor for Amcrest camera."""
self._attrs = {}
self._camera = camera
self._name = '{} {}'.format(name, SENSORS[sensor_type][0])
self._api = device.api
self._sensor_type = sensor_type
self._name = '{0}_{1}'.format(
name, SENSORS.get(self._sensor_type)[0])
self._icon = 'mdi:{}'.format(SENSORS.get(self._sensor_type)[2])
self._state = None
self._attrs = {}
self._unit_of_measurement = SENSORS[sensor_type][1]
self._icon = SENSORS[sensor_type][2]
@property
def name(self):
@@ -66,22 +70,30 @@ class AmcrestSensor(Entity):
@property
def unit_of_measurement(self):
"""Return the units of measurement."""
return SENSORS.get(self._sensor_type)[1]
return self._unit_of_measurement
def update(self):
"""Get the latest data and updates the state."""
_LOGGER.debug("Pulling data from %s sensor.", self._name)
if self._sensor_type == 'motion_detector':
self._state = self._camera.is_motion_detected
self._attrs['Record Mode'] = self._camera.record_mode
self._state = self._api.is_motion_detected
self._attrs['Record Mode'] = self._api.record_mode
elif self._sensor_type == 'ptz_preset':
self._state = self._camera.ptz_presets_count
self._state = self._api.ptz_presets_count
elif self._sensor_type == 'sdcard':
sd_used = self._camera.storage_used
sd_total = self._camera.storage_total
self._attrs['Total'] = '{0} {1}'.format(*sd_total)
self._attrs['Used'] = '{0} {1}'.format(*sd_used)
self._state = self._camera.storage_used_percent
storage = self._api.storage_all
try:
self._attrs['Total'] = '{:.2f} {}'.format(*storage['total'])
except ValueError:
self._attrs['Total'] = '{} {}'.format(*storage['total'])
try:
self._attrs['Used'] = '{:.2f} {}'.format(*storage['used'])
except ValueError:
self._attrs['Used'] = '{} {}'.format(*storage['used'])
try:
self._state = '{:.2f}'.format(storage['used_percent'])
except ValueError:
self._state = storage['used_percent']

View File

@@ -0,0 +1,75 @@
enable_recording:
description: Enable continuous recording to camera storage.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
disable_recording:
description: Disable continuous recording to camera storage.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
enable_audio:
description: Enable audio stream.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
disable_audio:
description: Disable audio stream.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
enable_motion_recording:
description: Enable recording a clip to camera storage when motion is detected.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
disable_motion_recording:
description: Disable recording a clip to camera storage when motion is detected.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
goto_preset:
description: Move camera to PTZ preset.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
preset:
description: Preset number, starting from 1.
example: 1
set_color_bw:
description: Set camera color mode.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
color_bw:
description: Color mode, one of 'auto', 'color' or 'bw'.
example: auto
start_tour:
description: Start camera's PTZ tour function.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'
stop_tour:
description: Stop camera's PTZ tour function.
fields:
entity_id:
description: "Name(s) of the cameras, or 'all' for all cameras."
example: 'camera.house_front'

View File

@@ -1,13 +1,19 @@
"""Support for toggling Amcrest IP camera settings."""
import logging
from homeassistant.const import CONF_NAME, CONF_SWITCHES, STATE_OFF, STATE_ON
from homeassistant.const import CONF_NAME, CONF_SWITCHES
from homeassistant.helpers.entity import ToggleEntity
from . import DATA_AMCREST, SWITCHES
from .const import DATA_AMCREST
_LOGGER = logging.getLogger(__name__)
# Switch types are defined like: Name, icon
SWITCHES = {
'motion_detection': ['Motion Detection', 'mdi:run-fast'],
'motion_recording': ['Motion Recording', 'mdi:record-rec']
}
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
@@ -16,67 +22,58 @@ async def async_setup_platform(
return
name = discovery_info[CONF_NAME]
switches = discovery_info[CONF_SWITCHES]
camera = hass.data[DATA_AMCREST][name].device
all_switches = []
for setting in switches:
all_switches.append(AmcrestSwitch(setting, camera, name))
async_add_entities(all_switches, True)
device = hass.data[DATA_AMCREST]['devices'][name]
async_add_entities(
[AmcrestSwitch(name, device, setting)
for setting in discovery_info[CONF_SWITCHES]],
True)
class AmcrestSwitch(ToggleEntity):
"""Representation of an Amcrest IP camera switch."""
def __init__(self, setting, camera, name):
def __init__(self, name, device, setting):
"""Initialize the Amcrest switch."""
self._name = '{} {}'.format(name, SWITCHES[setting][0])
self._api = device.api
self._setting = setting
self._camera = camera
self._name = '{} {}'.format(SWITCHES[setting][0], name)
self._state = False
self._icon = SWITCHES[setting][1]
self._state = None
@property
def name(self):
"""Return the name of the switch if any."""
return self._name
@property
def state(self):
"""Return the state of the switch."""
return self._state
@property
def is_on(self):
"""Return true if switch is on."""
return self._state == STATE_ON
return self._state
def turn_on(self, **kwargs):
"""Turn setting on."""
if self._setting == 'motion_detection':
self._camera.motion_detection = 'true'
self._api.motion_detection = 'true'
elif self._setting == 'motion_recording':
self._camera.motion_recording = 'true'
self._api.motion_recording = 'true'
def turn_off(self, **kwargs):
"""Turn setting off."""
if self._setting == 'motion_detection':
self._camera.motion_detection = 'false'
self._api.motion_detection = 'false'
elif self._setting == 'motion_recording':
self._camera.motion_recording = 'false'
self._api.motion_recording = 'false'
def update(self):
"""Update setting state."""
_LOGGER.debug("Polling state for setting: %s ", self._name)
if self._setting == 'motion_detection':
detection = self._camera.is_motion_detector_on()
detection = self._api.is_motion_detector_on()
elif self._setting == 'motion_recording':
detection = self._camera.is_record_on_motion_detection()
detection = self._api.is_record_on_motion_detection()
self._state = STATE_ON if detection else STATE_OFF
self._state = detection
@property
def icon(self):

View File

@@ -233,7 +233,7 @@ async def async_setup(hass, config):
tasks = [async_setup_ipcamera(conf) for conf in config[DOMAIN]]
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks)
return True

View File

@@ -90,20 +90,21 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
if CONF_ADB_SERVER_IP not in config:
# Use "python-adb" (Python ADB implementation)
adb_log = "using Python ADB implementation "
if CONF_ADBKEY in config:
aftv = setup(host, config[CONF_ADBKEY],
device_class=config[CONF_DEVICE_CLASS])
adb_log = " using adbkey='{0}'".format(config[CONF_ADBKEY])
adb_log += "with adbkey='{0}'".format(config[CONF_ADBKEY])
else:
aftv = setup(host, device_class=config[CONF_DEVICE_CLASS])
adb_log = ""
adb_log += "without adbkey authentication"
else:
# Use "pure-python-adb" (communicate with ADB server)
aftv = setup(host, adb_server_ip=config[CONF_ADB_SERVER_IP],
adb_server_port=config[CONF_ADB_SERVER_PORT],
device_class=config[CONF_DEVICE_CLASS])
adb_log = " using ADB server at {0}:{1}".format(
adb_log = "using ADB server at {0}:{1}".format(
config[CONF_ADB_SERVER_IP], config[CONF_ADB_SERVER_PORT])
if not aftv.available:
@@ -117,7 +118,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
else:
device_name = 'Android TV / Fire TV device'
_LOGGER.warning("Could not connect to %s at %s%s",
_LOGGER.warning("Could not connect to %s at %s %s",
device_name, host, adb_log)
raise PlatformNotReady
@@ -156,10 +157,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
for target_device in target_devices:
output = target_device.adb_command(cmd)
# log the output if there is any
if output and (not isinstance(output, str) or output.strip()):
# log the output, if there is any
if output:
_LOGGER.info("Output of command '%s' from '%s': %s",
cmd, target_device.entity_id, repr(output))
cmd, target_device.entity_id, output)
hass.services.register(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND,
service_adb_command,
@@ -224,6 +225,7 @@ class ADBDevice(MediaPlayerDevice):
self.exceptions = (ConnectionResetError, RuntimeError)
# Property attributes
self._adb_response = None
self._available = self.aftv.available
self._current_app = None
self._state = None
@@ -243,6 +245,11 @@ class ADBDevice(MediaPlayerDevice):
"""Return whether or not the ADB connection is valid."""
return self._available
@property
def device_state_attributes(self):
"""Provide the last ADB command's response as an attribute."""
return {'adb_response': self._adb_response}
@property
def name(self):
"""Return the device name."""
@@ -304,12 +311,24 @@ class ADBDevice(MediaPlayerDevice):
"""Send an ADB command to an Android TV / Fire TV device."""
key = self._keys.get(cmd)
if key:
return self.aftv.adb_shell('input keyevent {}'.format(key))
self.aftv.adb_shell('input keyevent {}'.format(key))
self._adb_response = None
self.schedule_update_ha_state()
return
if cmd == 'GET_PROPERTIES':
return self.aftv.get_properties_dict()
self._adb_response = str(self.aftv.get_properties_dict())
self.schedule_update_ha_state()
return self._adb_response
return self.aftv.adb_shell(cmd)
response = self.aftv.adb_shell(cmd)
if isinstance(response, str) and response.strip():
self._adb_response = response.strip()
else:
self._adb_response = None
self.schedule_update_ha_state()
return self._adb_response
class AndroidTVDevice(ADBDevice):

View File

@@ -47,7 +47,7 @@ async def async_setup_platform(hass, config, async_add_entities,
hass.async_create_task(device.async_update_ha_state())
avr = await anthemav.Connection.create(
host=host, port=port, loop=hass.loop,
host=host, port=port,
update_callback=async_anthemav_update_callback)
device = AnthemAVR(avr, name)

View File

@@ -82,7 +82,7 @@ class APIEventStream(HomeAssistantView):
raise Unauthorized()
hass = request.app['hass']
stop_obj = object()
to_write = asyncio.Queue(loop=hass.loop)
to_write = asyncio.Queue()
restrict = request.query.get('restrict')
if restrict:
@@ -119,8 +119,7 @@ class APIEventStream(HomeAssistantView):
while True:
try:
with async_timeout.timeout(STREAM_PING_INTERVAL,
loop=hass.loop):
with async_timeout.timeout(STREAM_PING_INTERVAL):
payload = await to_write.get()
if payload is stop_obj:

View File

@@ -1,6 +1,5 @@
"""APNS Notification platform."""
import logging
import os
import voluptuous as vol
@@ -149,7 +148,8 @@ class ApnsNotificationService(BaseNotificationService):
self.devices = {}
self.device_states = {}
self.topic = topic
if os.path.isfile(self.yaml_path):
try:
self.devices = {
str(key): ApnsDevice(
str(key),
@@ -160,6 +160,8 @@ class ApnsNotificationService(BaseNotificationService):
for (key, value) in
load_yaml_config_file(self.yaml_path).items()
}
except FileNotFoundError:
pass
tracking_ids = [
device.full_tracking_device_id

View File

@@ -167,7 +167,7 @@ async def async_setup(hass, config):
tasks = [_setup_atv(hass, config, conf) for conf in config.get(DOMAIN, [])]
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks)
hass.services.async_register(
DOMAIN, SERVICE_SCAN, async_service_handler,

View File

@@ -21,11 +21,11 @@
},
"totp": {
"error": {
"invalid_code": "C\u00f3digo inv\u00e1lido, por favor int\u00e9ntalo de nuevo. Si recibes este error de forma consistente, por favor aseg\u00farate de que el reloj de tu Home Assistant es correcto."
"invalid_code": "C\u00f3digo inv\u00e1lido, int\u00e9ntalo de nuevo. Si recibes este error de forma consistente, aseg\u00farate de que el reloj de tu sistema Home Assistant es correcto."
},
"step": {
"init": {
"description": "Para activar la autenticaci\u00f3n de dos factores utilizando contrase\u00f1as de un solo uso basadas en el tiempo, escanea el c\u00f3digo QR con tu aplicaci\u00f3n de autenticaci\u00f3n. Si no tienes una, te recomendamos [Autenticador de Google] (https://support.google.com/accounts/answer/1066447) o [Authy] (https://authy.com/). \n\n {qr_code} \n \nDespu\u00e9s de escanear el c\u00f3digo, introduce el c\u00f3digo de seis d\u00edgitos de tu aplicaci\u00f3n para verificar la configuraci\u00f3n. Si tienes problemas para escanear el c\u00f3digo QR, realiza una configuraci\u00f3n manual con el c\u00f3digo ** ` {code} ` **.",
"description": "Para activar la autenticaci\u00f3n de dos factores utilizando contrase\u00f1as de un solo uso basadas en el tiempo, escanea el c\u00f3digo QR con tu aplicaci\u00f3n de autenticaci\u00f3n. Si no tienes una, te recomendamos el [Autenticador de Google](https://support.google.com/accounts/answer/1066447) o [Authy](https://authy.com/). \n\n {qr_code} \n \nDespu\u00e9s de escanear el c\u00f3digo, introduce el c\u00f3digo de seis d\u00edgitos de tu aplicaci\u00f3n para verificar la configuraci\u00f3n. Si tienes problemas para escanear el c\u00f3digo QR, realiza una configuraci\u00f3n manual con el c\u00f3digo **`{code}`**.",
"title": "Configure la autenticaci\u00f3n de dos factores utilizando TOTP"
}
},

View File

@@ -6,7 +6,6 @@ from html.parser import HTMLParser
from urllib.parse import urlparse, urljoin
import aiohttp
from aiohttp.client_exceptions import ClientError
from homeassistant.util.network import is_local
@@ -81,8 +80,22 @@ async def fetch_redirect_uris(hass, url):
if chunks == 10:
break
except (asyncio.TimeoutError, ClientError) as ex:
_LOGGER.error("Error while looking up redirect_uri %s: %s", url, ex)
except asyncio.TimeoutError:
_LOGGER.error("Timeout while looking up redirect_uri %s", url)
pass
except aiohttp.client_exceptions.ClientSSLError:
_LOGGER.error("SSL error while looking up redirect_uri %s", url)
pass
except aiohttp.client_exceptions.ClientOSError as ex:
_LOGGER.error("OS error while looking up redirect_uri %s: %s", url,
ex.strerror)
pass
except aiohttp.client_exceptions.ClientConnectionError:
_LOGGER.error(("Low level connection error while looking up "
"redirect_uri %s"), url)
pass
except aiohttp.client_exceptions.ClientError:
_LOGGER.error("Unknown error while looking up redirect_uri %s", url)
pass
# Authorization endpoints verifying that a redirect_uri is allowed for use

View File

@@ -97,8 +97,7 @@ class AuthProvidersView(HomeAssistantView):
async def get(self, request):
"""Get available auth providers."""
hass = request.app['hass']
if not hass.components.onboarding.async_is_onboarded():
if not hass.components.onboarding.async_is_user_onboarded():
return self.json_message(
message='Onboarding not finished',
status_code=400,

View File

@@ -124,7 +124,7 @@ async def async_setup(hass, config):
context=service_call.context))
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks)
async def turn_onoff_service_handler(service_call):
"""Handle automation turn on/off service calls."""
@@ -134,7 +134,7 @@ async def async_setup(hass, config):
tasks.append(getattr(entity, method)())
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks)
async def toggle_service_handler(service_call):
"""Handle automation toggle service calls."""
@@ -146,7 +146,7 @@ async def async_setup(hass, config):
tasks.append(entity.async_turn_on())
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
await asyncio.wait(tasks)
async def reload_service_handler(service_call):
"""Remove all automations and load new ones from config."""

View File

@@ -31,6 +31,6 @@ async def async_trigger(hass, config, action, automation_info):
'from_state': from_s,
'to_state': to_s,
},
}, context=to_s.context))
}, context=(to_s.context if to_s else None)))
return async_track_template(hass, value_template, template_listener)

View File

@@ -166,14 +166,14 @@ async def _validate_aws_credentials(hass, credential):
profile = aws_config.get(CONF_PROFILE_NAME)
if profile is not None:
session = aiobotocore.AioSession(profile=profile, loop=hass.loop)
session = aiobotocore.AioSession(profile=profile)
del aws_config[CONF_PROFILE_NAME]
if CONF_ACCESS_KEY_ID in aws_config:
del aws_config[CONF_ACCESS_KEY_ID]
if CONF_SECRET_ACCESS_KEY in aws_config:
del aws_config[CONF_SECRET_ACCESS_KEY]
else:
session = aiobotocore.AioSession(loop=hass.loop)
session = aiobotocore.AioSession()
if credential[CONF_VALIDATE]:
async with session.create_client("iam", **aws_config) as client:

View File

@@ -94,10 +94,10 @@ async def async_get_service(hass, config, discovery_info=None):
if session is None:
profile = aws_config.get(CONF_PROFILE_NAME)
if profile is not None:
session = aiobotocore.AioSession(profile=profile, loop=hass.loop)
session = aiobotocore.AioSession(profile=profile)
del aws_config[CONF_PROFILE_NAME]
else:
session = aiobotocore.AioSession(loop=hass.loop)
session = aiobotocore.AioSession()
aws_config[CONF_REGION] = region_name

View File

@@ -0,0 +1,18 @@
{
"config": {
"error": {
"device_unavailable": "Apparaat is niet beschikbaar",
"faulty_credentials": "Ongeldige gebruikersreferenties"
},
"step": {
"user": {
"data": {
"host": "Host",
"password": "Wachtwoord",
"port": "Poort",
"username": "Gebruikersnaam"
}
}
}
}
}

View File

@@ -2,7 +2,8 @@
"config": {
"abort": {
"already_configured": "Enheten \u00e4r redan konfigurerad",
"bad_config_file": "Felaktig data fr\u00e5n config fil"
"bad_config_file": "Felaktig data fr\u00e5n config fil",
"link_local_address": "Link local addresses are not supported"
},
"error": {
"already_configured": "Enheten \u00e4r redan konfigurerad",
@@ -17,7 +18,7 @@
"port": "Port",
"username": "Anv\u00e4ndarnamn"
},
"title": "Konfigurera Axis enhet"
"title": "Konfigurera Axis-enhet"
}
},
"title": "Axis enhet"

View File

@@ -0,0 +1,86 @@
"""Base classes for Axis entities."""
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from .const import DOMAIN as AXIS_DOMAIN
class AxisEntityBase(Entity):
"""Base common to all Axis entities."""
def __init__(self, device):
"""Initialize the Axis event."""
self.device = device
self.unsub_dispatcher = []
async def async_added_to_hass(self):
"""Subscribe device events."""
self.unsub_dispatcher.append(async_dispatcher_connect(
self.hass, self.device.event_reachable, self.update_callback))
async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe device events when removed."""
for unsub_dispatcher in self.unsub_dispatcher:
unsub_dispatcher()
@property
def available(self):
"""Return True if device is available."""
return self.device.available
@property
def device_info(self):
"""Return a device description for device registry."""
return {
'identifiers': {(AXIS_DOMAIN, self.device.serial)}
}
@callback
def update_callback(self, no_delay=None):
"""Update the entities state."""
self.async_schedule_update_ha_state()
class AxisEventBase(AxisEntityBase):
"""Base common to all Axis entities from event stream."""
def __init__(self, event, device):
"""Initialize the Axis event."""
super().__init__(device)
self.event = event
async def async_added_to_hass(self) -> None:
"""Subscribe sensors events."""
self.event.register_callback(self.update_callback)
await super().async_added_to_hass()
async def async_will_remove_from_hass(self) -> None:
"""Disconnect device object when removed."""
self.event.remove_callback(self.update_callback)
await super().async_will_remove_from_hass()
@property
def device_class(self):
"""Return the class of the event."""
return self.event.CLASS
@property
def name(self):
"""Return the name of the event."""
return '{} {} {}'.format(
self.device.name, self.event.TYPE, self.event.id)
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def unique_id(self):
"""Return a unique identifier for this device."""
return '{}-{}-{}'.format(
self.device.serial, self.event.topic, self.event.id)

View File

@@ -2,6 +2,8 @@
from datetime import timedelta
from axis.event_stream import CLASS_INPUT, CLASS_OUTPUT
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.const import CONF_MAC, CONF_TRIGGER_TIME
from homeassistant.core import callback
@@ -9,7 +11,8 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.util.dt import utcnow
from .const import DOMAIN as AXIS_DOMAIN, LOGGER
from .axis_base import AxisEventBase
from .const import DOMAIN as AXIS_DOMAIN
async def async_setup_entry(hass, config_entry, async_add_entities):
@@ -21,32 +24,21 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
def async_add_sensor(event_id):
"""Add binary sensor from Axis device."""
event = device.api.event.events[event_id]
async_add_entities([AxisBinarySensor(event, device)], True)
if event.CLASS != CLASS_OUTPUT:
async_add_entities([AxisBinarySensor(event, device)], True)
device.listeners.append(async_dispatcher_connect(
hass, device.event_new_sensor, async_add_sensor))
class AxisBinarySensor(BinarySensorDevice):
class AxisBinarySensor(AxisEventBase, BinarySensorDevice):
"""Representation of a binary Axis event."""
def __init__(self, event, device):
"""Initialize the Axis binary sensor."""
self.event = event
self.device = device
super().__init__(event, device)
self.remove_timer = None
self.unsub_dispatcher = None
async def async_added_to_hass(self):
"""Subscribe sensors events."""
self.event.register_callback(self.update_callback)
self.unsub_dispatcher = async_dispatcher_connect(
self.hass, self.device.event_reachable, self.update_callback)
async def async_will_remove_from_hass(self) -> None:
"""Disconnect device object when removed."""
self.event.remove_callback(self.update_callback)
self.unsub_dispatcher()
@callback
def update_callback(self, no_delay=False):
@@ -67,7 +59,6 @@ class AxisBinarySensor(BinarySensorDevice):
@callback
def _delay_update(now):
"""Timer callback for sensor update."""
LOGGER.debug("%s called delayed (%s sec) update", self.name, delay)
self.async_schedule_update_ha_state()
self.remove_timer = None
@@ -83,32 +74,10 @@ class AxisBinarySensor(BinarySensorDevice):
@property
def name(self):
"""Return the name of the event."""
return '{} {} {}'.format(
self.device.name, self.event.TYPE, self.event.id)
if self.event.CLASS == CLASS_INPUT and self.event.id and \
self.device.api.vapix.ports[self.event.id].name:
return '{} {}'.format(
self.device.name,
self.device.api.vapix.ports[self.event.id].name)
@property
def device_class(self):
"""Return the class of the event."""
return self.event.CLASS
@property
def unique_id(self):
"""Return a unique identifier for this device."""
return '{}-{}-{}'.format(
self.device.serial, self.event.topic, self.event.id)
def available(self):
"""Return True if device is available."""
return self.device.available
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def device_info(self):
"""Return a device description for device registry."""
return {
'identifiers': {(AXIS_DOMAIN, self.device.serial)}
}
return super().name

View File

@@ -6,9 +6,9 @@ from homeassistant.components.mjpeg.camera import (
from homeassistant.const import (
CONF_AUTHENTICATION, CONF_DEVICE, CONF_HOST, CONF_MAC, CONF_NAME,
CONF_PASSWORD, CONF_PORT, CONF_USERNAME, HTTP_DIGEST_AUTHENTICATION)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .axis_base import AxisEntityBase
from .const import DOMAIN as AXIS_DOMAIN
AXIS_IMAGE = 'http://{}:{}/axis-cgi/jpg/image.cgi'
@@ -38,65 +38,40 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities([AxisCamera(config, device)])
class AxisCamera(MjpegCamera):
class AxisCamera(AxisEntityBase, MjpegCamera):
"""Representation of a Axis camera."""
def __init__(self, config, device):
"""Initialize Axis Communications camera component."""
super().__init__(config)
self.device_config = config
self.device = device
self.port = device.config_entry.data[CONF_DEVICE][CONF_PORT]
self.unsub_dispatcher = []
AxisEntityBase.__init__(self, device)
MjpegCamera.__init__(self, config)
async def async_added_to_hass(self):
"""Subscribe camera events."""
self.unsub_dispatcher.append(async_dispatcher_connect(
self.hass, self.device.event_new_address, self._new_address))
self.unsub_dispatcher.append(async_dispatcher_connect(
self.hass, self.device.event_reachable, self.update_callback))
async def async_will_remove_from_hass(self) -> None:
"""Disconnect device object when removed."""
for unsub_dispatcher in self.unsub_dispatcher:
unsub_dispatcher()
await super().async_added_to_hass()
@property
def supported_features(self):
"""Return supported features."""
return SUPPORT_STREAM
@property
def stream_source(self):
async def stream_source(self):
"""Return the stream source."""
return AXIS_STREAM.format(
self.device.config_entry.data[CONF_DEVICE][CONF_USERNAME],
self.device.config_entry.data[CONF_DEVICE][CONF_PASSWORD],
self.device.host)
@callback
def update_callback(self, no_delay=None):
"""Update the cameras state."""
self.async_schedule_update_ha_state()
@property
def available(self):
"""Return True if device is available."""
return self.device.available
def _new_address(self):
"""Set new device address for video stream."""
self._mjpeg_url = AXIS_VIDEO.format(self.device.host, self.port)
self._still_image_url = AXIS_IMAGE.format(self.device.host, self.port)
port = self.device.config_entry.data[CONF_DEVICE][CONF_PORT]
self._mjpeg_url = AXIS_VIDEO.format(self.device.host, port)
self._still_image_url = AXIS_IMAGE.format(self.device.host, port)
@property
def unique_id(self):
"""Return a unique identifier for this device."""
return '{}-camera'.format(self.device.serial)
@property
def device_info(self):
"""Return a device description for device registry."""
return {
'identifiers': {(AXIS_DOMAIN, self.device.serial)}
}

View File

@@ -146,7 +146,7 @@ class AxisFlowHandler(config_entries.ConfigFlow):
entry.data[CONF_DEVICE][CONF_HOST] = host
self.hass.config_entries.async_update_entry(entry)
async def async_step_discovery(self, discovery_info):
async def async_step_zeroconf(self, discovery_info):
"""Prepare configuration for a discovered Axis device.
This flow is triggered by the discovery component.

View File

@@ -1,7 +1,7 @@
"""Constants for the Axis component."""
import logging
LOGGER = logging.getLogger('homeassistant.components.axis')
LOGGER = logging.getLogger(__package__)
DOMAIN = 'axis'

View File

@@ -83,19 +83,23 @@ class AxisNetworkDevice:
self.product_type = self.api.vapix.params.prodtype
if self.config_entry.options[CONF_CAMERA]:
self.hass.async_create_task(
self.hass.config_entries.async_forward_entry_setup(
self.config_entry, 'camera'))
if self.config_entry.options[CONF_EVENTS]:
task = self.hass.async_create_task(
self.hass.config_entries.async_forward_entry_setup(
self.config_entry, 'binary_sensor'))
self.api.stream.connection_status_callback = \
self.async_connection_status_callback
self.api.enable_events(event_callback=self.async_event_callback)
task.add_done_callback(self.start)
platform_tasks = [
self.hass.config_entries.async_forward_entry_setup(
self.config_entry, platform)
for platform in ['binary_sensor', 'switch']
]
self.hass.async_create_task(self.start(platform_tasks))
self.config_entry.add_update_listener(self.async_new_address_callback)
@@ -145,9 +149,9 @@ class AxisNetworkDevice:
if action == 'add':
async_dispatcher_send(self.hass, self.event_new_sensor, event_id)
@callback
def start(self, fut):
"""Start the event stream."""
async def start(self, platform_tasks):
"""Start the event stream when all platforms are loaded."""
await asyncio.gather(*platform_tasks)
self.api.start()
@callback
@@ -157,15 +161,22 @@ class AxisNetworkDevice:
async def async_reset(self):
"""Reset this device to default state."""
self.api.stop()
platform_tasks = []
if self.config_entry.options[CONF_CAMERA]:
await self.hass.config_entries.async_forward_entry_unload(
self.config_entry, 'camera')
platform_tasks.append(
self.hass.config_entries.async_forward_entry_unload(
self.config_entry, 'camera'))
if self.config_entry.options[CONF_EVENTS]:
await self.hass.config_entries.async_forward_entry_unload(
self.config_entry, 'binary_sensor')
self.api.stop()
platform_tasks += [
self.hass.config_entries.async_forward_entry_unload(
self.config_entry, platform)
for platform in ['binary_sensor', 'switch']
]
await asyncio.gather(*platform_tasks)
for unsub_dispatcher in self.listeners:
unsub_dispatcher()
@@ -185,13 +196,22 @@ async def get_device(hass, config):
port=config[CONF_PORT], web_proto='http')
device.vapix.initialize_params(preload_data=False)
device.vapix.initialize_ports()
try:
with async_timeout.timeout(15):
await hass.async_add_executor_job(
device.vapix.params.update_brand)
await hass.async_add_executor_job(
device.vapix.params.update_properties)
await asyncio.gather(
hass.async_add_executor_job(
device.vapix.params.update_brand),
hass.async_add_executor_job(
device.vapix.params.update_properties),
hass.async_add_executor_job(
device.vapix.ports.update)
)
return device
except axis.Unauthorized:

View File

@@ -1,8 +1,10 @@
{
"domain": "axis",
"name": "Axis",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/axis",
"requirements": ["axis==22"],
"requirements": ["axis==23"],
"dependencies": [],
"zeroconf": ["_axis-video._tcp.local."],
"codeowners": ["@kane610"]
}

View File

@@ -0,0 +1,59 @@
"""Support for Axis switches."""
from axis.event_stream import CLASS_OUTPUT
from homeassistant.components.switch import SwitchDevice
from homeassistant.const import CONF_MAC
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .axis_base import AxisEventBase
from .const import DOMAIN as AXIS_DOMAIN
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Axis switch."""
serial_number = config_entry.data[CONF_MAC]
device = hass.data[AXIS_DOMAIN][serial_number]
@callback
def async_add_switch(event_id):
"""Add switch from Axis device."""
event = device.api.event.events[event_id]
if event.CLASS == CLASS_OUTPUT:
async_add_entities([AxisSwitch(event, device)], True)
device.listeners.append(async_dispatcher_connect(
hass, device.event_new_sensor, async_add_switch))
class AxisSwitch(AxisEventBase, SwitchDevice):
"""Representation of a Axis switch."""
@property
def is_on(self):
"""Return true if event is active."""
return self.event.is_tripped
async def async_turn_on(self, **kwargs):
"""Turn on switch."""
action = '/'
await self.hass.async_add_executor_job(
self.device.api.vapix.ports[self.event.id].action, action)
async def async_turn_off(self, **kwargs):
"""Turn off switch."""
action = '\\'
await self.hass.async_add_executor_job(
self.device.api.vapix.ports[self.event.id].action, action)
@property
def name(self):
"""Return the name of the event."""
if self.event.id and self.device.api.vapix.ports[self.event.id].name:
return '{} {}'.format(
self.device.name,
self.device.api.vapix.ports[self.event.id].name)
return super().name

View File

@@ -0,0 +1,80 @@
"""Support for Azure Event Hubs."""
import json
import logging
from typing import Any, Dict
import voluptuous as vol
from azure.eventhub import EventData, EventHubClientAsync
from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP, EVENT_STATE_CHANGED, STATE_UNAVAILABLE,
STATE_UNKNOWN)
from homeassistant.core import Event, HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entityfilter import FILTER_SCHEMA
from homeassistant.helpers.json import JSONEncoder
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'azure_event_hub'
CONF_EVENT_HUB_NAMESPACE = 'event_hub_namespace'
CONF_EVENT_HUB_INSTANCE_NAME = 'event_hub_instance_name'
CONF_EVENT_HUB_SAS_POLICY = 'event_hub_sas_policy'
CONF_EVENT_HUB_SAS_KEY = 'event_hub_sas_key'
CONF_FILTER = 'filter'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_EVENT_HUB_NAMESPACE): cv.string,
vol.Required(CONF_EVENT_HUB_INSTANCE_NAME): cv.string,
vol.Required(CONF_EVENT_HUB_SAS_POLICY): cv.string,
vol.Required(CONF_EVENT_HUB_SAS_KEY): cv.string,
vol.Required(CONF_FILTER): FILTER_SCHEMA,
}),
}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass: HomeAssistant, yaml_config: Dict[str, Any]):
"""Activate Azure EH component."""
config = yaml_config[DOMAIN]
event_hub_address = "amqps://{}.servicebus.windows.net/{}".format(
config[CONF_EVENT_HUB_NAMESPACE],
config[CONF_EVENT_HUB_INSTANCE_NAME])
entities_filter = config[CONF_FILTER]
client = EventHubClientAsync(
event_hub_address,
debug=True,
username=config[CONF_EVENT_HUB_SAS_POLICY],
password=config[CONF_EVENT_HUB_SAS_KEY])
async_sender = client.add_async_sender()
await client.run_async()
encoder = JSONEncoder()
async def async_send_to_event_hub(event: Event):
"""Send states to Event Hub."""
state = event.data.get('new_state')
if (state is None
or state.state in (STATE_UNKNOWN, '', STATE_UNAVAILABLE)
or not entities_filter(state.entity_id)):
return
event_data = EventData(
json.dumps(
obj=state.as_dict(),
default=encoder.encode
).encode('utf-8')
)
await async_sender.send(event_data)
async def async_shutdown(event: Event):
"""Shut down the client."""
await client.stop_async()
hass.bus.async_listen(EVENT_STATE_CHANGED, async_send_to_event_hub)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_shutdown)
return True

View File

@@ -0,0 +1,8 @@
{
"domain": "azure_event_hub",
"name": "Azure Event Hub",
"documentation": "https://www.home-assistant.io/components/azure_event_hub",
"requirements": ["azure-eventhub==1.3.1"],
"dependencies": [],
"codeowners": ["@eavanvalkenburg"]
}

View File

@@ -0,0 +1 @@
"""The Bizkaibus bus tracker component."""

View File

@@ -0,0 +1,8 @@
{
"domain": "bizkaibus",
"name": "Bizkaibus",
"documentation": "https://www.home-assistant.io/components/bizkaibus",
"dependencies": [],
"codeowners": ["@UgaitzEtxebarria"],
"requirements": ["bizkaibus==0.1.1"]
}

View File

@@ -0,0 +1,88 @@
"""Support for Bizkaibus, Biscay (Basque Country, Spain) Bus service."""
import logging
import voluptuous as vol
from bizkaibus.bizkaibus import BizkaibusData
import homeassistant.helpers.config_validation as cv
from homeassistant.const import CONF_NAME
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
ATTR_DUE_IN = 'Due in'
CONF_STOP_ID = 'stopid'
CONF_ROUTE = 'route'
DEFAULT_NAME = 'Next bus'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_STOP_ID): cv.string,
vol.Required(CONF_ROUTE): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Bizkaibus public transport sensor."""
name = config.get(CONF_NAME)
stop = config[CONF_STOP_ID]
route = config[CONF_ROUTE]
data = Bizkaibus(stop, route)
add_entities([BizkaibusSensor(data, stop, route, name)], True)
class BizkaibusSensor(Entity):
"""The class for handling the data."""
def __init__(self, data, stop, route, name):
"""Initialize the sensor."""
self.data = data
self.stop = stop
self.route = route
self._name = name
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def unit_of_measurement(self):
"""Return the unit of measurement of the sensor."""
return 'minutes'
def update(self):
"""Get the latest data from the webservice."""
self.data.update()
try:
self._state = self.data.info[0][ATTR_DUE_IN]
except TypeError:
pass
class Bizkaibus:
"""The class for handling the data retrieval."""
def __init__(self, stop, route):
"""Initialize the data object."""
self.stop = stop
self.route = route
self.info = None
def update(self):
"""Retrieve the information from API."""
bridge = BizkaibusData(self.stop, self.route)
bridge.getNextBus()
self.info = bridge.info

View File

@@ -8,7 +8,7 @@ from homeassistant.helpers import (
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)
CONF_MONITORED_CONDITIONS, CONF_MODE, CONF_OFFSET, TEMP_FAHRENHEIT)
_LOGGER = logging.getLogger(__name__)
@@ -41,7 +41,7 @@ BINARY_SENSORS = {
SENSORS = {
TYPE_TEMPERATURE: ['Temperature', TEMP_FAHRENHEIT, 'mdi:thermometer'],
TYPE_BATTERY: ['Battery', '%', 'mdi:battery-80'],
TYPE_BATTERY: ['Battery', '', 'mdi:battery-80'],
TYPE_WIFI_STRENGTH: ['Wifi Signal', 'dBm', 'mdi:wifi-strength-2'],
}
@@ -75,6 +75,8 @@ CONFIG_SCHEMA = vol.Schema(
vol.Optional(CONF_BINARY_SENSORS, default={}):
BINARY_SENSOR_SCHEMA,
vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA,
vol.Optional(CONF_OFFSET, default=1): int,
vol.Optional(CONF_MODE, default=''): cv.string,
})
},
extra=vol.ALLOW_EXTRA)
@@ -87,8 +89,12 @@ def setup(hass, config):
username = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]
scan_interval = conf[CONF_SCAN_INTERVAL]
is_legacy = bool(conf[CONF_MODE] == 'legacy')
motion_interval = conf[CONF_OFFSET]
hass.data[BLINK_DATA] = blinkpy.Blink(username=username,
password=password)
password=password,
motion_interval=motion_interval,
legacy_subdomain=is_legacy)
hass.data[BLINK_DATA].refresh_rate = scan_interval.total_seconds()
hass.data[BLINK_DATA].start()

View File

@@ -3,7 +3,7 @@
"name": "Blink",
"documentation": "https://www.home-assistant.io/components/blink",
"requirements": [
"blinkpy==0.13.1"
"blinkpy==0.14.0"
],
"dependencies": [],
"codeowners": [

View File

@@ -3,7 +3,7 @@
"name": "Bluesound",
"documentation": "https://www.home-assistant.io/components/bluesound",
"requirements": [
"xmltodict==0.11.0"
"xmltodict==0.12.0"
],
"dependencies": [],
"codeowners": []

View File

@@ -255,7 +255,7 @@ class BluesoundPlayer(MediaPlayerDevice):
BluesoundPlayer._TimeoutException):
_LOGGER.info("Node %s is offline, retrying later", self._name)
await asyncio.sleep(
NODE_OFFLINE_CHECK_TIMEOUT, loop=self._hass.loop)
NODE_OFFLINE_CHECK_TIMEOUT)
self.start_polling()
except CancelledError:
@@ -318,7 +318,7 @@ class BluesoundPlayer(MediaPlayerDevice):
try:
websession = async_get_clientsession(self._hass)
with async_timeout.timeout(10, loop=self._hass.loop):
with async_timeout.timeout(10):
response = await websession.get(url)
if response.status == 200:
@@ -361,7 +361,7 @@ class BluesoundPlayer(MediaPlayerDevice):
try:
with async_timeout.timeout(125, loop=self._hass.loop):
with async_timeout.timeout(125):
response = await self._polling_session.get(
url, headers={CONNECTION: KEEP_ALIVE})
@@ -378,7 +378,7 @@ class BluesoundPlayer(MediaPlayerDevice):
self._group_name = group_name
# the sleep is needed to make sure that the
# devices is synced
await asyncio.sleep(1, loop=self._hass.loop)
await asyncio.sleep(1)
await self.async_trigger_sync_on_all()
elif self.is_grouped:
# when player is grouped we need to fetch volume from

View File

@@ -2,12 +2,15 @@
import logging
from homeassistant.helpers.event import track_point_in_utc_time
from homeassistant.components.device_tracker import (
YAML_DEVICES, CONF_TRACK_NEW, CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL,
load_config, SOURCE_TYPE_BLUETOOTH_LE
from homeassistant.components.device_tracker.legacy import (
YAML_DEVICES, async_load_config
)
from homeassistant.components.device_tracker.const import (
CONF_TRACK_NEW, CONF_SCAN_INTERVAL, SCAN_INTERVAL, SOURCE_TYPE_BLUETOOTH_LE
)
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
import homeassistant.util.dt as dt_util
from homeassistant.util.async_ import run_coroutine_threadsafe
_LOGGER = logging.getLogger(__name__)
@@ -79,7 +82,10 @@ def setup_scanner(hass, config, see, discovery_info=None):
# Load all known devices.
# We just need the devices so set consider_home and home range
# to 0
for device in load_config(yaml_path, hass, 0):
for device in run_coroutine_threadsafe(
async_load_config(yaml_path, hass, 0),
hass.loop
).result():
# check if device is a valid bluetooth device
if device.mac and device.mac[:4].upper() == BLE_PREFIX:
if device.track:
@@ -97,7 +103,7 @@ def setup_scanner(hass, config, see, discovery_info=None):
_LOGGER.warning("No Bluetooth LE devices to track!")
return False
interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
def update_ble(now):
"""Lookup Bluetooth LE devices and update status."""

View File

@@ -5,11 +5,16 @@ import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import track_point_in_utc_time
from homeassistant.components.device_tracker import (
YAML_DEVICES, CONF_TRACK_NEW, CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL,
load_config, PLATFORM_SCHEMA, DEFAULT_TRACK_NEW, SOURCE_TYPE_BLUETOOTH,
DOMAIN)
from homeassistant.components.device_tracker import PLATFORM_SCHEMA
from homeassistant.components.device_tracker.legacy import (
YAML_DEVICES, async_load_config
)
from homeassistant.components.device_tracker.const import (
CONF_TRACK_NEW, CONF_SCAN_INTERVAL, SCAN_INTERVAL, DEFAULT_TRACK_NEW,
SOURCE_TYPE_BLUETOOTH, DOMAIN
)
import homeassistant.util.dt as dt_util
from homeassistant.util.async_ import run_coroutine_threadsafe
_LOGGER = logging.getLogger(__name__)
@@ -60,7 +65,10 @@ def setup_scanner(hass, config, see, discovery_info=None):
# Load all known devices.
# We just need the devices so set consider_home and home range
# to 0
for device in load_config(yaml_path, hass, 0):
for device in run_coroutine_threadsafe(
async_load_config(yaml_path, hass, 0),
hass.loop
).result():
# Check if device is a valid bluetooth device
if device.mac and device.mac[:3].upper() == BT_PREFIX:
if device.track:
@@ -77,7 +85,7 @@ def setup_scanner(hass, config, see, discovery_info=None):
devs_to_track.append(dev[0])
see_device(dev[0], dev[1])
interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
request_rssi = config.get(CONF_REQUEST_RSSI, False)

View File

@@ -3,7 +3,7 @@
"name": "Bom",
"documentation": "https://www.home-assistant.io/components/bom",
"requirements": [
"bomradarloop==0.1.2"
"bomradarloop==0.1.3"
],
"dependencies": [],
"codeowners": []

View File

@@ -3,7 +3,7 @@
"name": "Broadlink",
"documentation": "https://www.home-assistant.io/components/broadlink",
"requirements": [
"broadlink==0.9.0"
"broadlink==0.10.0"
],
"dependencies": [],
"codeowners": [

View File

@@ -1,7 +1,6 @@
"""Support for the Broadlink RM2 Pro (only temperature) and A1 devices."""
import binascii
import logging
import socket
from datetime import timedelta
import voluptuous as vol
@@ -60,6 +59,7 @@ class BroadlinkSensor(Entity):
"""Initialize the sensor."""
self._name = '{} {}'.format(name, SENSOR_TYPES[sensor_type][0])
self._state = None
self._is_available = False
self._type = sensor_type
self._broadlink_data = broadlink_data
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
@@ -74,6 +74,11 @@ class BroadlinkSensor(Entity):
"""Return the state of the sensor."""
return self._state
@property
def available(self):
"""Return True if entity is available."""
return self._is_available
@property
def unit_of_measurement(self):
"""Return the unit this state is expressed in."""
@@ -83,8 +88,11 @@ class BroadlinkSensor(Entity):
"""Get the latest data from the sensor."""
self._broadlink_data.update()
if self._broadlink_data.data is None:
self._state = None
self._is_available = False
return
self._state = self._broadlink_data.data[self._type]
self._is_available = True
class BroadlinkData:
@@ -119,8 +127,9 @@ class BroadlinkData:
if data is not None:
self.data = self._schema(data)
return
except socket.timeout as error:
except OSError as error:
if retry < 1:
self.data = None
_LOGGER.error(error)
return
except (vol.Invalid, vol.MultipleInvalid):
@@ -131,7 +140,7 @@ class BroadlinkData:
def _auth(self, retry=3):
try:
auth = self._device.auth()
except socket.timeout:
except OSError:
auth = False
if not auth and retry > 0:
self._connect()

View File

@@ -10,9 +10,10 @@ from homeassistant.components.switch import (
ENTITY_ID_FORMAT, PLATFORM_SCHEMA, SwitchDevice)
from homeassistant.const import (
CONF_COMMAND_OFF, CONF_COMMAND_ON, CONF_FRIENDLY_NAME, CONF_HOST, CONF_MAC,
CONF_SWITCHES, CONF_TIMEOUT, CONF_TYPE)
CONF_SWITCHES, CONF_TIMEOUT, CONF_TYPE, STATE_ON)
import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle, slugify
from homeassistant.helpers.restore_state import RestoreEntity
from . import async_setup_service, data_packet
@@ -109,13 +110,13 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
broadlink_device.timeout = config.get(CONF_TIMEOUT)
try:
broadlink_device.auth()
except socket.timeout:
except OSError:
_LOGGER.error("Failed to connect to device")
add_entities(switches)
class BroadlinkRMSwitch(SwitchDevice):
class BroadlinkRMSwitch(SwitchDevice, RestoreEntity):
"""Representation of an Broadlink switch."""
def __init__(self, name, friendly_name, device, command_on, command_off):
@@ -126,6 +127,14 @@ class BroadlinkRMSwitch(SwitchDevice):
self._command_on = command_on
self._command_off = command_off
self._device = device
self._is_available = False
async def async_added_to_hass(self):
"""Call when entity about to be added to hass."""
await super().async_added_to_hass()
state = await self.async_get_last_state()
if state:
self._state = state.state == STATE_ON
@property
def name(self):
@@ -137,6 +146,11 @@ class BroadlinkRMSwitch(SwitchDevice):
"""Return true if unable to access real state of entity."""
return True
@property
def available(self):
"""Return True if entity is available."""
return not self.should_poll or self._is_available
@property
def should_poll(self):
"""Return the polling state."""
@@ -166,7 +180,7 @@ class BroadlinkRMSwitch(SwitchDevice):
return True
try:
self._device.send_data(packet)
except (socket.timeout, ValueError) as error:
except (ValueError, OSError) as error:
if retry < 1:
_LOGGER.error("Error during sending a packet: %s", error)
return False
@@ -178,7 +192,7 @@ class BroadlinkRMSwitch(SwitchDevice):
def _auth(self, retry=2):
try:
auth = self._device.auth()
except socket.timeout:
except OSError:
auth = False
if retry < 1:
_LOGGER.error("Timeout during authorization")
@@ -244,6 +258,7 @@ class BroadlinkSP2Switch(BroadlinkSP1Switch):
except (socket.timeout, ValueError) as error:
if retry < 1:
_LOGGER.error("Error during updating the state: %s", error)
self._is_available = False
return
if not self._auth():
return
@@ -252,6 +267,7 @@ class BroadlinkSP2Switch(BroadlinkSP1Switch):
return self._update(retry-1)
self._state = state
self._load_power = load_power
self._is_available = True
class BroadlinkMP1Slot(BroadlinkRMSwitch):
@@ -277,10 +293,12 @@ class BroadlinkMP1Slot(BroadlinkRMSwitch):
except (socket.timeout, ValueError) as error:
if retry < 1:
_LOGGER.error("Error during sending a packet: %s", error)
self._is_available = False
return False
if not self._auth():
return False
return self._sendpacket(packet, max(0, retry-1))
self._is_available = True
return True
@property
@@ -330,7 +348,7 @@ class BroadlinkMP1Switch:
"""Authenticate the device."""
try:
auth = self._device.auth()
except socket.timeout:
except OSError:
auth = False
if not auth and retry > 0:
return self._auth(retry-1)

View File

@@ -388,7 +388,7 @@ class BrData:
tasks.append(dev.async_update_ha_state())
if tasks:
await asyncio.wait(tasks, loop=self.hass.loop)
await asyncio.wait(tasks)
async def schedule_update(self, minute=1):
"""Schedule an update after minute minutes."""
@@ -407,7 +407,7 @@ class BrData:
resp = None
try:
websession = async_get_clientsession(self.hass)
with async_timeout.timeout(10, loop=self.hass.loop):
with async_timeout.timeout(10):
resp = await websession.get(url)
result[STATUS_CODE] = resp.status

View File

@@ -8,7 +8,7 @@ import voluptuous as vol
from homeassistant.components.calendar import (
PLATFORM_SCHEMA, CalendarEventDevice, get_date)
from homeassistant.const import (
CONF_NAME, CONF_PASSWORD, CONF_URL, CONF_USERNAME)
CONF_NAME, CONF_PASSWORD, CONF_URL, CONF_USERNAME, CONF_VERIFY_SSL)
import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle, dt
@@ -36,7 +36,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_SEARCH): cv.string,
})
]))
])),
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean
})
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15)
@@ -50,7 +51,8 @@ def setup_platform(hass, config, add_entities, disc_info=None):
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
client = caldav.DAVClient(url, None, username, password)
client = caldav.DAVClient(url, None, username, password,
ssl_verify_cert=config.get(CONF_VERIFY_SSL))
calendars = client.principal().calendars()

View File

@@ -36,7 +36,7 @@ async def async_setup(hass, config):
hass.http.register_view(CalendarEventView(component))
# Doesn't work in prod builds of the frontend: home-assistant-polymer#1289
# await hass.components.frontend.async_register_built_in_panel(
# hass.components.frontend.async_register_built_in_panel(
# 'calendar', 'calendar', 'hass:calendar')
await component.async_setup(config)

View File

@@ -107,11 +107,14 @@ async def async_request_stream(hass, entity_id, fmt):
camera = _get_camera_from_entity_id(hass, entity_id)
camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id)
if not camera.stream_source:
async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support play stream service"
.format(camera.entity_id))
return request_stream(hass, camera.stream_source, fmt=fmt,
return request_stream(hass, source, fmt=fmt,
keepalive=camera_prefs.preload_stream)
@@ -121,7 +124,7 @@ async def async_get_image(hass, entity_id, timeout=10):
camera = _get_camera_from_entity_id(hass, entity_id)
with suppress(asyncio.CancelledError, asyncio.TimeoutError):
with async_timeout.timeout(timeout, loop=hass.loop):
async with async_timeout.timeout(timeout):
image = await camera.async_camera_image()
if image:
@@ -221,8 +224,16 @@ async def async_setup(hass, config):
async def preload_stream(hass, _):
for camera in component.entities:
camera_prefs = prefs.get(camera.entity_id)
if camera.stream_source and camera_prefs.preload_stream:
request_stream(hass, camera.stream_source, keepalive=True)
if not camera_prefs.preload_stream:
continue
async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
continue
request_stream(hass, source, keepalive=True)
async_when_setup(hass, DOMAIN_STREAM, preload_stream)
@@ -328,8 +339,7 @@ class Camera(Entity):
"""Return the interval between frames of the mjpeg stream."""
return 0.5
@property
def stream_source(self):
async def stream_source(self):
"""Return the source of the stream."""
return None
@@ -481,7 +491,7 @@ class CameraImageView(CameraView):
async def handle(self, request, camera):
"""Serve camera image."""
with suppress(asyncio.CancelledError, asyncio.TimeoutError):
with async_timeout.timeout(10, loop=request.app['hass'].loop):
async with async_timeout.timeout(10):
image = await camera.async_camera_image()
if image:
@@ -522,12 +532,10 @@ async def websocket_camera_thumbnail(hass, connection, msg):
"""
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')
}
))
await connection.send_big_result(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'))
@@ -549,18 +557,25 @@ async def ws_camera_stream(hass, connection, msg):
camera = _get_camera_from_entity_id(hass, entity_id)
camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id)
if not camera.stream_source:
async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support play stream service"
.format(camera.entity_id))
fmt = msg['format']
url = request_stream(hass, camera.stream_source, fmt=fmt,
url = request_stream(hass, source, fmt=fmt,
keepalive=camera_prefs.preload_stream)
connection.send_result(msg['id'], {'url': url})
except HomeAssistantError as ex:
_LOGGER.error(ex)
_LOGGER.error("Error requesting stream: %s", ex)
connection.send_error(
msg['id'], 'start_stream_failed', str(ex))
except asyncio.TimeoutError:
_LOGGER.error("Timeout getting stream source")
connection.send_error(
msg['id'], 'start_stream_failed', "Timeout getting stream source")
@websocket_api.async_response
@@ -624,7 +639,10 @@ async def async_handle_snapshot_service(camera, service):
async def async_handle_play_stream_service(camera, service_call):
"""Handle play stream services calls."""
if not camera.stream_source:
async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support play stream service"
.format(camera.entity_id))
@@ -633,7 +651,7 @@ async def async_handle_play_stream_service(camera, service_call):
fmt = service_call.data[ATTR_FORMAT]
entity_ids = service_call.data[ATTR_MEDIA_PLAYER]
url = request_stream(hass, camera.stream_source, fmt=fmt,
url = request_stream(hass, source, fmt=fmt,
keepalive=camera_prefs.preload_stream)
data = {
ATTR_ENTITY_ID: entity_ids,
@@ -648,7 +666,10 @@ async def async_handle_play_stream_service(camera, service_call):
async def async_handle_record_service(camera, call):
"""Handle stream recording service calls."""
if not camera.stream_source:
async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support record service"
.format(camera.entity_id))
@@ -659,7 +680,7 @@ async def async_handle_record_service(camera, call):
variables={ATTR_ENTITY_ID: camera})
data = {
CONF_STREAM_SOURCE: camera.stream_source,
CONF_STREAM_SOURCE: source,
CONF_FILENAME: video_path,
CONF_DURATION: call.data[CONF_DURATION],
CONF_LOOKBACK: call.data[CONF_LOOKBACK],

View File

@@ -79,7 +79,7 @@ class CanaryCamera(Camera):
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)
extra_cmd=self._ffmpeg_arguments))
return image
async def handle_async_mjpeg_stream(self, request):

View File

@@ -1,8 +1,7 @@
"""Component to embed Google Cast."""
from homeassistant import config_entries
from homeassistant.helpers import config_entry_flow
DOMAIN = 'cast'
from .const import DOMAIN
async def async_setup(hass, config):
@@ -23,15 +22,3 @@ async def async_setup_entry(hass, entry):
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
entry, 'media_player'))
return True
async def _async_has_devices(hass):
"""Return if there are devices that can be discovered."""
from pychromecast.discovery import discover_chromecasts
return await hass.async_add_executor_job(discover_chromecasts)
config_entry_flow.register_discovery_flow(
DOMAIN, 'Google Cast', _async_has_devices,
config_entries.CONN_CLASS_LOCAL_PUSH)

View File

@@ -0,0 +1,16 @@
"""Config flow for Cast."""
from homeassistant.helpers import config_entry_flow
from homeassistant import config_entries
from .const import DOMAIN
async def _async_has_devices(hass):
"""Return if there are devices that can be discovered."""
from pychromecast.discovery import discover_chromecasts
return await hass.async_add_executor_job(discover_chromecasts)
config_entry_flow.register_discovery_flow(
DOMAIN, 'Google Cast', _async_has_devices,
config_entries.CONN_CLASS_LOCAL_PUSH)

View File

@@ -0,0 +1,3 @@
"""Consts for Cast integration."""
DOMAIN = 'cast'

View File

@@ -1,9 +1,10 @@
{
"domain": "cast",
"name": "Cast",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/cast",
"requirements": [
"pychromecast==3.2.0"
"pychromecast==3.2.1"
],
"dependencies": [],
"codeowners": []

View File

@@ -24,6 +24,7 @@ from homeassistant.helpers.dispatcher import (
async_dispatcher_connect, dispatcher_send)
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
import homeassistant.util.dt as dt_util
from homeassistant.util.logging import async_create_catching_coro
from . import DOMAIN as CAST_DOMAIN
@@ -522,8 +523,8 @@ class CastDevice(MediaPlayerDevice):
if _is_matching_dynamic_group(self._cast_info, discover):
_LOGGER.debug("Discovered matching dynamic group: %s",
discover)
self.hass.async_create_task(
self.async_set_dynamic_group(discover))
self.hass.async_create_task(async_create_catching_coro(
self.async_set_dynamic_group(discover)))
return
if self._cast_info.uuid != discover.uuid:
@@ -536,7 +537,8 @@ class CastDevice(MediaPlayerDevice):
self._cast_info.host, self._cast_info.port)
return
_LOGGER.debug("Discovered chromecast with same UUID: %s", discover)
self.hass.async_create_task(self.async_set_cast_info(discover))
self.hass.async_create_task(async_create_catching_coro(
self.async_set_cast_info(discover)))
def async_cast_removed(discover: ChromecastInfo):
"""Handle removal of Chromecast."""
@@ -546,13 +548,15 @@ class CastDevice(MediaPlayerDevice):
if (self._dynamic_group_cast_info is not None and
self._dynamic_group_cast_info.uuid == discover.uuid):
_LOGGER.debug("Removed matching dynamic group: %s", discover)
self.hass.async_create_task(self.async_del_dynamic_group())
self.hass.async_create_task(async_create_catching_coro(
self.async_del_dynamic_group()))
return
if self._cast_info.uuid != discover.uuid:
# Removed is not our device.
return
_LOGGER.debug("Removed chromecast with same UUID: %s", discover)
self.hass.async_create_task(self.async_del_cast_info(discover))
self.hass.async_create_task(async_create_catching_coro(
self.async_del_cast_info(discover)))
async def async_stop(event):
"""Disconnect socket on Home Assistant stop."""
@@ -565,14 +569,15 @@ class CastDevice(MediaPlayerDevice):
self.hass, SIGNAL_CAST_REMOVED,
async_cast_removed)
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop)
self.hass.async_create_task(self.async_set_cast_info(self._cast_info))
self.hass.async_create_task(async_create_catching_coro(
self.async_set_cast_info(self._cast_info)))
for info in self.hass.data[KNOWN_CHROMECAST_INFO_KEY]:
if _is_matching_dynamic_group(self._cast_info, info):
_LOGGER.debug("[%s %s (%s:%s)] Found dynamic group: %s",
self.entity_id, self._cast_info.friendly_name,
self._cast_info.host, self._cast_info.port, info)
self.hass.async_create_task(
self.async_set_dynamic_group(info))
self.hass.async_create_task(async_create_catching_coro(
self.async_set_dynamic_group(info)))
break
async def async_will_remove_from_hass(self) -> None:
@@ -659,7 +664,7 @@ class CastDevice(MediaPlayerDevice):
self.entity_id, self._cast_info.friendly_name,
self._cast_info.host, self._cast_info.port, cast_info)
self.async_del_dynamic_group()
await self.async_del_dynamic_group()
self._dynamic_group_cast_info = cast_info
# pylint: disable=protected-access
@@ -1046,6 +1051,11 @@ class CastDevice(MediaPlayerDevice):
return images[0].url if images and images[0].url else None
@property
def media_image_remotely_accessible(self) -> bool:
"""If the image url is remotely accessible."""
return True
@property
def media_title(self):
"""Title of current playing media."""

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