Compare commits

...

779 Commits

Author SHA1 Message Date
Pascal Vizeli
d4ae73ce38 Merge pull request #23620 from home-assistant/rc
0.92.2
2019-05-02 09:49:23 +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
Paulus Schoutsen
2dbe6d3289 Updated frontend to 20190427.0 2019-04-27 22:18:18 -07:00
Pascal Vizeli
ee107755f8 Merge pull request #23448 from home-assistant/rc
0.92.1
2019-04-26 22:41:20 +02:00
Pascal Vizeli
081a0290ba Bump version 0.91.1 2019-04-26 20:00:33 +00:00
Fredrik Erlandsson
95ed8fb245 Fix point setup (#23441)
Fix point setup
2019-04-26 19:58:46 +00:00
Fredrik Erlandsson
0d4858e296 Fix daikin setup (#23440)
Fix daikin setup
2019-04-26 19:58:46 +00:00
Toon Willems
f6a6be9a22 Fix Flux component (#23431)
* Fix Flux component

* Update manifest.json

* Update manifest.json
2019-04-26 19:58:45 +00:00
cgtobi
065b077369 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 19:58:44 +00:00
Andrew Sayre
1ec08ce243 Fix supported features gates in media_player volume up/down services (#23419)
* Correct media player feature gates

* Fix failing test

* Lint...
2019-04-26 19:58:44 +00:00
Andrew Sayre
46c955a501 Add missing feature support flag (#23417) 2019-04-26 19:58:43 +00:00
Paulus Schoutsen
c1429f5d80 Make setup more robust (#23414)
* Make setup more robust

* Fix typing
2019-04-26 19:58:42 +00:00
Joakim Plate
ed16681b8e 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-26 19:58:42 +00:00
Jason Hu
1ab03d9e15 Add error handling for migration failure (#23383) 2019-04-26 19:55:26 +00:00
Chuang Zheng
ffcaeb4ef1 async_setup_component stage_1_domains (#23375) 2019-04-26 19:55:25 +00:00
Andrew Sayre
dd1e352d1d Bump pyheos to 0.4.1 (#23360)
* Bump pyheos==0.4.1

* Refresh player after reconnection
2019-04-26 19:55:24 +00:00
Greg Laabs
3bfb5b119a 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-26 19:55:24 +00:00
dreed47
a269603e3b fix for issue #21381 (#23306) 2019-04-26 19:55:23 +00:00
Paulus Schoutsen
8ae2ce2299 Merge pull request #23353 from home-assistant/rc
0.92.0
2019-04-24 13:37:44 -07:00
Paulus Schoutsen
700b8b2d0c Fix config test when current version is 92 (#23356) 2019-04-24 13:37:19 -07:00
Paulus Schoutsen
806aba4a1a Bumped version to 0.92.0 2019-04-24 11:25:57 -07:00
Jason Hu
1128cf576f Remove ghost folder (#23350) 2019-04-24 11:25:02 -07:00
Jason Hu
febdb72fb2 Support unicode in configuration migration (#23335) 2019-04-24 11:25:00 -07:00
Paulus Schoutsen
3c0146d382 Add sensor and binary senseor to default expose (#23332) 2019-04-24 11:24:59 -07:00
Paulus Schoutsen
9e76293141 Always set latest pin (#23328) 2019-04-24 11:24:58 -07:00
dreed47
6149c2877d Zestimate - Added check for the existence of data in response (#23310) 2019-04-24 11:24:58 -07:00
Joakim Plate
2efe607b78 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-24 11:24:57 -07:00
Paulus Schoutsen
9fc271d178 Updated frontend to 20190424.0 2019-04-24 11:16:30 -07:00
Paulus Schoutsen
06f76e8e97 Bumped version to 0.92.0b3 2019-04-22 22:09:33 -07:00
Paulus Schoutsen
d5bd8b9405 Dont cache integrations that are not found (#23316) 2019-04-22 22:09:13 -07:00
Pascal Vizeli
34c03109e5 Fix hass.io panel_custom/frontend (#23313)
* Fix hass.io panel_custom/frontend

* Update manifest.json
2019-04-22 22:09:12 -07:00
Richard Mitchell
df3ceb8d87 Correct calculation and units of light level values. (#23309) 2019-04-22 22:09:12 -07:00
VDRainer
f514d44224 Create services.yaml for input_datetime (#23303)
* Create services.yaml for input_datetime

* HA error while parsing a flow mapping
2019-04-22 22:09:11 -07:00
Austin Mroczek
7fb0055a92 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 22:09:10 -07:00
Joakim Sørensen
f81eeded90 Show correct version for stable (#23291) 2019-04-22 22:09:10 -07:00
damarco
6df31da180 Bump zigpy and zigpy-xbee (#23275) 2019-04-22 22:09:09 -07:00
damarco
364f5c8c02 Bump zigpy-deconz (#23270) 2019-04-22 22:09:08 -07:00
Otto Winter
85ac85c959 Fix ESPHome setup errors in beta (#23242)
* Fix ESPHome setup errors in beta

* Update requirements_all.txt
2019-04-22 22:09:08 -07:00
Andrew Sayre
a2565ad3b4 Update pyheos and log service errors in HEOS integration (#23222)
* Update pyheos and command error handling

* Correct comment and remove unnecessary autospec
2019-04-22 22:09:07 -07:00
Jc2k
6d31d56c03 Backport missing folder fix from #23191 (#23297) 2019-04-22 12:07:03 -07:00
Paulus Schoutsen
ef28e2cc2a Bumped version to 0.92.0b2 2019-04-19 17:05:56 -07:00
Andrew Sayre
ff047e1cd1 Return 0 instead of None (#23261) 2019-04-19 17:05:46 -07:00
Paulus Schoutsen
8741a20191 Async fix for bluetooth stopping (#23225) 2019-04-19 17:05:45 -07:00
Paulus Schoutsen
d0c6f0b710 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 17:05:44 -07:00
cgtobi
15c1213928 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 17:05:44 -07:00
David F. Mulcahey
f618e7253a fix bindable devices (#23216) 2019-04-19 17:05:43 -07:00
David F. Mulcahey
5df57bbda5 update zha-quirks (#23215) 2019-04-19 17:05:43 -07:00
Paulus Schoutsen
4433ad0a06 Add stub services.yaml and make validation mandatory (#23213) 2019-04-19 17:05:42 -07:00
Alok Saboo
f18a49ce97 create services.yaml for shell_command (#23210) 2019-04-19 17:05:41 -07:00
Alok Saboo
23cb053e82 Create services.yaml for Tuya (#23209) 2019-04-19 17:05:41 -07:00
Richard Mitchell
52eb9e50aa 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 17:05:40 -07:00
Erik Montnemery
35da3f053c Fix clearing error message for MQTT vacuum (#23206)
* Fix clearing error message

* Remove redundant hass.async_block_till_done
2019-04-19 17:05:39 -07:00
Paulus Schoutsen
1a4a9532dd Add services.yaml validator (#23205)
* Add services.yaml validator

* Fix path
2019-04-19 17:05:39 -07:00
Robbie Trencheny
2bb772bbdc Set encoding before connecting (#23204) 2019-04-19 17:05:38 -07:00
Alok Saboo
ad5d4bbf51 Create services.yaml for python_script and script (#23201)
* Create services.yaml for python_script

* Create services.yaml for script
2019-04-19 17:05:38 -07:00
Otto Winter
9c9b25d4b9 Create empty services.yaml for esphome (#23200) 2019-04-19 17:05:37 -07:00
Paulus Schoutsen
89037b367b Don't load component when fetching translations (#23196) 2019-04-19 17:05:37 -07:00
Richard Mitchell
a3c3c41faa Hue motion senors are motion sensors, not presence sensors. (#23193) 2019-04-19 17:05:36 -07:00
Pascal Vizeli
7eebf4631d 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 17:05:35 -07:00
Dries De Peuter
decaabeb4a Fix niko home control dependency installation (#23176)
* Upgrade niko-home-control library

* Fix additional feedback

* Lint
2019-04-19 17:05:35 -07:00
David Bonnes
df02879c51 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-19 17:05:34 -07:00
Paulus Schoutsen
dbb49afb3e Updated frontend to 20190419.0 2019-04-19 17:05:08 -07:00
Paulus Schoutsen
25a5bd32e2 Bumped version to 0.92.0b1 2019-04-17 22:42:41 -07:00
Paulus Schoutsen
3665e87800 Don't warn for missing services (#23182) 2019-04-17 22:42:35 -07:00
Paulus Schoutsen
fa0d538358 Fix empty components (#23177) 2019-04-17 22:42:34 -07:00
Joakim Plate
c508d5905b 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:42:34 -07:00
Richard Mitchell
dc2cb62265 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:42:33 -07:00
Richard Mitchell
d0c3a8ecaf 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 22:42:33 -07:00
Paulus Schoutsen
9986df358a Bumped version to 0.92.0b0 2019-04-17 10:32:59 -07:00
Paulus Schoutsen
e75820fc97 Merge remote-tracking branch 'origin/master' into dev 2019-04-17 10:32:37 -07:00
Jasper van der Neut - Stulen
8e4e6a50d8 Only create sensors if the station actually has values for them. (#20643)
Because Luftdaten assigns separate ids for particle and weather
measurements, most if not all stations added with config flow will
have non-functional sensors, as mentioned in #19591. This change
prevents the creation of sensors without data.
2019-04-17 10:27:59 -07:00
Andrey "Limych" Khrolenok
2e57d48191 Adding Telegram bot leave_chat() service (#22259)
* Adding leave_chat() service

* Fix indent
2019-04-17 10:15:33 -07:00
Jc2k
a97fb8fd10 Support fetching/setting humidity of HomeKit controller thermostats (#23040)
* Add support for homekit humidity control

* Add tests
2019-04-17 10:03:32 -07:00
Jc2k
f7afd9d6bc Fix handling of homekit_controler zeroconf c# changes (#22995) 2019-04-17 10:02:51 -07:00
Jc2k
88455a8a8b homekit_controller: Support cover stop (#23046) 2019-04-17 10:02:04 -07:00
pbalogh77
7d4083cdd3 Changed scene unique IDs (#22987)
There was a potential unique ID collission which caused problems for some users, as scenes and devices are enumerated separately, so the same ID could be assigned to in they are unnamed.
So I changed the unique ID generation for scenes to avoid this, which is a breaking change wrt scenes.
2019-04-17 09:56:34 -07:00
Penny Wood
7a9c9031af I think this is a potential bug (#23157) 2019-04-17 09:52:08 -07:00
Paulus Schoutsen
6a40a712cd Install deps and reqs early for config flows (#23169) 2019-04-17 09:49:45 -07:00
Paulus Schoutsen
3d85999258 Updated frontend to 20190417.0 2019-04-17 09:48:59 -07:00
ThaStealth
5b33d952aa Added epson workforce component (#23144)
* Added epson workforce component

* Added __init__ file
2019-04-17 18:33:22 +02:00
Paulus Schoutsen
dcb4eb39fa Update translations 2019-04-17 09:31:34 -07:00
Pascal Vizeli
073f947ca4 Bump Home Assistant Cloud 0.12 (#23159)
* Home Assistant Cloud 0.12

* Fix raising error

* Fix requirements

* Fix lint
2019-04-17 06:57:26 -07:00
Robert Svensson
0b7e62f737 Axis change how new event is signalled (#23152) 2019-04-17 15:21:42 +02:00
Erik Eriksson
e114ae9b53 catch asyncio.TimeoutError (#23156) 2019-04-17 22:00:57 +09:00
trilu2000
b909e5823f Homematic Lock: state_uncertain attribute, Homematic dimmer: Light service transition attribute (#22928)
* STATE_UNCERTAIN for Homematic Lock devices introduced

Homematic Lock devices provides an uncertain flag if the lock was opened manually an the lock is uncertain regards the status.
The other necassary functionality was implemented in pyhomematic by Daniel earlier...

* enabled attribute transition in light service for homematic dimmer devices

* Update light.py

* Revert "Update light.py"

This reverts commit f5565a006d.

* Revert "Revert "Update light.py""

This reverts commit 2c264826ef.

* fix for line too long error

* trailing whitespace
2019-04-17 14:30:53 +02:00
Paulus Schoutsen
37ca9cabd1 Fix check config script (#23151)
* Fix check config script

* Fix typings

* Fix test
2019-04-16 17:14:25 -07:00
Joakim Plate
1bfccd803f Allow switches to be represented as outlets on google assistant (#23149)
* Add device class support for switch to support outlet type

* Add a test for cover device class sync

* Drop remnant unused import
2019-04-16 17:07:14 -07:00
GeoffAtHome
e02a5f0b31 Genius hub (#21598)
* Adding Genius Hub

* Added Genius hub

* Correct hound errors

* Correct hound errors.

* Correct tox errors.

* Fix travis errors

* Correct sensor names

* Correct travis errors

* Correct hound  errors

* Follow up from code review by Martin Hjelmare

* More changes from code review.

* Attempt to resolve conflicts in requirements_all

* de-lint for the houndci-bot

* better logging message, and small tidy-up

* minor refactor and de-lint

* domain name should be the same as the component name

* use self where appropriate

* minor de-lint

* add entities as a single call

* de-lint

* all read-only attrs almost done

* refactor - near the end

* change state/,ode mapping

* override temp from curr_temp

* all read-only properties working

* working now

* ready for PR, but need to remove logging

* de-lint

* de-linted, ready for merge

* de-linted, ready for merge 2

* didn't like import in climate/__init__

* improve footprint logic

* add manifest.json

* add manifest.json 2

* correct a regression

* fix regression with device.is_on()

* use latest client library

* update to latest client library, 3.3.6

* delint and shoudl be OK to go
2019-04-16 23:54:46 +02:00
Joakim Plate
4ed1d9ba8e Add target_temp_high/low and current_temperature (#21393)
* Add target_temp_high/low and current_temperature

water_heater piggy back on climate(thermostat) component in gui,
so these things are already supported by frontend for display
purposes.

* Drop support tags for target high/low
2019-04-16 14:37:27 -07:00
Mike Megally
d7183d642e update caldav to fix calendar issues with synology clients (#23145) 2019-04-16 14:30:40 -07:00
Jason Hu
308d1fbba0 Rename google/tts.py to google_translate/tts.py (#23090)
* Rename google/tts.py to google_translate/tts.py

* Move config migration before load config file

Migrate default config google tts to google_translate tts

* Revert change in process component config

* Fix tests
2019-04-16 14:27:07 -07:00
Paulus Schoutsen
ca524233ec Update components that can be used without being set up (#23133) 2019-04-16 14:11:58 -07:00
Otto Winter
3186109172 Simplify esphome (#22868)
* Add ESPHome climate support

* Adjust line length

* Update .coveragerc

* Update climate.py

* Simplify esphome integration

* Undo change

* Update cover.py
2019-04-16 13:48:46 -07:00
Paulus Schoutsen
10e8f4f70a Add support for after_dependencies (#23148)
* Add support for after_dependencies

* Remove assert false"

* Fix types
2019-04-16 13:40:21 -07:00
Nikolay Vasilchuk
7b1cbeaf80 Fix verify_ssl configuration (#23146)
Fix verify_ssl configuration
2019-04-16 11:55:12 -07:00
Dries De Peuter
45e5f5de78 Fix niko_home_control integration (#23093)
Update base library and only pull for state once.
2019-04-16 11:47:16 -07:00
Villhellm
177ae3fd32 Added state workaround exception for Kwikset 99100-078 (#23130)
I have verified that this does work with my lock.
2019-04-16 08:19:31 -04:00
Pascal Vizeli
6bb95f6b58 Merge pull request #23137 from home-assistant/rc
0.91.4
2019-04-16 10:53:12 +02:00
Pascal Vizeli
c90219ad2e Bumped version to 0.91.4 2019-04-16 08:47:36 +00:00
Robert Svensson
a45df7aac9 Axis - improved internal parameter handling (#23122)
Will result in faster startup per entry due to less network data
2019-04-16 10:46:29 +02:00
Pascal Vizeli
0e7a2f163c Fix ingress bug with Firefox (#23121)
* Fix ingress bug with Firefox

* Fix mock

* Fix tests

* Fix test lint
2019-04-16 08:44:30 +00:00
Jason Hunter
e7102eaf30 only preload when stream is setup (#23134) 2019-04-15 22:36:57 -07:00
Paulus Schoutsen
8b86bf7dd2 Load integrations only once (#23132) 2019-04-15 20:38:24 -07:00
Teemu R
f48eb913b3 Bump pyhs100 requirement for tplink integration (#23065)
* bump pyhs100 requirement for tplink integration

* Fixes #20994

* Run script/gen_requirements_all.py
2019-04-15 20:29:31 -04:00
Sidney
48138189b3 Fix flux_led only-white controllers (and remove explicit declaration as RGBW in automatic add) (#22210)
* Remove explicit declaration of automatic found devices as RGBW

* fixes for Magic Home only-white controllers

* mode is now set to None instead of removed entirely

* flux_led now changes no values when turned on from off state.

* better checking for changed values in turn_on

* Reduce waiting time to 1 second

* Correction of turn on logic

* Remove accidentally inserted 'not'

* Remove lint

* Remove redundant code
2019-04-15 17:07:15 -07:00
Paulus Schoutsen
6a2da9f9a5 load cleanups (#23112)
* load cleanups

* Remove unused methods

* Allow importing requirements at the top of a file

* Fix test

* Lint

* Install reqs ASAP when loading platforms
2019-04-15 16:45:46 -07:00
Fredrik Erlandsson
4d080f8b17 skip non existing zones (#23113) 2019-04-15 16:41:33 -07:00
Tim Lyakhovetskiy
9e15fc1376 Update Leviton Decora WiFi library version. (#23125) 2019-04-15 16:15:51 -07:00
zewelor
7bed448100 Update yeelight lib (#23123)
* Update yeelight lib

* Run gen requirements
2019-04-15 16:10:26 -07:00
Pascal Vizeli
7a78d65633 Fix ingress bug with Firefox (#23121)
* Fix ingress bug with Firefox

* Fix mock

* Fix tests

* Fix test lint
2019-04-15 15:27:13 -07:00
Robert Svensson
60c787c2e6 Axis component support unloading entries (#22692)
* Add support for unloading entries

* Improve config entry tests

* Improve coverage for device

* Remove callback when relevant
2019-04-15 15:06:45 -07:00
Andrew Loe
dbcdc32f05 Ensure Boolean configuration values are handled correctly. (#22810) 2019-04-15 14:24:20 -07:00
Michał Węgrzynek
7251e29e60 Add basic Supla cover support (#22133)
* Added basic Supla (https://www.supla.org) support (covers)

* PySupla upgrade, minor spelling corrections and .coveragerc update

* Linter errors cleanup

* More linter cleanups.

* Documentation link removal and import sorting

* Docstring formatting

* PR suggestions

* Styling and linting

* PySupla version update

* Removal of ALLOW_EXTRA in SERVER_CONFIG

* Return False on failed connection validation, function order cleanup

* Component manifest

* Missing return None and different way of setting unique_id

* CODEOWNERS update

* CircleCI nudge
2019-04-15 13:20:08 -07:00
Pascal Vizeli
8a4dd093f8 Add pvizeli/danielperna84 to code owner of homematic (#22989)
* Add pvizeli/danielperna84 to code owner of homematic

* Update CODEOWNERS

* Run hassfest
2019-04-15 13:13:29 -07:00
giefca
497038b332 Add Google Assistant garage type (#23115)
* Tests

* Add Google Assistant GARAGE type

* Update test_trait.py

* Key device class by domain

* Update smart_home.py
2019-04-15 13:05:53 -07:00
cgtobi
f5878e1f22 Clean coveragerc of removed integrations (#23118) 2019-04-15 10:58:37 -07:00
cgtobi
6ab158ba88 Bump pyatmo version (#23116) 2019-04-15 10:58:02 -07:00
Tsvi Mostovicz
d894025365 Lower verbosity of command line sensor (#23120)
The command line sensor prints every minute the command that is run. This fills up the log.
The command run should be a debug statement.
2019-04-15 10:56:32 -07:00
Jeff Irion
c341e33749 Handle missing 'serialno' of Android TV (#22996)
* Handle missing 'serialno' for unique ID

* Use None for unique_id if serialno is missing

* Remove name from unique ID

* Use serialno as unique_id
2019-04-15 10:28:58 -07:00
Robert Svensson
ec171b9928 Axis - start stream when system is ready (#23119)
* Make sure that event stream doesn't start until event listeners are ready

* Change order
2019-04-15 09:20:01 -07:00
Jc2k
e97b2b7015 Fix homekit_controller climate supported operation_list being blank (#23095)
* Fix tado supported operation modes when used with homekit_controller

* Replace with list comp as requested in review

* More list comps
2019-04-15 17:09:21 +02:00
Jason Hu
2f89f88d23 Load component which contains data entry flow handler (#23107)
* Load component which contains data entry flow handler

* Use integration.get_component()

* Add error log
2019-04-14 23:24:47 -07:00
Paulus Schoutsen
b0d893afc9 Remove loader.get_component (#23111)
* Remove get_component

* Lint
2019-04-14 22:31:01 -07:00
Robert Svensson
23cb579f9f Support updating deCONZ host address (#22784)
* Update config flow to support updating host address
Improve tests

* Update gateway to handle new address signal

* Improve description why whe need to keep step_init
2019-04-14 21:50:01 -07:00
Maikel Punie
96f689a70f Upgraded python-velbus package, this fixes a lot of problems with the… (#23100)
* Upgraded python-velbus package, this fixes a lot of problems with the velbus component

* updated manifest.json
2019-04-14 21:42:30 -07:00
giefca
b804919eaa Fix for stateless covers (#22962)
* Corrections and test

* Raise error if does not support setting position

* Raising error for stateless and assumed state covers

* Fix pylint

* Tests

* Update test_trait.py
2019-04-14 19:52:00 -07:00
Paulus Schoutsen
d722f4d64a Further integration load cleanups (#23104)
* Further integration load cleanups

* Fix tests

* Unflake MQTT vacuum command test
2019-04-14 19:07:05 -07:00
Alexei Chetroi
930f75220c Await merge_packages_config(). (#23109) 2019-04-14 19:02:49 -07:00
Paulus Schoutsen
6b0180f753 Fix demo (#23087)
* Fix demo

* Fix types

* Fix all the things

* Fix type

* Fix test

* Lint
2019-04-14 16:59:06 -07:00
Pawel
1d2e9b6915 Add support for params in send_command (#23071)
* add support for params in send_command

* add more tests
2019-04-14 11:09:46 -07:00
ActuallyRuben
df580b2322 Add URL query parameters to webhook trigger result data (#23043)
* Added query parameters to webhook data

* Added test for query webhook

* Add second blank line in new test for webhook trigger
2019-04-14 10:53:35 -07:00
Jason Hu
d1398e24be Increase timeout (#23098) 2019-04-14 10:18:45 -07:00
Paulus Schoutsen
3368e30279 Migrate packages and check config (#23082)
* Migrate packages and check config

* Fix typing

* Fix check config script
2019-04-14 07:23:01 -07:00
Jason Hu
95662f82d4 Remove validate from aws_config (#23084) 2019-04-14 07:21:47 -07:00
choss
c314220167 Ignore secrets.yaml when using include_dir_named (#22929)
* ignore secrets.yaml in include_dir_named include

* updating test for include_dir_named secrets ignore
2019-04-13 21:24:06 -07:00
Erik Montnemery
c6bc47b32d Refactor MQTT climate to deduplicate code (#23044) 2019-04-13 20:34:39 -07:00
Erik Montnemery
b390de1598 Fix bugs in MQTT vacuum (#23048) 2019-04-13 20:29:01 -07:00
Erik Montnemery
d99637e51b Deprecate implicit state_topic for MQTT discovery (#22998)
* Deprecate implicit state_topic for MQTT discovery

* Lint

* Add comments

* Modernize tests
2019-04-13 20:25:45 -07:00
Aaron Bach
56b08a6ddb Ensure OpenUV service checks permissions (#22668)
* Create decorator to check service permissions

* Ensure OpenUV service has proper user permissions

* Reverting strange changes
2019-04-13 16:50:19 -06:00
Martin Fuchs
0a0975b5d9 Add support for Stiebel Eltron heat pumps (#21199)
* Start with Stiebel Eltron heatpump

* STE HP

* Add read of operating mode

* Add read-write operation mode

* Further extract ModBus access

* Separation of platform and API

* Last changes

* Use modbus hub

* Update module doc with config

* Clean up platform code

* Cleanup and update to dev2 of pystiebeleltron

* Remove slave configuration

* Add translation of states

* Make name parameter optional

* Consolidate platform

* Correct .coveragerc after conflict

* Prepare component for sensor platform

* Fix issues found in review

* Remove custom states and map to existing HA states

* Force update, when values are modified

* Update CODEOWNERS and requirements_all.txt

* Fix .coveragerc file

* Exclude stiebel_eltron components in .coveragerc

* Break out to module level constant

* Rename constant

* Removed REQ and DEP constant.
2019-04-13 23:53:36 +02:00
Teemu R
39264af310 Add missing async for tplink's async_setup_platform methods (#23066)
* add missing async for tplink's async_setup_platform methods

thanks to @MartinHjelmare for spotting this, related to #21916

* fix line lengths
2019-04-13 23:50:21 +02:00
Andrew Sayre
8c89e260df HEOS confirm discovered devices before adding (#23063)
* Add host selection step to discovery

* Review feedback

* Fix failing test
2019-04-13 16:44:45 -05:00
Aaron Bach
46ee7d7b22 Fix test (#23081) 2019-04-13 14:32:07 -07:00
Paulus Schoutsen
e8343452cd Validate component usage (#23037)
* Update manifest validator

* Update circle

* Update text

* Typo

* fix link to codeowners

* Merge CODEOWNERS into hassfest

* Annotate errors with fixable

* Convert error to warning

* Lint

* Make abs path

* Python 3.5...

* Typo

* Fix tests
2019-04-13 13:17:01 -07:00
Aaron Bach
fc481133e7 Create decorator to check service permissions (#22667)
* Create decorator to check service permissions

* Typing

* Linting

* Member comments

* Linting

* Member comments

* Updated import

* Owner comments

* Linting

* Linting

* More work

* Fixed tests

* Removed service helper tests in RainMachine

* Linting

* Owner comments

* Linting

* Owner comments

Co-Authored-By: bachya <bachya1208@gmail.com>
2019-04-13 13:54:29 -06:00
Joakim Plate
7a6950fd72 Validate data packet format on config validation (#23062) 2019-04-13 10:58:12 -07:00
Penny Wood
2527731865 Fix websocket connection sensor (#22923)
* Fix for #22890

* Singleton count
2019-04-13 10:48:40 -07:00
Alexei Chetroi
479511ee42 Bugfix ZHA device_removed() handler. (#23074) 2019-04-13 12:57:22 -04:00
c-soft
2f17529f28 Add Satel_integra switchable outputs and multiple partitions (#21992)
* Added editable outputs and multiple zones.

* Updated requirements_all.txt

* Linter fixes.

* Post-review changes

* Fixed too many lines separation error

* Passing satel controller as parameter to entities.

* Fixed linter error.

* Fixed forgotten requirements update.

* Fixed satel_integra version (again!?!)

* Fixed manifest.json.

* Fixed passing non-serializable controller

* Removed unnecessary isinstance check.

* Post review changes
2019-04-13 14:24:12 +02:00
Josef Schlehofer
18cf8275b8 Upgrade python-slugify to 3.0.2 (#22997) 2019-04-13 11:29:44 +02:00
Jason Hu
73a473ac29 Allow aws credential skip validation (#22991)
* Allow aws credential skip validation

* Don't validate the auto-created default profile
2019-04-12 17:19:05 -07:00
Paulus Schoutsen
3f69d0283d Convert translation helper to use async_get_integration (#23054)
* Convert translation helper to use async_get_integration

* Simplify after comments

* Lint

* Fix typing

* Typo
2019-04-12 17:10:19 -07:00
Paulus Schoutsen
b767232e50 Only load stream when av package available (#23058) 2019-04-12 17:09:58 -07:00
Aaron Bach
05f267de6e Update RainMachine sensors in parallel (#23057) 2019-04-12 17:44:04 -06:00
Diogo Gomes
51508d69ad Bandage telegram bot (#23022)
* Bandage

* lint

* move everything into __init__.py

* fix lint
2019-04-12 14:28:59 -07:00
Joakim Plate
0a3e11aa12 Move Broadlink services to component (#21465)
* Register services in broadlink domain

* Add tests for broadlink services

* Resolve review comments

* One more review fix

* Restore auth retry

* Drop unused constants

* Fix flake8 errors
2019-04-12 20:11:36 +02:00
Paulus Schoutsen
f269135ae9 Migrate check-config to use get_integration (#23026)
* Migrate check-config to use get_integration

* ImportError
2019-04-12 10:14:16 -07:00
cgtobi
2c07bfb9e0 Remove dependencies and requirements (#23024)
* Remove dependencies and requirements

* Revert "Remove dependencies and requirements"

This reverts commit fe7171b4cd.

* Remove dependencies and requirements

* Revert "Remove dependencies and requirements"

This reverts commit 391355ee2c.

* Remove dependencies and requirements

* Fix flake8 complaints

* Fix more flake8 complaints

* Revert non-component removals
2019-04-12 10:13:30 -07:00
Paulus Schoutsen
f7d4c48199 Convert service helper to use async_get_integration (#23023)
* Convert service helper to use async_get_integration

* Fix tests
2019-04-12 10:09:17 -07:00
Charles Garwood
c8375be4b1 Replace get_platform (#23014)
* Update Z-Wave to use async_get_integration

* Change load method per PR comments

* update tests
2019-04-12 12:22:56 -04:00
Aaron Bach
7d46ed0bf9 Remove expired 17track.net packages from entity registry (#23001)
* Remove expired 17track.net packages from entity registry

* Reverse order
2019-04-12 08:03:14 -06:00
Austin Drummond
3d441dffad Update HAP-python to 2.5.0 (#23031) 2019-04-12 13:26:52 +02:00
Malte Franken
6c51592e34 Instituto Geográfico Nacional Sismología (Earthquakes) Feed platform (#22696)
* wip

* added new requirements

* fixed tests

* improved test coverage

* added feed entry's title

* added manifest

* updated codeowners

* generated requirements
2019-04-12 09:01:28 +02:00
Paulus Schoutsen
c94b031db1 Fix unnecessary hass.components interaction (#23029)
* Fix wemo

* Fix bloomsky

* Fix netatmo

* Fix one more reference
2019-04-11 23:37:45 -07:00
Paulus Schoutsen
57f17707c6 Specify configurator as dependency (#23030) 2019-04-11 20:11:56 -07:00
Robbie Trencheny
7303d56a55 Mobile App: Remove component loading support (#23025)
Loading a component defined in a registration didn't actually work and was undocumented, so let's just remove it instead of fixing #23005.

## Checklist:
  - [X] The code change is tested and works locally.
  - [X] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [X] There is no commented out code in this PR.
2019-04-11 19:06:36 -07:00
Paulus Schoutsen
7e39e14086 Merge remote-tracking branch 'origin/master' into dev 2019-04-11 16:06:31 -07:00
Ian Richardson
8bfe77a1a0 Add aftership package details and add/remove services (#22275)
* 📦 Package details and add/remove services

* lint

* Cleanup

* lint

* Fix add tracking service call

* cleanup

* Make data easier to consume on the front-end

* lint

* Add expected delivery date

* call update after add/remove

* lint

* cleanup

* Add last_checkpoint

* address review comments

* remove formatting changes

* lint

* Address review comments

* address review comments

* address review comments

* lint

* lint
2019-04-11 15:57:48 -07:00
Jason Hu
ac7f1a7a37 Fix test failed in py35 (#23002) 2019-04-11 12:52:02 -07:00
Stephan Beier
02347df140 Prevent the projector to toogle on/off (#22985) 2019-04-11 11:32:25 -05:00
Markus Jankowski
d078e50fb8 Add device HmIP-MIOB to Homematic IP Cloud (#22975)
* Update upstream dependency

* Add two switches
2019-04-11 10:49:02 +02:00
Rohan Kapoor
6ba9ccf052 Load requirements and dependencies from manifests. Fallback to current REQUIREMENTS and DEPENDENCIES (#22717)
* Load dependencies from manifests. Fallback to current DEPENDENCIES

* Fix typing

* Ignore typing correctly

* Split out dependency processing to a new method

* Fix tests

* Only pull from manifest if dependencies is non empty

* Inline temporary function

* Fix light tests [skip ci]

* Fix tests/common

* Fix some mqtt tests [skip ci]

* Fix tests and component manifests which have only one platform

* Fix rflink tests

* Fix more tests and manifests

* Readability over shorthand format

* Fix demo/notify tests

* Load dependencies from manifests. Fallback to current DEPENDENCIES

* Load requirements from manifests. Fallback to current REQUIREMENTS

* Fix typing

* Ignore typing correctly

* Split out dependency processing to a new method

* Only pull from manifest if dependencies is non empty

* Inline temporary function

* Fix tests and component manifests which have only one platform

* Fix rflink tests

* Readability over shorthand format

* Clean up requirements

* Use integration to resolve deps/reqs

* Lint

* Lint

* revert a change

* Revert a test change

* Fix types

* Fix types

* Add back cache for load component

* Fix test_component_not_found

* Move light.test and device_tracker.test into test package instead with manifest to fix tests

* Fix broken device_tracker tests

* Add docstrings to __init__

* Fix all of the light tests that I broke earlier

* Embed the test.switch platform to fix other tests

* Embed and fix the test.imagimage_processing platform

* Fix tests for nx584

* Add dependencies from platform file's DEPENDENCIES

* Try to setup component when entity_platform is setting up

Fix tests in helpers folder

* Rewrite test_setup

* Simplify

* Lint

* Disable demo component if running in test

Temp workaround to unblock CI tests

* Skip demo tests

* Fix config entry test

* Fix repeat test

* Clarify doc

* One extra guard

* Fix import

* Lint

* Workaround google tts
2019-04-11 01:26:36 -07:00
Miroslav Ždrale
8a81286abb Bump pyubee version to support more models and detect model automatically (#22450)
* Bump pyubee to 0.4, support more models and detect model automatically

* Update requirements_all.txt

* Check for supported models

* Add model aliases

* Code clean-up

* Updated code to meet reviewer's requests.

* Updated code to meet reviewer's requests.

* Minor update

* Minor update

* Populate mac2name dict

* Return list of MAC addresses, not dict

Co-Authored-By: mzdrale <mzdrale@gmail.com>

* Minor update
2019-04-11 10:25:46 +02:00
Robbie Trencheny
f5c677146a Make inlined JSON example valid 2019-04-10 21:58:50 -07:00
Paulus Schoutsen
f33bf718c7 Google Assistant: Migrate light setting trait to use HSV color spectrum (#22980)
* Migrate light setting trait to use HSV

* Fix tests

* Fix all the typos
2019-04-10 21:35:37 -07:00
cgtobi
c2cfc4a813 Stream support for Netatmo cameras (#22952)
* Add stream feature

* Add a missing slash

* Get config parameter

* Get default quality
2019-04-10 16:10:14 -07:00
Paulus Schoutsen
373b2009c9 Catch connection reset (#22982) 2019-04-10 15:42:10 -07:00
Paulus Schoutsen
e9d9861bda Update translations 2019-04-10 15:01:32 -07:00
Paulus Schoutsen
c81b1956da Updated frontend to 20190410.0 2019-04-10 15:01:14 -07:00
Aaron Bach
153c6957b9 Add watchdog reset to on_connect in Ambient (#22956) 2019-04-10 15:25:19 -06:00
ehendrix23
7862fdd27e Fix myq increasing number of network connections (#22432)
* Fix for network issues

Fix for network issues

* Further changes to network connection

* websession is created in pymyq

websession is created in pymyq instead.
Added call on stop event to close web session.

* Updated requirements file

* Added comment

* Changed back to use aiohttp_client

* Cleanup closed sockets in aiohttp

Enable automatic cleanup of closed sockets in aiohttp client helper.

* Updated manifest & requirements

* Updated comment block
2019-04-10 14:24:12 -07:00
Erik Montnemery
38d92b2abf Fix optimistic mode and add tests (#22899) 2019-04-10 13:56:34 -07:00
Robert Svensson
6463b8165f Fix deCONZ change entity_id bug (#22974)
Fix deCONZ change entity_id bug
2019-04-10 22:35:28 +02:00
Otto Winter
72af4276b9 Add ESPHome climate support (#22859)
* Add ESPHome climate support

* Adjust line length

* Update .coveragerc

* Update climate.py

* Rename
2019-04-10 22:13:13 +02:00
Andrew Sayre
7624d0e79f Check for supported features in media_player services (#22878)
* Add check for supported features

* Move logic to service helper

* Fix hacked in test for seek

* Test for service required features
2019-04-10 09:44:58 -07:00
Pascal Vizeli
fc7a187dd6 Update uvloop 0.12.2 2019-04-10 16:46:23 +02:00
Pascal Vizeli
536356ceec Merge pull request #22969 from home-assistant/rc
0.91.3
2019-04-10 16:42:00 +02:00
Pascal Vizeli
984af45bb2 Bumped version to 0.91.3 2019-04-10 13:22:19 +00:00
Pascal Vizeli
eab575e65d Bugfix: pass protocol out of header to application layer (#22955) 2019-04-10 13:19:54 +00:00
Robbie Trencheny
e7a17b710d Add cloudhook and remote UI vals to get_config (#22921) 2019-04-10 13:19:54 +00:00
Robbie Trencheny
a267df2abb More Mobile app sensor fixes (#22914)
* Ensure we only add a sensor once

* Ensure that we dont process updates for entities that arent what we were setup for

* Add debug logging to ease development of apps

* Use str representation
2019-04-10 13:19:53 +00:00
Fabian Affolter
f531ca61c6 Set pytz>=2019.01 (#22966) 2019-04-10 15:18:30 +02:00
John Raahauge
9e56283eaf Fix position of add_entities of binary sensor (#22866)
* Bugfix - binary_sensor.py

* Added features to Concord232 Alarm Panel

* Added New Line End Of File

* Deleted Whitespace

* Back to original

Removed added feature and sticking to bugfix
2019-04-10 13:18:10 +00:00
Fabian Affolter
be51a3ae12 Upgrade ruamel.yaml to 0.15.91 (#22965) 2019-04-10 15:15:12 +02:00
Fabian Affolter
f4309dfcc6 Add missing attribution (#22964) 2019-04-10 14:51:42 +02:00
Fabian Affolter
691271147e Update ordering (#22963) 2019-04-10 14:35:57 +02:00
Fabian Affolter
3d5ee0eb58 Upgrade youtube_dl to 2019.04.07 (#22961) 2019-04-10 13:05:16 +02:00
Fabian Affolter
6156bb4e5b Upgrade Sphinx to 2.0.1 (#22960) 2019-04-10 13:03:30 +02:00
Ville Skyttä
7058249c01 Uprade asynctest to 0.12.3 (#22824) 2019-04-10 11:17:02 +02:00
Ville Skyttä
fa8a4de019 Upgrade pytest to 4.4.0 (#22822) 2019-04-10 11:16:52 +02:00
Erik Montnemery
bc5f0ff0b3 Use dict[key] for required config keys and keys with default values of MQTT light (#22834)
* Use dict[key] for required config keys and keys with default values.

* Improve tests

* Lint

* Improve tests of JSON data
2019-04-10 11:16:41 +02:00
mgiako
bbedf091aa Add functionality to the version sensor (#22896)
* Update manifest.json

* Update sensor.py

* new version option
2019-04-10 09:55:39 +02:00
Fredrik Erlandsson
5d3aac8130 Use ConfigEntryNotReady when setting up Daikin (#22901)
* raise ConfigEntryNotReady

* better debugging
2019-04-10 09:44:00 +02:00
Anders Melchiorsen
a833736a1e Add sms_total sensor to netgear_lte (#22954) 2019-04-10 09:41:57 +02:00
cdce8p
6d2412022b Fix HomeKit fan speed conversion (#22951)
* Check that speed value from state is not 'None'
* Added tests
2019-04-10 08:35:17 +02:00
Paulus Schoutsen
51e6d5380e Add color setting trait (#22894) 2019-04-09 20:17:13 -07:00
Pascal Vizeli
37f3eccb1e Bugfix: pass protocol out of header to application layer (#22955) 2019-04-09 20:13:39 -07:00
Paulus Schoutsen
e48ef7f441 Fix broken platform components (#22943)
* Fix broken platform components

* Lint
2019-04-09 15:42:44 -07:00
Paulus Schoutsen
8582e390f8 Remove introduction component (#22944)
* Remove introduction component

* Remove more usage
2019-04-09 14:45:09 -07:00
Austin Drummond
c4e31bc4df Add linked battery sensor to HomeKit (#22788) 2019-04-09 23:13:48 +02:00
Anders Melchiorsen
6244a397b1 Hide unsupported Sonos favorites (#22940) 2019-04-09 23:09:18 +02:00
Jason Hu
c82d2cb11c Cherry pick test fix (#22939) 2019-04-09 13:59:15 -07:00
Anders Melchiorsen
58ec77b017 Binary sensors for netgear_lte (#22902)
* Binary sensors for netgear_lte

* Move LTEEntity to component

* Revert unrelated manifest changes

* Address review comments

* Remove unused import
2019-04-09 20:28:20 +02:00
Justin Vanderhooft
4803f319b6 bump raincloudy to 0.0.7 (#22935) 2019-04-09 19:00:50 +02:00
Paulus Schoutsen
cac00f5b26 Test for circular dependencies using manifests (#22908)
* Integration dependencies

* Lint

* Lint

* Fix one test

* Lint

* Fix load custom component integration

Fix async issue
Add circular dependency detection in manifest validation

* Fix test

* Address review comment

* Apply suggestions from code review

Co-Authored-By: balloob <paulus@home-assistant.io>
2019-04-09 09:30:32 -07:00
Andrew Sayre
4110bd0acf Add support for when device is not logged in to HEOS (#22913) 2019-04-09 18:21:00 +02:00
Paulus Schoutsen
0d2646ba25 Update translations 2019-04-09 08:34:20 -07:00
Phil Bruckner
34bb31f4ec Add amcrest binary_sensors (#22703)
* Add amcrest binary_sensors

Add binary_sensors with option motion_detected. Deprecate motion_detector sensor.

* Update per review

* Update per review

Add custom validators to make sure camera names are unique, and to issue warning if deprecated sensors option motion_detector is used.

async_setup_platform should not return a value.

* Another review update

Since there is only one type of binary_sensor, remove type test in update method.
2019-04-09 15:21:47 +02:00
Evan Bruhn
a48c0f2991 Logi Circle public API refactor and config flow (#20624)
* Logi Circle now uses OAuth2 for authentication, added config flow.

* Service calls now dispatched to camera entities via signalled events

* Update from PR review

* Add unit tests for config flow

* Updated CODEOWNERS

* Reverted change to .coveragerc

* Improved test coverage of config flow
2019-04-09 14:26:58 +02:00
Ben Dews
f81ce0b720 Add 'Assumed State' property to Somfy MyLink covers (#22922)
* Explicitly return none for is_closed property

* Set the assumed_state property to true

* Added period to docstring
2019-04-09 05:58:09 -04:00
Paul Madden
88694c978b Camera component for BOM integration (#22816)
* Work on PR comments

* Work on PR comments

* Update imports

* Work on schema validation

* Fix package

* Add bomradarcam to .coveragerc

* Improve error message for location

* Delinting

* Correct module name in .coveragerc

* Add manifest.json

* Update requirements_all.txt

* Merge bomradarcam into existing bom integration
2019-04-09 05:56:04 -04:00
John Raahauge
d48fe4cebc Added features to Concord232 Alarm Panel (#22892)
* Added features to Concord232 Alarm Panel

* Update homeassistant/components/concord232/alarm_control_panel.py

Deleted 'or None' as per @syssi suggestion.
2019-04-09 05:49:48 -04:00
Robbie Trencheny
fd8d9747ef More Mobile app sensor fixes (#22914)
* Ensure we only add a sensor once

* Ensure that we dont process updates for entities that arent what we were setup for

* Add debug logging to ease development of apps

* Use str representation
2019-04-09 05:48:59 -04:00
Alexei Chetroi
64ea13104e Fix ZHA Light color conversion. (#22909) 2019-04-09 05:48:17 -04:00
Robbie Trencheny
75bed93d3d Add cloudhook and remote UI vals to get_config (#22921) 2019-04-09 05:47:57 -04:00
Ben Dews
6ee23bdf4e Add Somfy MyLink support for Covers (#22514)
* Added MyLink component

* Updated requirements.txt

* Fix lint issues

* Removed ‘Scene’ functionality

* Removed state restoration, as state is no longer tracked

* Add component manifest

* Remove documentation links in Docstring

* Removed redundant try/except block

* Removed default dict

* Removed features already implemented in default CoverDevice

* Removed attributes for tracking state

* Simplified loading of covers

No options exist other than reversal, so just check reversal status directly and update if needed

* Reimplemented is_closed property

* Import ENTITY_ID_FORMAT from base component

* Removed misc unused vars

* Update module docstrings to one line

* Removed too many blank lines, giving one back :)

* Return none on TimeoutError

* Added component to .coveragerc
2019-04-09 08:31:34 +02:00
Jason Hunter
43487aa0d6 Stream Timestamp Fixes (#22912)
* reset timestamps for streams that do not do so when first requested

* update inline comments to be more descriptive
2019-04-08 23:24:51 -07:00
Paulus Schoutsen
590eead128 Test fixes (#22911)
* Fix light tests [skip ci]

* Fix tests/common

* Fix some mqtt tests [skip ci]

* Fix tests and component manifests which have only one platform

* Fix more tests and manifests

* Fix demo/notify tests

* Rollback test for demo.geo_location
2019-04-08 23:16:55 -07:00
pbalogh77
1a05f7b04d Initial Fibaro HC Climate support (#20256)
* Initial version of climate

* initial commit of climate device support

* Fixed opmode and fanmode

* Cleanup

* meh

* added back all other components

Oops

* wider support for thermostats

Added one more identifier for thermostats to broaden compatibility

* Added even more climate types

* Reworked detection mechanism

Better support for combined devices

* Added additional modes

* force visibility on climate

* Changed logging of device data

* Improved operatingmode support

Improved operatingmode support

* Updated logic for opmode/fanmode list creation

Implemented a universal mapping logic for opmode and fanmode, to make it more widely compatible
Improved mapping of Fibaro FGT devices

* Lint fixes

* bump

* Fixes based on code review

* Fixes

* Moved to fibaro folder

* lint inspired cosmetic changes

* Mapped all operating modes to existing HA ones

Mapped all operating modes to existing HA ones

* Improved compatibility with Heatit thermostats

Thanks to astrandb for testing, debugging and fixing my code

* Changes based on code review

Changes based on code review

* more fixes based on more code review

more fixes based on more code review
2019-04-09 06:24:57 +02:00
Andrew Sayre
38f063a158 Fix HEOS discovery could result in multiple config entries (#22903)
* Prevent duplicate entries from discovery

* Update reqs files

* Prevent duplicate entries from discovery
2019-04-08 21:24:40 -05:00
Anders Melchiorsen
d577955d1e Fix Sonos handling of unsupported favorites (#22906) 2019-04-08 19:32:56 -05:00
Fredrik Erlandsson
55c8417ec0 fix aiohttp ServerDisconnectedError in Daikin (#22880) 2019-04-08 10:08:03 -07:00
Erik Montnemery
49a2f5a40b Use dict[key] for required config keys and keys with default values. (#22832) 2019-04-08 08:47:40 -07:00
Otto Winter
5727beed8e Add ESPHome Cover position/tilt support (#22858)
## Description:

Add ESPHome cover position and tilt support.

The aioesphomeapi also received a small refactor for these changes and those are part of this PR (constants were refactored into enums and optimistic was renamed to assumed_state). If possible, I'd like to include those in this PR because:

 1. It's mostly just very simple changes
 2. Because of the new position change the dev branch would be in a non-working state for a while until the split PR is merged (unless I write some temporary glue logic, but I'd prefer to avoid that)

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.

If the code communicates with devices, web services, or third-party tools:
  - [x] [_The manifest file_][manifest-docs] has all fields filled out correctly ([example][ex-manifest]).
  - [x] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]).
  - [x] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.

[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_
2019-04-08 15:44:24 +02:00
Rohan Kapoor
6c53528ae8 Update harmony manifest to match REQUIREMENTS in module (#22826) 2019-04-08 06:43:38 -07:00
Otto Winter
c9ec166f4b Add MQTT climate two-point target temperature support (#22860)
* Add MQTT climate two-point target temperature support

* Sort

* Fix test
2019-04-08 06:28:42 -07:00
Matt Snyder
36c135c785 Stream support for Doorbird component (#22876)
* Support stream source for doorbird live camera

* Support stream source for doorbird live camera

* Support stream component on Doorbird camera entities

* Bump library version

* Update manifest

* Lint

* Correct parameter order
2019-04-08 09:22:31 -04:00
akasma74
d8c7160377 force_update=False (not None) (#22867)
because force_update: boolean
2019-04-08 06:21:13 -07:00
cgtobi
8cc5cc7f43 Add zwave network key validator (#22785)
* Add zwave network key validator

* Move validator to zwave component

* Move validator to zwave component

* Move stuff

* Move stuff

* Remove helper and replace with voluptuous method

* Add test

* Fix long line

* Improve tests

* Add more negative tests

* Remove unnecessary assertion

* Make the linter happy

* Remove print
2019-04-08 06:18:52 -07:00
John Raahauge
45a43592bd Fix position of add_entities of binary sensor (#22866)
* Bugfix - binary_sensor.py

* Added features to Concord232 Alarm Panel

* Added New Line End Of File

* Deleted Whitespace

* Back to original

Removed added feature and sticking to bugfix
2019-04-08 08:53:00 -04:00
Finbarr Brady
a0d6e08421 Bump pypi module version for enigma2 (#22886)
* Bug fix for #22727

* Update requirements_all.txt

* Update manifest.json
2019-04-08 08:49:52 -04:00
Finbarr Brady
a4ffc9e37a add myself as codeowner (#22885) 2019-04-08 08:48:19 -04:00
Pascal Vizeli
8f9c2000ce Merge pull request #22883 from home-assistant/rc
0.91.2
2019-04-08 11:27:14 +02:00
Robbie Trencheny
a04d44d97a Minor sensor fixes (#22884)
* Minor sensor fixes

* Fix tests
2019-04-08 08:17:11 +00:00
Robbie Trencheny
137d80452d Minor sensor fixes (#22884)
* Minor sensor fixes

* Fix tests
2019-04-08 01:13:26 -07:00
Pascal Vizeli
3f73973970 Bumped version to 0.91.2 2019-04-08 08:00:22 +00:00
Pascal Vizeli
3a79e37cde Fix content_type handling ingress (#22864) 2019-04-08 07:59:05 +00:00
zewelor
3f15b6b2d3 Fix yeelight possible array change during iteration (#22849) 2019-04-08 07:59:04 +00:00
zewelor
c5d4b7c243 Use relative imports in yeelight (#22839) 2019-04-08 07:59:04 +00:00
Robbie Trencheny
236e484dc2 Fix for rate limits should be optional (#22823) 2019-04-08 07:59:02 +00:00
Jason Hunter
f51e8c3012 coerce duration and lookback to int so they can be used in template automation (#22819) 2019-04-08 07:59:01 +00:00
Robbie Trencheny
474fc21c66 Fix for optional values in the update_location webhook call (#22817)
* Fix for optional values in the update_location webhook call

* Square brackets instead of .get
2019-04-08 07:59:00 +00:00
Robbie Trencheny
82f6bed3a3 Add a new mobile_app webhook command to get config (#22813)
* Add a new mobile_app webhook command to get config

* Limit fields returned
2019-04-08 07:58:59 +00:00
zewelor
abb531c06b Improve yeelight imports (#22804) 2019-04-08 07:58:10 +00:00
Chris Helming
7a8aa79f19 Add optional rtsp_port for Foscam (#22786)
* add optional rtsp port for config

* getting rid of default=None

* removing vol.Any
2019-04-08 07:56:56 +00:00
Robbie Trencheny
ed9d1e776f Add new mobile_app webhook command: get_zones (#22604)
## Description:

Adds a new `mobile_app` webhook command, `get_zones`, which just returns all zones.

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-04-08 07:56:55 +00:00
Wolfgang Malgadey
d8119b2281 Fix tado turn on off (#22291)
* fix for turn on and off, with new pyTado

missing blank line

* removed, because can't push

* uploaded the file through github again
2019-04-08 07:54:58 +00:00
Pascal Vizeli
2d287d2abe Fix content_type handling ingress (#22864) 2019-04-08 09:22:55 +02:00
Aaron Bach
4982c0b196 Added REQUIREMENTS back to Ambient (#22875) 2019-04-07 21:02:03 -07:00
cdce8p
8bebd8583f Fix manifest codeowners (#22871)
* Added individual files section
* Replaced some manifest/codeowners
2019-04-07 21:01:05 -07:00
David F. Mulcahey
3086e1d39d get temp and color for light during init and poll (#22847) 2019-04-07 22:03:38 -04:00
Aaron Bach
a40a0c4042 Bump aioambient to 0.3.0 (#22855)
* Bump aioambient to 0.3.0

* Updated requirements

* Removed old REQUIREMENTS reference
2019-04-07 14:21:29 -06:00
zewelor
e407226afc Fix yeelight possible array change during iteration (#22849) 2019-04-07 14:05:38 -06:00
Jason Hu
abe85c73ae Fix flaky test (#22850) 2019-04-07 12:42:16 -07:00
Jason Hunter
3fde1d3bab coerce duration and lookback to int so they can be used in template automation (#22819) 2019-04-07 13:08:08 -04:00
roblandry
c7a49e0820 Fix glances docker container errors (#22846)
* Fix unavailable container errors

* Update to dev

* Use const
2019-04-07 13:07:05 -04:00
Robbie Trencheny
02b7fd93ed Fix for rate limits should be optional (#22823) 2019-04-07 07:37:27 -07:00
Erik Montnemery
fa2e07d7c5 Use dict[key] for required config keys and keys with default values. (#22830) 2019-04-07 10:11:45 -04:00
Erik Montnemery
58220a9448 Use dict[key] for required config keys and keys with default values. (#22829) 2019-04-07 10:11:20 -04:00
Erik Montnemery
dbb42e5890 Use dict[key] for required config keys and keys with default values. (#22838) 2019-04-07 10:10:57 -04:00
Erik Montnemery
2a62906965 Use dict[key] for required config keys and keys with default values. (#22837) 2019-04-07 10:10:13 -04:00
Erik Montnemery
b1213b7a2d Use dict[key] for required config keys and keys with default values. (#22836) 2019-04-07 10:09:43 -04:00
Erik Montnemery
a4e7708450 Use dict[key] for required config keys and keys with default values. (#22833) 2019-04-07 10:08:47 -04:00
Erik Montnemery
439197ea3e Use dict[key] for required config keys and keys with default values. (#22828) 2019-04-07 10:08:04 -04:00
zewelor
f62d1d8d09 Optimize yeelight signal handling (#22806) 2019-04-07 16:07:50 +02:00
zewelor
a91e79ee77 Improve yeelight imports (#22804) 2019-04-07 16:07:34 +02:00
zewelor
bb5c18f7be Use relative imports in yeelight (#22839) 2019-04-07 16:07:15 +02:00
Erik Montnemery
842534d472 Use dict[key] for required config keys and keys with default values. (#22831) 2019-04-07 10:00:40 -04:00
Erik Montnemery
83fb3637d9 Sort configuration schema. (#22835) 2019-04-07 09:56:38 -04:00
Robbie Trencheny
6492809a7e Fix for optional values in the update_location webhook call (#22817)
* Fix for optional values in the update_location webhook call

* Square brackets instead of .get
2019-04-07 01:17:14 -07:00
Robbie Trencheny
3ce6be6297 Add a new mobile_app webhook command to get config (#22813)
* Add a new mobile_app webhook command to get config

* Limit fields returned
2019-04-07 01:16:54 -07:00
Markus Jankowski
c8eebb6b4a Add HmIP-SMO to Homematic IP (#22802) 2019-04-07 00:43:07 -07:00
Justin Vanderhooft
8c17b2f7dd Bump raincloud dependency to fix broken integration: Fixes #22422 (#22805)
* Bump raincloud dependency to fix broken integration: Fixes #22422

* bump requirements_all

* bump CODEOWNERS

* edit codeowners in response to PR feedback
2019-04-06 20:33:28 -07:00
Erik Montnemery
353fca3b6e Raise severity of MQTT callback deprecation warning (#22792) 2019-04-06 20:31:39 -07:00
Erik Montnemery
55619da722 Remove unused group status (#22791) 2019-04-06 20:31:21 -07:00
Andrew Hayworth
87cabc933c Update version of python_awair to 0.0.4 (#22809)
The awair API has changed again, this time substituting 'lat' and 'lon'
for 'latitude' and 'longitude'.
2019-04-06 18:55:15 -07:00
Jeff Irion
a747eaa3ba Remove pycryptodome requirement for Android TV (#22552)
* Bump androidtv to 0.0.15

* Bump androidtv to 0.0.15 in manifest.json
2019-04-06 16:18:50 +01:00
panosmz
6351c5c6ab Add OASA Telematics greek public transport sensor component (#22196)
* add telematics sensor

* add missing final newline

* code cleanup & add manifest

* fixes from review

* fix flake8 warning

* rerun gen_requirements_all.py script
2019-04-06 15:20:51 +02:00
Pascal Vizeli
8b3cf2d493 Update homeassistant-pyozw 0.1.4 (#22794) 2019-04-06 12:09:15 +02:00
Chris Helming
2b490e4486 Add optional rtsp_port for Foscam (#22786)
* add optional rtsp port for config

* getting rid of default=None

* removing vol.Any
2019-04-05 23:02:38 -04:00
Alexei Chetroi
a69b1a359d ZHA Light debug logging. (#22776) 2019-04-05 17:06:59 -07:00
David F. Mulcahey
f004f440d3 make the custom polling actually request state (#22778) 2019-04-05 17:01:06 -07:00
Nate Clark
dbe53a3947 Fix konnected unique_id computation for switches (#22777) 2019-04-05 16:52:30 -07:00
Rohan Kapoor
a44966f483 Correctly load Mopar's config (#22771) 2019-04-05 16:52:29 -07:00
David F. Mulcahey
192ed90773 make the custom polling actually request state (#22778) 2019-04-05 16:50:20 -07:00
Alexei Chetroi
8dfbfae270 ZHA Light debug logging. (#22776) 2019-04-05 19:06:41 -04:00
Nate Clark
144632a81b Fix konnected unique_id computation for switches (#22777) 2019-04-06 00:22:57 +02:00
Robert Svensson
d1bf470899 deCONZ multiple gateways fixup (#22774)
* Initial PR was merged before a proper review was performed
* These fixes follow Martins review comments after merge
2019-04-05 22:21:06 +02:00
Per Osbäck
7a33dc5cec update core dependencies due to pywebpush update (#22767) 2019-04-05 12:22:24 -07:00
Robert Svensson
008b641c56 Axis - support stream (#22593)
* Add support for new stream component
2019-04-05 19:14:54 +02:00
teliov
b3e60df82a Add google hangouts manual authentication option (#22158)
* Added option to use manual authentication for google hangout component
See: https://hangups.readthedocs.io/en/latest/user_guide.html#logging-in for manual log in example

Bumped up version of hangups to 0.4.9

* Updated components/hangouts/strings.json and generated translation string by running script/translations_develop
Reduced verbosity of modifications to components/hangouts/config_flow.py

* Added option to use manual authentication for google hangout component
See: https://hangups.readthedocs.io/en/latest/user_guide.html#logging-in for manual log in example

Bumped up version of hangups to 0.4.9

* Updated components/hangouts/strings.json and generated translation string by running script/translations_develop
Reduced verbosity of modifications to components/hangouts/config_flow.py

* fixing missing rebase
2019-04-05 10:11:04 -07:00
Rohan Kapoor
879967bed2 Correctly load Mopar's config (#22771) 2019-04-05 18:15:35 +02:00
carstenschroeder
323dc5b78a Improve exception handling in ADS integration (#22627)
* add exception handling

* fix hound findings

* improve logging

* improve logging II

* fix try..except to large
2019-04-05 17:14:44 +02:00
Pascal Vizeli
c209236f47 Merge pull request #22755 from home-assistant/rc
0.91.1
2019-04-05 15:44:21 +02:00
zewelor
9eb32728f1 Fix yeelight recorder warning (#22756) 2019-04-05 13:33:10 +02:00
zewelor
5e7fdb479b Fix yeelight recorder warning (#22756) 2019-04-05 13:32:46 +02:00
Pascal Vizeli
9198047ad5 Cleanup cookie handling (#22757) 2019-04-05 13:31:17 +02:00
Pascal Vizeli
4b877dd96f Cleanup cookie handling (#22757) 2019-04-05 13:29:43 +02:00
Paulus Schoutsen
cd3f51f7b1 Bumped version to 0.91.1 2019-04-04 23:49:37 -07:00
Fredrik Erlandsson
e9d55bf1c0 fixes configuration flow #22706 (#22754) 2019-04-04 23:49:12 -07:00
Jason Hunter
5252c92670 use the input stream codec as the template for the output streams (#22747) 2019-04-04 23:49:12 -07:00
Chris Helming
dc185b994d Update Foscam stream for newer models (#22744)
* Update Foscam to support stream source

* Removing spaces and tabs

* Changing to Python3-style string formatting

* Adding '_media_port' to hopefully cover other models

* changing logic for success and return none

* Update Foscam stream for newer models

* change if to or
2019-04-04 23:49:11 -07:00
Aaron Bach
74a7d4117e Bump aioambient to 0.2.0 (#22736) 2019-04-04 23:49:10 -07:00
Aaron Bach
bab966fb29 Fix incorrect "Unavailable" Ambient sensors (#22734)
* Fix incorrect "Unavailable" Ambient sensors

* Removed unnecessary cast
2019-04-04 23:49:10 -07:00
Pascal Vizeli
79facb82c6 Fix chunk streaming (#22730)
* Fix chunk streaming

* Cleanup a print

* Better error handling

* Fix import order
2019-04-04 23:49:09 -07:00
Pascal Vizeli
ec07affe0d Fix ingress routing with / (#22728) 2019-04-04 23:49:08 -07:00
David F. Mulcahey
193b608ee0 fix device class lookup for binary sensors (#22724) 2019-04-04 23:49:08 -07:00
Pascal Vizeli
8eb93a8bea Change URL handling (#22713) 2019-04-04 23:49:07 -07:00
Fredrik Erlandsson
876b5fbe96 fixes configuration flow #22706 (#22754) 2019-04-04 23:48:41 -07:00
Pascal Vizeli
71e120ce97 Fix chunk streaming (#22730)
* Fix chunk streaming

* Cleanup a print

* Better error handling

* Fix import order
2019-04-04 23:41:13 -07:00
Chris Helming
82a1c0d0e8 Update Foscam stream for newer models (#22744)
* Update Foscam to support stream source

* Removing spaces and tabs

* Changing to Python3-style string formatting

* Adding '_media_port' to hopefully cover other models

* changing logic for success and return none

* Update Foscam stream for newer models

* change if to or
2019-04-04 23:40:47 -07:00
Jason Hunter
8c657d4254 use the input stream codec as the template for the output streams (#22747) 2019-04-04 23:40:22 -07:00
Jason Hunter
a75b151dfa fix flaky test (#22748) 2019-04-04 23:39:19 -07:00
Erik Montnemery
563e4fbfca Add deprecation warning to embedded broker (#22753) 2019-04-04 23:38:10 -07:00
Robbie Trencheny
8b77298908 More fallout from #22737 and b130c433c9 2019-04-04 21:57:34 -07:00
Rohan Kapoor
d15eedc0fb Generate requirements_* from manifests (#22718)
## Description:
Generate requirements_* from manifests (if present). If not, fallback to the current approach of reading `REQUIREMENTS` from the module attribute. I disabled exploring the children of the `homeassistant.components.*` packages since that will just add a dependency (from the manifest) due to each of the python files in the package. Just having one for the top level package should be sufficient.

**Related issue (if applicable):** relates to #22700 

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23


Co-authored-by: Jason Hu <awaregit@gmail.com>
2019-04-04 21:29:29 -07:00
Robbie Trencheny
6c5f0b7434 It doesnt count as a fail if you catch it within 2 minutes 2019-04-04 21:27:18 -07:00
Rohan Kapoor
be579b783a Update PR template requirements to point to the manifest (#22751)
## Description:
Update the PR template to point requirements to the new manifest requirements.

**Related issue (if applicable):** relates to #22700

**Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** https://github.com/home-assistant/developers.home-assistant/pull/214

## Example entry for `configuration.yaml` (if applicable):
```yaml

```

## Checklist:
  - [ ] 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.

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:
  - [ ] New dependencies have been added to the `REQUIREMENTS` variable ([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`.

If the code does not interact with devices:
  - [ ] Tests have been added to verify that the new code works.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
2019-04-04 21:24:55 -07:00
Robbie Trencheny
b130c433c9 Update pywebpush version in manifest.json
Missed during #22737
2019-04-04 20:50:07 -07:00
Markus Jankowski
eadc1e037a add device class signal strength (#22738) 2019-04-04 21:37:59 -04:00
Wolfgang Malgadey
6996fec809 Fix tado turn on off (#22291)
* fix for turn on and off, with new pyTado

missing blank line

* removed, because can't push

* uploaded the file through github again
2019-04-04 17:52:06 -07:00
Robert Svensson
b50afec5f1 Support multiple deCONZ gateways (#22449)
* Store gateways inside a dict in deconz domain

* Make reachable events gateway specific

* Gateway shall always exist

* Adapt new device signalling to support multiple gateways

* Services follow gateway master

* Working on unload entry

* Make unload and master handover work
Improve tests for init

* Fix config flow

* Fix linting

* Clean up init tests

* Clean up hassio discovery to fit with the rest

* Store gateways inside a dict in deconz domain

* Make reachable events gateway specific

* Gateway shall always exist

* Adapt new device signalling to support multiple gateways

* Services follow gateway master

* Working on unload entry

* Make unload and master handover work
Improve tests for init

* Fix config flow

* Fix linting

* Clean up init tests

* Clean up hassio discovery to fit with the rest

* Add support for services to specify bridgeid
2019-04-04 17:48:24 -07:00
Per Osbäck
b9ec623ad9 Bump pywebpush to latest 1.9.2 (#22737) 2019-04-04 14:19:29 -07:00
Aaron Bach
96adbfdc36 Fix incorrect "Unavailable" Ambient sensors (#22734)
* Fix incorrect "Unavailable" Ambient sensors

* Removed unnecessary cast
2019-04-04 13:50:10 -06:00
Aaron Bach
0438dffe25 Bump aioambient to 0.2.0 (#22736) 2019-04-04 13:43:21 -06:00
Markus Ressel
07d739c14e Add N26 component (#22684)
* upgraded n26 dependency
removed card_id config parameter (unnecessary)
get_token is now a public method inside n26 dependency

* Add manifest.json
2019-04-04 10:18:54 -07:00
Pascal Vizeli
9bb88a6143 Fix ingress routing with / (#22728) 2019-04-04 17:43:18 +02:00
David F. Mulcahey
e29eb4fa23 fix device class lookup for binary sensors (#22724) 2019-04-04 09:06:54 -04:00
Eliran Turgeman
172ede217a Add 10 additional language options to DarkSky (#22719) 2019-04-04 14:23:31 +02:00
Martin Hjelmare
5d7c29dee2 Only post coverage comment if coverage changes (#22721) 2019-04-04 04:01:56 -07:00
Robbie Trencheny
754c4d205b Allow users to set encoding of mikrotik connection (#22715)
## Description:

Mikrotik does some stupid stuff with character encoding that can screw up the DHCP responses. See #15257 for more detail. 

**Related issue (if applicable):** fixes #15257

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-04-04 02:15:20 -07:00
Pascal Vizeli
beb6ddfa68 Change URL handling (#22713) 2019-04-04 11:10:44 +02:00
Paulus Schoutsen
d231d59896 Remove deprecated Insteon components (#22710) 2019-04-04 00:46:20 -07:00
Robbie Trencheny
704983a64f Fix hassio CODEOWNER to be the actual team name, hass-io 2019-04-04 00:34:34 -07:00
Robbie Trencheny
f9564400e8 Activate codeowners-mention via GitHub actions 2019-04-03 23:53:17 -07:00
Paulus Schoutsen
d5307c03d8 Generate codeowners based on manifests (#22705)
* Gen codeowners

* Update manifest_helper.py
2019-04-03 23:46:06 -07:00
Paulus Schoutsen
0c284161eb Validate manifests in CI (#22708)
* Validate manifests

* Fix mode

* Activate venv

* Validate manifests after installing HA which includes voluptuous
2019-04-03 23:45:09 -07:00
Rohan Kapoor
afac09932f Remove all config deprecations invalidated in 0.91 (#22704)
* Remove all config deprecations invalidated in 0.91

* Fix lint
2019-04-03 23:31:55 -07:00
Markus Jankowski
8e39939b7e Add device_class_power to sensor (#22691)
* Add device_class_power to sensor

* Fix comment
2019-04-03 21:52:23 -07:00
Kyle Niewiada
a5a926bcc6 Raise ConfigEntryNotReady for MQTT connection exception (#22540)
* Raise ConfigEntryNotReady for connection exception

Raise ConfigEntryNotReady for the connection exception like if the MQTT Server container/device is being restarted or was unavailable on boot.

* Add new exception

* grammar fix

* Possibly resolve hound comments

* raise `ConfigEntryNotReady` for mqtt connection error

* revert exceptions.py

* Update exceptions.py

* modify test to handle exception

* use constants to control exception scope

* Raise ConfigEntryNotReady for connection exception

Raise ConfigEntryNotReady for the connection exception like if the MQTT Server container/device is being restarted or was unavailable on boot.

* Add new exception

* Add new exception

* grammar fix

* Possibly resolve hound comments

* raise `ConfigEntryNotReady` for mqtt connection error

* revert exceptions.py

* Update exceptions.py

* modify test to handle exception

* use constants to control exception scope

* revert test change as it's not the same thing

* Update test_init.py

* Add test for MQTT OSError

* revert file changes from a bad rebase

* Rewrite test with valid syntax

* rewrite test to be less ambiguous

* add empty line

* add back 'axis'

* Remove empty line

* Update tests and undo merge from earlier

* correctly restore test for no connect broker

* fix test mock correctly

* line was too long. hit enter.
2019-04-03 21:51:01 -07:00
Robbie Trencheny
d81a627739 Add a .codecov.yml to control coverage statuses and enable notifications (#22707)
* Add a .codecov.yml to control coverage statuses and enable notifications

* Comment about Slack/Discord notification
2019-04-03 21:44:15 -07:00
Paulus Schoutsen
cfe4cf30ad Add manifests (#22699)
* Add manifests

* Update auto name

* Update codeowners

* Add requirements from platforms

* Minor cleanup

* Incorporate changes from awarecan PR
2019-04-03 21:14:45 -07:00
Jason Hu
6aac49de7e Remove aws_* notify platforms (#22698) 2019-04-03 20:14:02 -07:00
ehendrix23
a85bcce857 Fix connection loss issues for Harmony (#22687)
* Increase aioharmony version to 0.1.11

Update aioharmony version to 0.1.11, this new update contains fixes for websocket connection losses.

* Update requirements_all
2019-04-03 19:29:49 -05:00
Paulus Schoutsen
360caa3b1f Merge pull request #22688 from home-assistant/rc
0.91.0
2019-04-03 14:39:21 -07:00
Erik Montnemery
98644135fa Update light/services.yaml (#22662) 2019-04-03 20:30:03 +02:00
Paulus Schoutsen
63d8dd9f7a Bumped version to 0.91.0 2019-04-03 11:27:57 -07:00
Paulus Schoutsen
685de23a4e Run PyLint under Python 3.5 (#22642)
* Run PyLint under Python 3.5

* Remove -q from pip install to debug

* Upgrade setuptools before install

* Use correct cache key for pylint
2019-04-03 11:27:50 -07:00
Jason Hu
b30c140648 Require static-check success first for rest of workflow (#22635)
* Require static-check success first

* Update config.yml
2019-04-03 11:27:49 -07:00
Jason Hu
2c10563205 Config CircleCI workflow (#22590)
* Add mypyrc to control typing check, add mypy to circle

* Add translation upload circlci job
2019-04-03 11:27:49 -07:00
Jason Hu
5dd444fcd8 Set up Circleci workflow (#22519)
* Set up Circleci workflow

* Update python tag

* Add pre-test job to cache the requirements

* Upgrade pip itself

* Use 3.7 for lint

* Parallelize pylint

* Tweak run gen_requirements_all

* tweak cache key
2019-04-03 11:27:48 -07:00
Jason Hu
273007fa19 Fix Circleci config (#22509)
* Add libav depends on circleci

* tweak circleci config
2019-04-03 11:27:48 -07:00
Jason Hu
2e8c690033 A very basic Circleci setup (#22503)
* Add circleci support

* Add buildpack-deps

* Install libudev-dev

* sudo

* always run test

* Add test report

* no sugar

* quite pytest

* better junit test result

* Add $CODE_COVERAGE env var
2019-04-03 11:27:47 -07:00
Pascal Vizeli
836aab283f Fix ffmpeg default extra options (#22682) 2019-04-03 11:25:38 -07:00
Paulus Schoutsen
7cf92c2210 Deal with cover assumed state (#22673)
* Deal with cover assumed state

* Add docs
2019-04-03 11:25:38 -07:00
Jason Hu
9eb4f89da4 Fix trusted networks auth provider warning message (#22671)
* Fix trusted networks auth provider warning message

* Update auth.py
2019-04-03 11:25:37 -07:00
Diogo Gomes
167d8cbaba Fix #22648 - Utility_meter would try to cancel a non existing task (#22669)
* don't cancel tariff that are paused

* test tariffs
2019-04-03 11:25:36 -07:00
mvn23
e90d980e67 Don't use room setpoint override in climate.opentherm_gw (#22656)
* Dont use DATA_ROOM_SETPOINT_OVRD in climate.opentherm_gw as it is unreliable with some thermostats.

* Show new target temperature immediately until the backend notices a change

* Only update target temp on the gateway if the value differs from the current target_temperature.
2019-04-03 11:25:36 -07:00
Pascal Vizeli
81a659be0d Hass.io discovery flow deconz (#22623)
* Add Hass.io deCONZ discovery flow

* add bridge ID

* fix attribute

* fix strings

* Address comments

* Add test

* Add only instance / changed maybe later
2019-04-03 11:25:35 -07:00
Robbie Trencheny
51c7cbc6b9 Add mobile_app notify platform (#22580)
* Add mobile_app notify platform

* Requested changes

* Fix incorrect param for status code

* Move push_registrations to notify platform file

* Trim down registration information sent in push

* quotes

* Use async version of load_platform

* Add warning for duplicate device names

* Switch to async_get_service

* add mobile_app.notify test

* Update tests/components/mobile_app/test_notify.py

* Update tests/components/mobile_app/test_notify.py
2019-04-03 11:25:34 -07:00
Paulus Schoutsen
14da2fd8c9 Google Assistant: Add support for open/close binary sensors (#22674)
* Google Assistant: Add support for binary sensors

* Update test
2019-04-03 10:20:56 -07:00
Martin Hjelmare
3872ac9bf9 Fix citybikes (#22683)
* Move asyncio condition to instance from class, to be able to pass in
  lopp.
* Avoid not needed sife effects in init methods.
* Clean up.
2019-04-03 09:05:18 -07:00
Jason Hu
b4fc1d77ea Fix trend binary sensor and tests (#22686) 2019-04-03 09:04:30 -07:00
Tobias Sauerwein
048b100eea Clean up docstrings (#22679)
* Clean up docstrings

* Fix long lines

* Fix more docstrings

* Fix more docstrings

* Fix more docstrings
2019-04-03 17:40:03 +02:00
Alexei Chetroi
625c8e0cee Shutdown ZHAGateway on hass closing. (#22646)
* Shutdown ZHAGateway on hass stop.
* Cleanup ZHA event leftovers.
2019-04-03 09:40:48 -04:00
Robbie Trencheny
b797b1513a Add mobile_app notify platform (#22580)
* Add mobile_app notify platform

* Requested changes

* Fix incorrect param for status code

* Move push_registrations to notify platform file

* Trim down registration information sent in push

* quotes

* Use async version of load_platform

* Add warning for duplicate device names

* Switch to async_get_service

* add mobile_app.notify test

* Update tests/components/mobile_app/test_notify.py

* Update tests/components/mobile_app/test_notify.py
2019-04-03 08:21:25 -04:00
Paulus Schoutsen
b1cca25299 Deal with cover assumed state (#22673)
* Deal with cover assumed state

* Add docs
2019-04-03 13:53:44 +02:00
Pascal Vizeli
7066fb0d10 Fix ffmpeg default extra options (#22682) 2019-04-03 13:46:41 +02:00
Pascal Vizeli
58a89640bb Update uvloop to 0.12.2 (#22681) 2019-04-03 12:20:05 +02:00
Diogo Gomes
7c5846aed2 Fix #22648 - Utility_meter would try to cancel a non existing task (#22669)
* don't cancel tariff that are paused

* test tariffs
2019-04-03 08:49:53 +02:00
Finbarr Brady
a7d49e40c0 Rebrand Cisco Spark notify to be Cisco Webex Teams (#21938)
* Rebrand Cisco Spark notify to be Cisco Webex Teams

* Remove property from class

* Switch to use html for api

* Update notify.py

* Rename CONF_ROOMID to CONF_ROOM_ID

* updated

* Fix lint errors

* Update notify.py

* Update notify.py

* Also validate room  ID

* Update notify.py

* Update .coveragerc

* Update notify.py
2019-04-02 23:25:02 -07:00
Jason Hu
6a411710df Fix trusted networks auth provider warning message (#22671)
* Fix trusted networks auth provider warning message

* Update auth.py
2019-04-02 21:23:59 -07:00
Johann Kellerman
f2941522ca Person tests - split from #21703 (#22663) 2019-04-03 05:35:33 +02:00
emontnemery
e736521e9f Fix regression from PR #22396 (#22661)
* Fix regression from PR #22396

* Fix test
2019-04-02 19:58:28 -07:00
emontnemery
4f2435103b Cast: Fix next/previous track (#22634)
* Fix next/previous track

* Bump pychromecast

* Update test, fixup
2019-04-02 19:58:02 -07:00
Johann Kellerman
3453d67cfe Person schema for merge_packages #21307 (#21703)
* Person schema for merge_packages #21307

* empty list

* skip empty persons

* hound

* test schema

* ensure_none

* remove any test changes

* remove_falsy validator

* nice!

* coretests
2019-04-02 19:43:06 -07:00
Pascal Vizeli
5613e8bb60 Hass.io discovery flow deconz (#22623)
* Add Hass.io deCONZ discovery flow

* add bridge ID

* fix attribute

* fix strings

* Address comments

* Add test

* Add only instance / changed maybe later
2019-04-02 19:23:33 -07:00
mvn23
22d93a74a4 Don't use room setpoint override in climate.opentherm_gw (#22656)
* Dont use DATA_ROOM_SETPOINT_OVRD in climate.opentherm_gw as it is unreliable with some thermostats.

* Show new target temperature immediately until the backend notices a change

* Only update target temp on the gateway if the value differs from the current target_temperature.
2019-04-02 13:57:38 -07:00
Andrew Sayre
5651db4b5c Add discovery support to HEOS component (#22652)
* Add discovery entry point

* Fix test

* Correct test call method

* Update netdisco to 2.6.0
2019-04-02 15:22:49 -05:00
Paulus Schoutsen
3357596215 Bumped version to 0.91.0b5 2019-04-02 11:42:01 -07:00
Jc2k
31ac965b16 Fix racy homekit_controller platform setup caused by #22368 (#22655) 2019-04-02 11:41:56 -07:00
Chris Helming
e3ca1e6203 Return 0 for failed Foscam streams (#22651)
* Update Foscam to support stream source

* Removing spaces and tabs

* Changing to Python3-style string formatting

* Adding '_media_port' to hopefully cover other models

* changing logic for success and return none
2019-04-02 11:41:55 -07:00
Pascal Vizeli
6d741d68b7 Support GET params for websocket ingress path (#22638) 2019-04-02 11:41:55 -07:00
Daniel Høyer Iversen
a5c7f131ee Handle disonnect bug in Tibber library (#22629) 2019-04-02 11:41:54 -07:00
Paulus Schoutsen
c7576999ca Disable Z-Wave autoheal (#22628) 2019-04-02 11:41:53 -07:00
Pascal Vizeli
56c75d7706 Update face_recognition to 1.2.3 (#22622) 2019-04-02 11:41:53 -07:00
Chris Helming
e0b4e88544 Update Foscam component to support stream source (#22568)
* Update Foscam to support stream source

* Removing spaces and tabs

* Changing to Python3-style string formatting

* Adding '_media_port' to hopefully cover other models
2019-04-02 11:41:52 -07:00
Pascal Vizeli
6f345c55c9 Hass.io ingress (#22505)
* Fix API stream of snapshot / Add ingress

* fix lint

* Fix stream handling

* Cleanup api handling

* fix typing

* Set proxy header

* Use header constant

* Enable the ingress setup

* fix lint

* Fix name

* Fix tests

* fix lint

* forward params

* Add tests for ingress

* Cleanup cookie handling with aiohttp 3.5

* Add more tests

* Fix tests

* Fix lint

* Fix header handling for steam

* forward header too

* fix lint

* fix flake
2019-04-02 11:41:51 -07:00
Jason Hu
5cb69cf163 Add trusted networks deprecating warning (#22487)
* Add trusted networks deprecating warning

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Tweak
2019-04-02 11:41:51 -07:00
Alex Bahm
471afb4702 Add color support to emulated hue (#19590)
* [Hue API] Add color support

Adds color support to the hue api (specifically hue/saturation). Switched from using a tuple to convey state internally to using a dict to make adding new fields easier.

* [Hue API] Add unit test for color support
2019-04-02 11:25:58 -07:00
OleksandrBerchenko
8a86a79040 Add missing properties and scenes support to Osram Lightify (#22597)
* Rewrite Osram Lightify component

* Update python-lightify version to 1.0.7.2

* Remove unneeded code

* 1. Remove changes in light/__init__.py, 2. Set properties to None by default

* Fix typo

* Implement missing features (including scenes)

* Make input parameters to setup_platform standardized
2019-04-02 11:14:46 -07:00
Robert Svensson
8a0b210f87 Axis discovery updates host address (#22632)
* Discovery can update host on existing entries

* Add support in device to update host on entry update

* Fix tests and listener

* Fix hound comment

* Fix failing tests from cleanup
2019-04-02 11:13:11 -07:00
Markus Jankowski
6c14e7afa7 Add battery sensor to Homematic IP (#22630) 2019-04-02 10:29:48 -07:00
Chris Helming
429e2cdde8 Return 0 for failed Foscam streams (#22651)
* Update Foscam to support stream source

* Removing spaces and tabs

* Changing to Python3-style string formatting

* Adding '_media_port' to hopefully cover other models

* changing logic for success and return none
2019-04-02 09:59:38 -07:00
Jason Hu
d6e2862115 Ignore code coverages for component without test (#22653) 2019-04-02 09:51:44 -07:00
Paulus Schoutsen
e00ae35e07 Admin service to automatically add empty schema (#22637)
* Admin service to automatically add empty schema

* Lint
2019-04-02 09:34:11 -07:00
cgtobi
b8b3f4e88f Fix pytest durations parameter (#22658)
* Fix durations parameter

* Update config.yml
2019-04-02 09:31:29 -07:00
Alexei Chetroi
0427154963 Don't force updates on ZHA Electrical Measurement sensor. (#22647) 2019-04-02 08:28:55 -07:00
David Bonnes
3bd37d6a65 Improve evohome exception handling and fix bugs (#22140)
* Use latest client library, evohomeclient v0.3.1

* Fix issue #22097: Failed to call service climate/turn_on...

* BUGFIX: handle case where a Zone doesn't have a temperature

* BUGFIX: missing exception handler, and inappropriate delint hints

* Improve exception handling, and also better messages

* improve code (REDACT secrets); remove TODOs

* minor refactor - improve error message

* more refactoring - improve error message

* remove TODOs

* update to latest evohomeclient library

* Use latest client library, evohomeclient v0.3.1

* Fix issue #22097: Failed to call service climate/turn_on...

* BUGFIX: handle case where a Zone doesn't have a temperature

* BUGFIX: missing exception handler, and inappropriate delint hints

* Improve exception handling, and also better messages

* improve code (REDACT secrets); remove TODOs

* minor refactor - improve error message

* more refactoring - improve error message

* remove TODOs

* update to latest evohomeclient library

* fix requests for houndci-bot

* Tidy up requests exception handling

* Correct lint error

* update to latest client library

* minor de-lint

* more cleanup of exceptions, messages

* refactored for new exception

* fix error in requirements*_all.txt

* de-lint

* delint unused import

* import 3rd-party library only inside methods

* change honeywell tests

* delint, fix typo

* we dont log usernames, passwords, etc.

* de-lint
2019-04-02 15:11:26 +02:00
Jc2k
16e0953f26 Fix racy homekit_controller platform setup caused by #22368 (#22655) 2019-04-02 09:57:58 +02:00
Paulus Schoutsen
48189dd152 Run PyLint under Python 3.5 (#22642)
* Run PyLint under Python 3.5

* Remove -q from pip install to debug

* Upgrade setuptools before install

* Use correct cache key for pylint
2019-04-01 21:51:43 -07:00
Johann Kellerman
2578c8525b Qwikswitch fix listen loop (#22600)
* Qwikswitch fix listen loop
* 0.93 fix qwikcord upstream
2019-04-02 05:57:25 +02:00
Jason Hu
7646dc00e0 Add codecov (#22649) 2019-04-01 20:31:05 -07:00
Jason Hu
39eaa7fc8d Add trusted networks deprecating warning (#22487)
* Add trusted networks deprecating warning

* Update auth.py

* Update auth.py

* Update auth.py

* Update auth.py

* Tweak
2019-04-01 17:43:29 -07:00
Jason Hu
1e26151069 Require static-check success first for rest of workflow (#22635)
* Require static-check success first

* Update config.yml
2019-04-01 17:42:04 -07:00
Pascal Vizeli
e708032669 Support GET params for websocket ingress path (#22638) 2019-04-01 17:41:08 -07:00
Malte Franken
a7e613616c change library to georss_generic_client (#22615) 2019-04-01 19:27:58 -04:00
Phil Bruckner
82296aeb71 Amcrest: Add on/off support & attributes. Bump amcrest to 1.3.0 (#22418)
* Amcrest: Add on/off support & attributes to camera entity. Bump amcrest package to 1.3.0.

Add support for turn_on & turn_off services.

Add implementation of is_recording method, as well as brand, model, hardware_version, machine_name, serial_number, software_build and software_version attributes.

Bump amcrest package to 1.3.0 required for above changes and also handles errors in storage commands which resolves #19982.

* Update per review

Rebase to upstream/dev.

Remove video_enabled property and setter and replace with _enable_video_stream
method.

Remove static attributes from camera and sensors.
2019-04-01 17:36:29 -05:00
etheralm
e78709c5f5 Add support for Dyson Purecool 2018 Air Purifiers models TP04 and DP04 (#22215)
* initial commit

initial commit

rewrite tests

fix merge issue with fan component

fix merge issue with fan component

* correct line length

* change to sync_setup_component for tests

* rename services and move services.yaml

* move hepa and carbon filter state from sensor to fan

* add test for duplicate entities

* fix method call tests

* fix docstring
2019-04-01 19:57:11 +02:00
René-Marc Simard
1ce622469d Fix GTFS variable type mismatch (#22624) 2019-04-01 10:49:53 -07:00
Anna Prosvetova
ab2ac60d12 Fix xiaomi vacuum resume functionality (#22626) 2019-04-01 10:44:46 -07:00
Daniel Høyer Iversen
2e02efed10 Handle disonnect bug in Tibber library (#22629) 2019-04-01 10:33:38 -07:00
Paulus Schoutsen
bbc4775eab Disable Z-Wave autoheal (#22628) 2019-04-01 10:20:13 -07:00
VDRainer
431cc63aaf Trend binary sensor check for state unavailable (#22621)
* Trend binary sensor check for state unavailable

Fixes: https://github.com/home-assistant/home-assistant/issues/20210

* Fix pylint
2019-04-01 10:03:18 -07:00
Fredrik Erlandsson
0056fcf904 Make platform setup a coroutine (#22620)
* make setup_platform a coroutine

* Update homeassistant/components/tellduslive/sensor.py

Co-Authored-By: fredrike <fredrik.e@gmail.com>
2019-04-01 10:01:31 -07:00
Pascal Vizeli
1e96d69688 Update face_recognition to 1.2.3 (#22622) 2019-04-01 10:00:25 -07:00
Andrew Sayre
9f2c5b7231 Add source selection to Heos component (#22592)
* Add select source support

* Review feedback changes

* Removed unused import

* Ignore 'umused' import used in typing

* Only include trace back on useful errors

* Remove return from play_source
2019-04-01 11:58:52 -05:00
Pascal Vizeli
a5b03541e9 Delete .travis.yml 2019-04-01 17:16:56 +02:00
Jason Hu
de4d1f2c19 Config CircleCI workflow (#22590)
* Add mypyrc to control typing check, add mypy to circle

* Add translation upload circlci job
2019-04-01 07:12:59 -07:00
Pascal Vizeli
6829ecad9d Hass.io ingress (#22505)
* Fix API stream of snapshot / Add ingress

* fix lint

* Fix stream handling

* Cleanup api handling

* fix typing

* Set proxy header

* Use header constant

* Enable the ingress setup

* fix lint

* Fix name

* Fix tests

* fix lint

* forward params

* Add tests for ingress

* Cleanup cookie handling with aiohttp 3.5

* Add more tests

* Fix tests

* Fix lint

* Fix header handling for steam

* forward header too

* fix lint

* fix flake
2019-04-01 14:16:16 +02:00
Paulus Schoutsen
42e3e878df Cloudhooks for webhook config flows (#22611) 2019-04-01 14:07:12 +02:00
Paulus Schoutsen
c96804954c Only allow admins to enable remote connection (#22609)
* Only allow admins to enable remote connection

* Protect WS API

* Lint
2019-04-01 10:22:51 +02:00
Anders Melchiorsen
282fd225c9 Add netgear_lte connection sensors (#22558) 2019-03-31 23:47:29 -07:00
N1nja98
a61181b10c Fixed brightness reducing after each light change (#22606)
self._brightness max is 255 and hsv brightness max is 100. Assigning 255 based brightness value directly with 100 based hsv reduces brightness eventually to zero.
2019-03-31 23:27:47 -07:00
Robbie Trencheny
7bd8c0d39a Add new mobile_app webhook command: get_zones (#22604)
## Description:

Adds a new `mobile_app` webhook command, `get_zones`, which just returns all zones.

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-31 21:30:45 -07:00
Paulus Schoutsen
fbb28c401e Bumped version to 0.91.0b4 2019-03-31 20:30:30 -07:00
carstenschroeder
734a67ede0 Refactor of ADS integration and introduce ADSEntity (#22583)
* Prevent toogle to false at restart

* change to asyncio.run_coroutine_threadsafe

* refactor ADS platforms; introduce AdsEntity

* fix hound findings

* some formatting

* remove redundant def.

* fix useless super delegation

* fix inconsistent ADS data type for brightness

* fix requested changes

* fix comment
2019-03-31 20:28:43 -07:00
Paulus Schoutsen
0e42cb64d6 Add stream to the default config (#22602) 2019-03-31 20:02:01 -07:00
drjared88
2e61ead4fd Update ONVIF component to SUPPORT_STREAM (#22569)
* Update Onvif component to SUPPORT_STREAM

* Update camera.py

* Update camera.py

* Update camera.py

Remove extra spaces.

* lookup URL when camera is added to hass and add extra guards
2019-03-31 20:02:00 -07:00
Jason Hu
de16059365 Fix name conflict in tests (#22556)
* Fix name conflict in tests

* Lint

* Lint
2019-03-31 20:01:59 -07:00
drjared88
a71fcfb6e5 Update Amcrest component to SUPPORT_STREAM (#22553)
* Update camera.py

Update Amcrest component to SUPPORT_STREAM to allow streaming in the UI and Google Assistant.

* Update camera.py
2019-03-31 20:01:59 -07:00
giefca
8af70d5d19 Google assistant: add blinds trait for covers (#22336)
* Update const.py

* Update smart_home.py

* Update trait.py

* Update test_trait.py

* Update smart_home.py

* Update test_trait.py

* Update trait.py

* Update trait.py

* Update test_trait.py

* Update test_trait.py

* Update __init__.py

* Update test_trait.py

* Change email

* Trying to correct CLA

* Update __init__.py

* Update trait.py

* Update trait.py

* Update trait.py

* Update trait.py

* Update __init__.py

* Update test_trait.py

* Update test_google_assistant.py

* Update trait.py

* Update trait.py

* Update test_trait.py

* Update test_trait.py
2019-03-31 20:01:59 -07:00
Paulus Schoutsen
ec9a58442b Updated frontend to 20190331.0 2019-03-31 20:01:35 -07:00
Paulus Schoutsen
804f1d1cc8 Update translations 2019-03-31 20:01:23 -07:00
Paulus Schoutsen
9a4b0cfb9b Updated frontend to 20190331.0 2019-03-31 19:52:44 -07:00
Aaron Bach
3d8efd4200 Add permission checking to all RainMachine services (#22399)
* Add permission checking to all RainMachine services

* Linting

* Some initial work

* Owner comments

* Test in place (I think)

* Linting

* Update conftest.py
2019-03-31 19:32:55 -07:00
Paulus Schoutsen
50a0504e07 Add stream to the default config (#22602) 2019-03-31 17:14:19 -07:00
drjared88
e085383d2d Update ONVIF component to SUPPORT_STREAM (#22569)
* Update Onvif component to SUPPORT_STREAM

* Update camera.py

* Update camera.py

* Update camera.py

Remove extra spaces.

* lookup URL when camera is added to hass and add extra guards
2019-03-31 15:12:55 -07:00
René-Marc Simard
755571abe3 Fix gtfs typing and logger issues (#22572)
## Description:
Some code cleanup requests where raised in the [latest merged GTFS commit](9153e3b671). This new PR aims to address them, including:
- Clear all typing issues.
- Respect logger levels and format.
- Simplify some non-pythonic lines.

This sensor now passes `mypy` testing, but does so by ignoring two lines with `# type: ignore`.

**Related issue (if applicable):** fixes issues raised by @MartinHjelmare in #20966

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
2019-03-31 14:21:45 -07:00
Sander Cornelissen
7d7b931163 Retrying connecting Influxdb at setup (#22567)
* Also retry Influxdb at setup()

* Use event.call_later() for retry setup Influxdb

* Fix max line length in setup() in Influxdb

* Add extra space before comment

* Fix sec -> seconds and add return True
2019-03-31 16:00:48 -04:00
Markus Jankowski
5abfc84382 Clean up homematicip cloud (#22589)
* Code Cleanup

- removed unused constants
- more icons on binary_sensor groups
- alligned  code for device_state_attributes
- fixed temperature unit origin for weather

* removed icons
2019-03-31 21:18:45 +02:00
OleksandrBerchenko
842a36dc9e Rewrite Osram Lightify component (#22184)
* Rewrite Osram Lightify component

* Update python-lightify version to 1.0.7.2

* Remove unneeded code

* 1. Remove changes in light/__init__.py, 2. Set properties to None by default

* Fix typo
2019-03-31 21:02:45 +02:00
Anders Melchiorsen
1b0b5b4b8c Fix lightwave config validation (#22576) 2019-03-31 09:19:39 -05:00
OleksandrBerchenko
800b1c7fe6 Fix typo in light/__init__.py (#22581) 2019-03-31 13:43:54 +02:00
Jason Hu
388d614e30 Ignore flaky test (#22563) 2019-03-30 21:10:32 -07:00
emontnemery
4d1633807c Turn light off if brightness is 0 (#22400)
* Turn light off if brightness is 0

* Lint

* Review comments

* Lint

* Fixup, add tests

* Fix trådfri light + test
2019-03-30 21:04:32 -07:00
Chris Helming
f6e9dd4832 Update Foscam component to support stream source (#22568)
* Update Foscam to support stream source

* Removing spaces and tabs

* Changing to Python3-style string formatting

* Adding '_media_port' to hopefully cover other models
2019-03-30 21:01:58 -07:00
emontnemery
54777a81bc Forward media control to playing group (#22566)
* Forward media control to playing group

* Fix forwarding control to dynamic group

* Fix, add tests
2019-03-30 20:07:01 -07:00
Pascal Vizeli
71ecaa4385 Delete main.workflow 2019-03-30 21:59:15 +01:00
Paulus Schoutsen
e70931da67 Delete azure-pipelines.yml 2019-03-30 12:30:35 -07:00
Greg Dowling
9bf0f60784 Bump pyloopenergy library to 0.1.2 (#22561) 2019-03-30 12:52:54 -05:00
Klaudiusz Staniek
2eafa5f81a Ampio Smog Air Quality Sensor (#21152)
* Initial commit for Ampio Smog Air Quality Sensor

* coveragerc and requirements_all update

* Lint fixed

* Moved to vendor folder

* Updated according to review

* Docs string fix

* Docstring fix

* Docstring fix

* Requirements fixed

* Lint fix

* .coveragerc updated
2019-03-30 18:49:59 +01:00
carstenschroeder
34324afbde Prevent toogle to false at restart of ADS platforms (#22522)
* Prevent toogle to false at restart

* change to asyncio.run_coroutine_threadsafe
2019-03-30 18:47:39 +01:00
emontnemery
2e375aa802 Improve handling of audio groups (#22396)
* Improve handling of audio groups

* Review comments

* Fix tests

* Add tests

* Review comment

* Bump pychromecast
2019-03-30 10:19:18 -07:00
Jason Hu
64306922b1 Fix name conflict in tests (#22556)
* Fix name conflict in tests

* Lint

* Lint
2019-03-30 08:30:21 -07:00
Andrew Sayre
ecba87179f Add Heos config flow (#22554)
* Add UI initiated config flow

* Fix alpha order
2019-03-30 08:52:17 -05:00
Marco Orovecchia
b6ac964df3 Added support for transitions for nanoleaf light (#22192)
* Added transition support for nanoleaf

* Formatting for comments

* Inline comment instead of additional line

* Set color_temp before starting transition
2019-03-30 12:08:30 +01:00
Jc2k
906f0113ad Add more HomeKit device enumeration tests (#22194)
* Test that Aqara Gateway, Ecobee 3 and Lennox E30 is correctly enumerated

* Move json to fixtures directory

* Move IO to executor
2019-03-30 11:21:11 +01:00
Anders Melchiorsen
1a39fb4de7 Add table with netgear_lte sensor units (#22508) 2019-03-30 10:09:36 +01:00
Kevin Cooper
4b9e3258dc Add command_template and value_template for MQTT alarm (#21438)
* Option to send pin code with the MQTT payload for MQTT alarm

* publish code via json

Add publish code via json
add code_disarm_required

* publish code via json

Add publish code via json
add code_disarm_required

* implemented command_template

* Fix issue with night arm and add template test

* implemented value_template for mqtt alarm

* Fixed merge errors

* Requested changes

* Resolve lint errors

* Resolve hound issues

* Fix test formatting
2019-03-30 07:36:10 +01:00
Andrew Sayre
1bfe86b30d Change HEOS component library and add basic config flow (#22517)
* Update heos lib

* Update requirements files

* Removed unecessary mock_coro usage

* Remove assert_called_once usage

* Updates from review feedback

* Remove extra param to error format
2019-03-29 21:10:00 -07:00
drjared88
fe8e51e2e9 Update Amcrest component to SUPPORT_STREAM (#22553)
* Update camera.py

Update Amcrest component to SUPPORT_STREAM to allow streaming in the UI and Google Assistant.

* Update camera.py
2019-03-29 20:53:01 -07:00
giefca
b04fd08cea Google assistant: add blinds trait for covers (#22336)
* Update const.py

* Update smart_home.py

* Update trait.py

* Update test_trait.py

* Update smart_home.py

* Update test_trait.py

* Update trait.py

* Update trait.py

* Update test_trait.py

* Update test_trait.py

* Update __init__.py

* Update test_trait.py

* Change email

* Trying to correct CLA

* Update __init__.py

* Update trait.py

* Update trait.py

* Update trait.py

* Update trait.py

* Update __init__.py

* Update test_trait.py

* Update test_google_assistant.py

* Update trait.py

* Update trait.py

* Update test_trait.py

* Update test_trait.py
2019-03-29 20:51:47 -07:00
Paulus Schoutsen
95a7077b41 Move core services.yaml file to Home Assistant integration (#22489)
* Move services.yaml to correct dir

* Remove special case for HA servicesgs
2019-03-29 20:48:45 -07:00
Julien Roy
8e975395be upgrade pylinky to 0.3.3 (#22544) 2019-03-29 19:22:28 -07:00
Paulus Schoutsen
b1a6539290 Bumped version to 0.91.0b3 2019-03-29 17:05:40 -07:00
Paulus Schoutsen
3ad4419cb6 Fix platform warnings (#22551) 2019-03-29 17:05:30 -07:00
Paulus Schoutsen
f9f100b575 Add support for streaming to ffmpeg (#22549) 2019-03-29 17:05:29 -07:00
Paulus Schoutsen
cc886821bc Fix platform warnings (#22551) 2019-03-29 17:04:59 -07:00
Paulus Schoutsen
c05bff7d17 Add support for streaming to ffmpeg (#22549) 2019-03-29 17:03:02 -07:00
Paulus Schoutsen
65c47824a0 Updated frontend to 20190329.0 2019-03-29 16:47:27 -07:00
Paulus Schoutsen
fbb9097f6c Updated frontend to 20190329.0 2019-03-29 16:46:15 -07:00
Jason Hu
e81e5ea796 Set up Circleci workflow (#22519)
* Set up Circleci workflow

* Update python tag

* Add pre-test job to cache the requirements

* Upgrade pip itself

* Use 3.7 for lint

* Parallelize pylint

* Tweak run gen_requirements_all

* tweak cache key
2019-03-29 16:37:45 -07:00
Paulus Schoutsen
c4a4af7c29 Bumped version to 0.91.0b2 2019-03-29 14:07:22 -07:00
damarco
24095c0d7b Bump zigpy (#22545) 2019-03-29 14:07:18 -07:00
Steven Looman
ae18705c45 Upgrade to async_upnp_client==0.14.7 (#22543) 2019-03-29 14:07:17 -07:00
Jason Hu
ab642ca4eb Fix tts Great Migration issue (#22539) 2019-03-29 14:07:16 -07:00
David F. Mulcahey
b7bc520a0e clean up channel configuration (#22534) 2019-03-29 14:07:16 -07:00
ktnrg45
53595e76d8 PS4 bump to 0.5.2 (#22523)
* Bump pyps4 to 0.5.2

* Bump pyps4 to 0.5.2

* Bump pyps4 to 0.5.2
2019-03-29 14:07:15 -07:00
David F. Mulcahey
173ef7cac5 Do not use zha default light polling (#22513)
* don't use default light polling

* review comment
2019-03-29 14:07:15 -07:00
Jason Hu
9f72764cff Fix lint on dev (#22512)
## Description:

Fix a lint issue in credstash script.


**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>

## Example entry for `configuration.yaml` (if applicable):
```yaml

```

## Checklist:
  - [ ] 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.

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:
  - [ ] New dependencies have been added to the `REQUIREMENTS` variable ([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`.

If the code does not interact with devices:
  - [ ] Tests have been added to verify that the new code works.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
2019-03-29 14:07:14 -07:00
Jason Hu
77f7a53d9f Remove botocore dependency from credstash script (#22511)
* Remove botocore dependency from credstash script

* Update requirements_all.txt

* Update pylintrc

* Update credstash.py
2019-03-29 14:07:13 -07:00
zewelor
fae8265a37 Fixes for yeelight availbility state (#22502) 2019-03-29 14:07:13 -07:00
mvn23
a95fb809a5 Update pyotgw to 0.4b3 (#22496) 2019-03-29 14:07:12 -07:00
Jason Hu
21917f4dc4 Fix dev branch (#22493) 2019-03-29 14:07:12 -07:00
Sebastian Muszynski
9aa5b904c6 Fix regression of the xiaomi_aqara config validation (#22435)
* Fix regression of the xiaomi_aqara config validation

* Make the key optional again

* Add base schema

* Remove the GW_MAC default
2019-03-29 14:07:11 -07:00
damarco
c0ce86fa8e Bump zigpy (#22545) 2019-03-29 14:01:51 -07:00
Steven Looman
613c356c5f Upgrade to async_upnp_client==0.14.7 (#22543) 2019-03-29 13:41:50 -07:00
Sebastian Muszynski
f46a8378b0 Fix regression of the xiaomi_aqara config validation (#22435)
* Fix regression of the xiaomi_aqara config validation

* Make the key optional again

* Add base schema

* Remove the GW_MAC default
2019-03-29 13:41:13 -07:00
David F. Mulcahey
6401920019 clean up channel configuration (#22534) 2019-03-29 16:41:04 -04:00
ktnrg45
a07919ced2 PS4 bump to 0.5.2 (#22523)
* Bump pyps4 to 0.5.2

* Bump pyps4 to 0.5.2

* Bump pyps4 to 0.5.2
2019-03-29 12:10:28 -07:00
Yaroslav
daf6b01b98 Ring camera improvements (#22526)
* Ring camera improvements

Expose last_video_id attribute.
Fix missing last_video_url
Only update last_video_id when video is ready

* Fix formatting
2019-03-29 12:10:00 -07:00
Jason Hu
c31ab7a175 Fix tts Great Migration issue (#22539) 2019-03-29 11:45:02 -07:00
zewelor
4e78d895d9 Fixes for yeelight availbility state (#22502) 2019-03-29 18:43:29 +01:00
Paulus Schoutsen
ec076c7c10 Azure Pipelines: No Python 3.5.3 available, use any 3.5 version [skip ci] 2019-03-29 09:21:20 -07:00
Paulus Schoutsen
e7d3b22b46 Add lint task to Azure Pipelines [skip ci] 2019-03-29 09:18:25 -07:00
Paulus Schoutsen
75eeeae920 Set up CI with Azure Pipelines [skip ci] 2019-03-29 09:11:13 -07:00
David F. Mulcahey
6dc127780e Do not use zha default light polling (#22513)
* don't use default light polling

* review comment
2019-03-29 16:52:13 +01:00
Kyle Niewiada
1050baa9cc throw PlatformNotReady if unable to connect (#22515)
Throw `PlatformNotReady` for when the device disconnects, or when the Home Assistant is booting and the ADB server is not ready yet.
2019-03-29 08:08:36 -07:00
Robert Svensson
5f6037d563 Axis component reflect device availability (#22401) 2019-03-29 15:20:12 +01:00
Aaron Bach
f4625fd561 Speed up status updating in SimpliSafe (#22506)
* Speed up status updating in SimpliSafe

* Linting

* Member comments
2019-03-29 01:38:58 -07:00
mvn23
424543f34a Update pyotgw to 0.4b3 (#22496) 2019-03-29 08:28:50 +01:00
Andrew Sayre
78047c8c3c Fix .coveragerc from merge/rebase (#22516)
* Fix coveragerc

* Fix coveragerc
2019-03-28 20:01:53 -07:00
yosilevy
e14dbfb006 Add google calendar max_results config option (#21874)
* Added max_results config capability to google calendar (people are creating custom components just to override that)

* Dummy commit

* Dummy commit 2

* Changed to positive_int

* Removed double imports
2019-03-28 19:56:12 -07:00
Andreas Rydbrink
01052f516b Add HEOS media player component (#21721)
## Description:
Denon HEOS media player.

**Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** home-assistant/home-assistant.io#8848

## Example entry for `configuration.yaml` (if applicable):
```yaml
heos:
  host: HEOS-1                              
```

## Checklist:
  - [X] The code change is tested and works locally.
  - [X] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [X] There is no commented out code in this PR.

If user exposed functionality or configuration variables are added/changed:
  - [X] 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:
  - [X] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]).
  - [X] New dependencies are only imported inside functions that use them ([example][ex-import]).
  - [X] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
  - [X] New files were added to `.coveragerc`.

If the code does not interact with devices:
  - [ ] Tests have been added to verify that the new code works.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23


Co-authored-by: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com>
2019-03-28 19:03:02 -07:00
Jason Hu
709419e465 Fix lint on dev (#22512)
## Description:

Fix a lint issue in credstash script.


**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>

## Example entry for `configuration.yaml` (if applicable):
```yaml

```

## Checklist:
  - [ ] 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.

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:
  - [ ] New dependencies have been added to the `REQUIREMENTS` variable ([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`.

If the code does not interact with devices:
  - [ ] Tests have been added to verify that the new code works.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
2019-03-28 15:33:21 -07:00
Andre Lengwenus
ee8cd861e0 Add LCN binary_sensor component (#22341) 2019-03-28 23:09:45 +01:00
Jason Hu
821a90fa54 Remove botocore dependency from credstash script (#22511)
* Remove botocore dependency from credstash script

* Update requirements_all.txt

* Update pylintrc

* Update credstash.py
2019-03-28 14:37:44 -07:00
Jason Hu
8874422e8a Fix Circleci config (#22509)
* Add libav depends on circleci

* tweak circleci config
2019-03-28 14:37:10 -07:00
Jason Hu
59476ab475 A very basic Circleci setup (#22503)
* Add circleci support

* Add buildpack-deps

* Install libudev-dev

* sudo

* always run test

* Add test report

* no sugar

* quite pytest

* better junit test result

* Add $CODE_COVERAGE env var
2019-03-28 09:54:49 -07:00
Jason Hu
8d86722c0e Fix dev branch (#22493) 2019-03-28 11:09:12 +01:00
Paulus Schoutsen
615b1cbfc7 Bumped version to 0.91.0b1 2019-03-27 23:50:58 -07:00
Paulus Schoutsen
3a406f5677 Fix YAML 2019-03-27 23:49:34 -07:00
Paulus Schoutsen
4db224ceb5 Fix YAML 2019-03-27 23:49:10 -07:00
Paulus Schoutsen
5d8d905822 Version bump to 0.92.0dev0 2019-03-27 22:10:35 -07:00
Paulus Schoutsen
a2c9834852 Bumped version to 0.91.0b0 2019-03-27 22:09:25 -07:00
Paulus Schoutsen
4f820aef83 Merge remote-tracking branch 'origin/master' into dev 2019-03-27 22:08:48 -07:00
Jason Hu
6ba2891604 Add trusted_users in trusted networks auth provider (#22478) 2019-03-27 21:53:11 -07:00
Jason Hunter
26726af689 Stream Record Service (#22456)
* Initial commit of record service for live streams

* fix lint

* update service descriptions

* add tests

* fix lint
2019-03-27 21:47:07 -07:00
Paulus Schoutsen
9d21afa444 Update translations 2019-03-27 21:32:58 -07:00
Paulus Schoutsen
05cdab03b1 Updated frontend to 20190327.0 2019-03-27 21:32:40 -07:00
Clifford W. Hansen
ece9c62ee8 Add game and app media types (#22459)
* Added game and app media types

* Changed media type to game from music

* Removed app type as it is not used yet
2019-03-27 21:20:43 -07:00
Paulus Schoutsen
a69080ba73 Print error instead of warning for custom platforms in legacy format (#22486)
* Legacy platform format prints error

* Enforce no partial overlays
2019-03-27 20:52:28 -07:00
Robbie Trencheny
7741ec4d5a Great migration notify (#22406)
* Move notify platforms into components

* Move notify tests

* Fix notify tests

* More fixes

* Update requirements

* Update .coveragerc

* Run gen reqs
2019-03-27 20:36:13 -07:00
Paulus Schoutsen
92457ca5ca Fix syntax error 2019-03-27 20:16:00 -07:00
Aaron Bach
8777146053 Fix too-abrubt SimpliSafe data refresh termination on error (#22466) 2019-03-27 20:14:49 -07:00
Rohan Kapoor
c4eab21736 Mopar split (#21526)
* Split out mopar into a component and sensor platform

* Add the mopar switch platform

* Add the mopar lock platform

* Clean up and bump version

* Update per review

* Re-add service to trigger horn

* Clean up again

* Don't call async from sync context

* Lint

* Implement changes from review

* Lint

* A little more clean up
2019-03-27 20:09:36 -07:00
Heine Furubotten
f11f5255ae Entur upgrade to v0.2.0: async polling, number of departures, omit non boarding departures (#22001)
* The Great Migration

* removed outdated tests

* Upgraded enturclient to v0.2.0
- client has gone async
- configurable if non boarding departures should be omitted from result
- configurable how many departures should be shown
- more clear which attributes are included and when

* reduced nesting and clearing of attributes

* Removed test data

* ensure attribution and stop id in attributes

* docstring fixes

* fix rebase errors
went a bit too fast on continue on one of the conflicts..

* fix test requirements comment from gen
2019-03-27 20:04:35 -07:00
Anders Melchiorsen
a1369c2fee Incoming SMS handling for netgear_lte (#22402)
* Fire netgear_lte events for incoming SMS

* Add netgear_lte.delete_sms service call

* Fix log statement

* Add services.yaml
2019-03-27 20:02:04 -07:00
Jc2k
8bf5e57b7f Move HKDevice into connection (#22430) 2019-03-27 20:01:10 -07:00
Jack Wilsdon
14ceb8472f Return percentage information in Alexa Smart Home response (#22440) 2019-03-27 19:58:52 -07:00
Finbarr Brady
e022f4465c Bump pypi again for Cisco Mobility Express (#22467)
* Fix empty device clId

Fix for https://github.com/fbradyirl/ciscomobilityexpress/issues/13

* Update requirements_all.txt
2019-03-27 19:58:06 -07:00
Maciej Bieniek
b8e38c1b25 Add new data fields and bump python-join-api (#22472)
* Add new data fields and bump python-join-api

* Update __init__.py
2019-03-27 19:56:27 -07:00
Daniel Høyer Iversen
c7904a4b37 Improve Sensibo error handling (#22475)
* Handle sensibo exception

* improve sensibo
2019-03-27 19:54:44 -07:00
Robert Svensson
8f3434c2ab Fix events so they work with multiple devices (#22477) 2019-03-27 19:54:27 -07:00
Nate Clark
d13c892b28 fix inverse state changes for binary sensors (#22479) 2019-03-27 19:54:01 -07:00
Sebastian Muszynski
26d4736ebf Fix auto discovery of yeelights (#22481)
* Fix auto discovery of yeelights

* Fix lint
2019-03-27 19:51:22 -07:00
Alexei Chetroi
e670491c86 Targeted ZHA permit joins. (#22482)
* Targeted ZHA permit service.

* Convert IEEE string to EUI64 usiv vol schema.

* Update test units.

* Lint.

isort imports.
2019-03-27 19:50:52 -07:00
Andrew Sayre
e26a5abb2b Don't return cover position when not supported (#22484) 2019-03-27 19:50:02 -07:00
Rohan Kapoor
78e162c1d3 Centralize all usages of host as a configuration param to the constant CONF_HOST (#22458)
* Centralize all usages of  as a configuration param to the constant CONF_HOST

* Clean up test
2019-03-27 19:48:05 -07:00
dilruacs
9176e13a97 Modify check for ADB public key (#22378)
* Remove check for public key

* Remove has_adb_files, directly call cv.isfile

* Check for missing adbkey.pub, create dummy if not found

* Reorder imports

* Bumped androidtv library version, deactivated pubkey test

* Code works without pubkey, removed function

* Removed "import os", not needed anymore

* Bump library version
2019-03-27 20:19:24 -05:00
René-Marc Simard
217782cd05 Cache GTFS metadata and expose utility attributes (breaking change) (#20966)
## Description:
Current sensor updates run 7 additional SQLite database queries to populate attributes, on top of the bus schedule queries themselves. Double that if you have two sensors. That leads to a lot of slowdowns for everything else when using an SD card!

Considering that some data never changes (agency, routes...) and that others like departure times are good until invalidated, let's fetch such metadata at first then only when relevant changes do occur.

**Breaking Change:**
GTFS sensor attributes are now named using the standard snake_case format.

### Work performed:
- All metadata queries are now cached.
- Metadata queries are now all regrouped in the `update()` method.
- Attributes assembling is now done in ~~`device_state_attributes()` where it belongs.~~ in a utility method called from `update()`, for code clarity and since there is potential I/O from SQLAlchemy.
- As a bonus, many metadata entries with cryptic values have complementary entries added that provide easier to use data:
	- .\* Stop Drop Off Type: .\* Stop Drop Off Type **State** -> (string, unknown)
	- .\* Stop Pickup Type: .\* Stop Pickup Type **State** -> (string, unknown)
	- .\* Stop Timepoint: .\* Stop Timepoint **Exact** -> boolean
	- .\* Station Location Type: .\* Station Location Type **Name** -> string
	- .\* Wheelchair Boarding: .\* Wheelchair Boarding **Available** -> (boolean, unknown)
	- Route Type: Route Type **Name** (string)
	- Trip Bikes Allowed: Trip Bikes Allowed **State** -> (boolean, unknown)
	- Trip Wheelchair Access: Trip Wheelchair Access **Available** -> (boolean, unknown)
- Attribute names are now using snake_case.
- Added type hints.

**Related issue (if applicable):** fixes #21222

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-27 17:58:23 -07:00
Jc2k
d8817bb127 Remove homekit_controller duplicate legacy pairing loader code (#22442) 2019-03-28 00:36:50 +01:00
Anders Melchiorsen
90c4f6f6e5 Do data extraction in sensors (#22444)
* Do data extraction in sensors

* Hopefully fix lint
2019-03-27 19:24:02 -04:00
Jason Hu
f795d03503 Fix aws.notify platform schema (#22374)
* Fix aws component notify platform schema

* Address code review comment

* Do not allow load aws.notify from notify component

* Revert unrelated translation update

* Review comment
2019-03-27 14:53:06 -07:00
Gido
24c7c2aa6e Solaredge new sensors (#21047)
* Remove unused hass parameter for SolarEdgeData

* Add factory to create different types of sensors
Rename SolarEdgeSensor to SolarEdgeOverviewSensor
Rename SolarEdgeData to SolarEdgeOverviewDataService
Remove unused hass parameter in SolarEdgeOverviewDataService

* Add SolarEdgeDetailsDataService to retrieve details data
Add SolarEdgeDetailsSensor to report details data
Add abstract class SolarEdgeSensor
Add details sensor types

* Combine multiple details sensor into one sensor with attributes

* Fix pylint and flake8 errors

* Resolve conflict with solaredge component update

* Add SolarEdgeInventoryDataService to retrieve inventory information
Add SolarEdgeInventorySensor to view inventory information
Add inverters to monitored_conditions

* Fix pylint and flake8 errors

* Add additional monitored variables for solaredge

* Add new sensors to solaredge component

* Add SolarEdgePowerFlowDataService
Add SolarEdgePowerFlowSensor
Add new monitored_conditions for power consumption and grid, load and
solar power production/consumption

* Set entity_id for each sensor based on platform and sensor type

* Fix flake8 and pylint errors

* Add check for connections in return data

* Fix pylint and flake8 errors

* Renamed state_attributes to device_state_attributes
Moved request import to top

* Remove explicit definition of entity_id

* Fix pylint and flake8 errors

* Add check for None before adding sensor

* Update SolarEdgeSensorFactory with initial dict which maps sensor_key to
entity class and data service

* Update attribute values to snakecase
Added stingcase as requirement

* Update requirements_all.txt to include stringcase for solaredge

* Update some initial values for data and unit_of_measurement
Update sensor factory
2019-03-27 17:08:52 -04:00
Nate Clark
2b48ecd5c5 better algorithm for computing unique_id (#22389) 2019-03-27 16:47:03 -04:00
Fredrik Erlandsson
71b800457b Add switches to control Daikin Airbase zones (#22417)
* initial AirBase zone support

* fix zone name

* version bump pydaikin

* don't use get()
2019-03-27 16:37:21 -04:00
Ryan Claussen
c3f090af17 Add hourly forecasts to Dark Sky (#21820) 2019-03-27 20:11:25 +00:00
Leonardo Merza
29ad3961e5 Use voluptuous error string for websocket validation error (#21883)
* use voluptuous error string to websocket validation error

* added exception logging to websocket error

* add detailed message to websocket validation error

* add error message to websocket validation error

* Add humanize error for websocket invalid vol error

* Add humanize error for websocket invalid vol error

* Add humanize error for websocket invalid vol error
2019-03-27 10:40:39 -07:00
Robert Svensson
52437f6246 Axis devices support device registry (#22367)
* Add support for device registry

* Fix test
2019-03-27 18:25:01 +01:00
Penny Wood
646c4a7137 Bootstrap to start registry loading early (#22321)
* Registries store directly in data on loading.

* Loading registries concurent with stage 1.

* Removed comments
2019-03-27 22:06:20 +08:00
zewelor
4de2efd07f Add support for yeelight ceiling ambilight (#22346) 2019-03-27 13:39:55 +01:00
Alexei Chetroi
6540114ec5 Update ZHA component CODEOWNERS (#22452) 2019-03-27 07:17:10 -04:00
zewelor
fa9a6f072e Add myself as codeowner for yeelight component (#22438) 2019-03-27 08:02:30 +01:00
Pascal Vizeli
a55afa8119 Update ha-ffmpeg 2.0 (#22427) 2019-03-27 07:55:05 +01:00
Thomas Lovén
19d99ddf57 Lower severity level of log messages from http.view (#21091) 2019-03-26 19:18:32 -04:00
Paulus Schoutsen
1766536812 Fix test name (#22421) 2019-03-26 15:24:28 -07:00
Finbarr Brady
02b12ec1b9 Adding conf for deep standby, wake and specific source bouquet of Enigma2 (#22393)
* - adding deep standby, conf for wake and specify source bouquet

* set defaults to strings

* bump pip

* bump pip

* bump pip

* bump pip

* bump pip

* bump pip
2019-03-26 17:49:53 -04:00
Pascal Vizeli
80250add9e Update homeassistant-pyozw to 0.1.3 (#22433) 2019-03-26 17:42:43 -04:00
Finbarr Brady
7e3567319f ciscomobilityexpress pypi version update (#22431)
* Bump pip

* Bump ciscomobilityexpress to 0.1.4
2019-03-26 21:13:56 +01:00
Anders Melchiorsen
afa99c9189 Use dispatcher for netgear_lte state updates (#22328)
* Use dispatcher for netgear_lte state updates

* Also dispatch unavailable state
2019-03-26 08:06:11 -07:00
Jason Hu
7519e8d417 Update translate, fix dev build error (#22419) 2019-03-26 07:48:26 -07:00
Jc2k
133ae63ed0 Add missing append (#22414) 2019-03-26 07:39:05 -07:00
Pascal Vizeli
3fddf5df08 Enable hass.io panel without ping (#22388)
* Enable hass.io panel without ping

* fix tests
2019-03-26 07:38:25 -07:00
cgtobi
a27e821e8b Migrate tts (#22403)
* Migrate tts

* Migrate tts tests

* Update requirements

* Fix path to demo mp3
2019-03-26 07:34:16 -07:00
Kevin Fronczak
c71e5ed588 Changed busy error to warning (#22398) 2019-03-26 09:20:50 -04:00
zewelor
2cebf9ef71 Fix yeelight state update (#22373) 2019-03-26 09:18:53 -04:00
David F. Mulcahey
3cca3c37f0 zha fixes (#22381) 2019-03-26 09:17:43 -04:00
Daniel Høyer Iversen
77e7b63f4a Tibber add support for Watty (#22397) 2019-03-26 14:02:10 +01:00
Paulus Schoutsen
65432ba552 Move core stuff into Home Assistant integration (#22407)
* Move core stuff into Home Assistant integration

* Lint
2019-03-26 13:38:32 +01:00
Jason Hunter
bad0a8b342 Camera Preferences + Preload Stream (#22339)
* initial commit for camera preferences and preload stream

* cleanup and add tests

* respect camera preferences on each request stream call

* return the new prefs after update
2019-03-26 08:31:29 -04:00
Jason Hunter
baa4945944 reset unsub to None on timeout (#22404) 2019-03-26 08:39:09 +01:00
Jason Hu
e85b089eff Set default parallel_update value should base on async_update (#22149)
* Set default parallel_update value should base on async_update

* Set default parallel_update value should base on async_update

* Delay the parallel_update_semaphore creation

* Remove outdated comment
2019-03-25 23:53:36 -07:00
Jc2k
a62c116959 Remove get_serial helper that is no longer needed. (#22368) 2019-03-25 23:49:51 -07:00
Sebastian Muszynski
6fa8fdf555 Fix data_key of the xiaomi_aqara cover for LAN protocol v2 (#22358) 2019-03-25 23:46:00 -07:00
Robert Svensson
79445a7ccc deCONZ support Xiaomi vibration sensor (#22366)
* Martin pointed out in previous PR that no ending '.' in logging

* Add support for Xiaomi vibration sensor
2019-03-25 23:43:58 -07:00
Nick Whyte
73b38572f0 Add infer_arming_state option to ness alarm (#22379)
* Add infer_arming_state option to ness alarm

* actually use config value

* 🤦‍♂️
2019-03-25 23:43:24 -07:00
Jc2k
b2ba9d07ca Fix unavailable state for homekit locks and covers (#22390) 2019-03-25 23:40:28 -07:00
Daniel Shokouhi
8aef8c6bb4 Update ring_doorbell to 0.2.3 (#22395) 2019-03-25 23:37:59 -07:00
uchagani
0c4380a78d remove config sections from hass.config.components (#22370)
* remove config sections from hass.config.components

* fix tests
2019-03-25 22:36:39 -07:00
René-Marc Simard
42c27e5b72 Search GTFS departures across midnight (#20992) 2019-03-25 21:51:49 -07:00
Niccolò Maggioni
5ad3e75a4d Support for Plex sensor with enforced SSL (#21432) 2019-03-25 20:45:13 +01:00
Fredrik Erlandsson
6ffe9ad473 updated pydaikin (#22382) 2019-03-25 19:37:31 +01:00
zewelor
6a74c403c0 Update python yeelight and add nightlight mode sensor (#22345) 2019-03-25 19:06:43 +01:00
lapy
2731777c7e Add traccar events (#22348)
* Add import_events(), small refactoring, traccar_id

I isolated the code that imports traccar tracking data and added a new function that imports the traccar events to make them run in parallel and reduce delay. The events that are imported in hass, will be fired with the prefix "traccar_". Furthermore a traccar_id is now imported in hass entities, useful for matching the traccar hass entities with the traccar hass events in the most accurate way.

* bump pytraccar version

* Code format fix

* Code format fix 2

* Code format fix 3

* Implement requested changes

* Add new traccar dependency

* Fix line too long

* Update device_tracker.py

* Update requirements_all.txt
2019-03-25 18:52:53 +01:00
Andrew
a59487a438 Fix TpLink Device Tracker initialize error (#22349)
Catch RequestException instead of ConnectionError
In some cases TpLinkDeviceScanner throws various successors of
RequestException. They should be caught.
2019-03-25 10:25:49 -07:00
Paulus Schoutsen
f1a0ad9e4a Frontend indicate require admin (#22272)
* Allow panels to indicate they are meant for admins

* Panels to indicate when they require admin access

* Do not return admin-only panels to non-admin users

* Fix flake8
2019-03-25 10:04:35 -07:00
Pascal Vizeli
b57d809dad Update hass-nabucasa & fix state (#22385)
* Update hass-nabucasa & fix state

* Fix lint
2019-03-25 09:43:15 -07:00
Jc2k
f997957054 Remove unused const (#22383) 2019-03-25 16:28:34 +01:00
Jeff Irion
c8048e1aff Allow for custom turn on/off commands (#22354) 2019-03-25 08:37:10 -04:00
ktnrg45
17a96c6d9b Improve PS4 media art fetching and config flow (#22167)
* improved config flow

* Added errors, docs url

* Added errors, docs url

* Added manual config mode

* Add tests for manual/auto host input

* fix inline docs

* fix inline docs

* Changed region list

* Added deprecated region message

* removed DEFAULT_REGION

* Added close method

* Fixes

* Update const.py

* Update const.py

* Update const.py

* Update test_config_flow.py

* Added invalid pin errors

* Update strings.json

* Update strings.json

* bump pyps4 to 0.5.0

* Bump pyps4 0.5.0

* Bump pyps4 to 0.5.0

* test fixes

* pylint

* Change error reference

* remove pin messages

* remove pin messages

* Update en.json

* remove pin tests

* fix tests

* update vol

* Vol fix

* Update config_flow.py

* Add migration for v1 entry

* lint

* fixes

* typo

* fix

* Update config_flow.py

* Fix vol

* Executor job for io method.

* Update __init__.py

* blank line

* Update __init__.py

* Update tests/components/ps4/test_config_flow.py

Co-Authored-By: ktnrg45 <38207570+ktnrg45@users.noreply.github.com>
2019-03-25 08:25:15 -04:00
zewelor
96133f5e6b Improve yeelight component (#22347) 2019-03-25 08:50:47 +01:00
Jc2k
af4b85d39d Give HomeKit locks better names by default (#22333)
## Description:

This is a follow up to #22171. There we set the name of an entity based on the `accessory-information` homekit service, rather than using the zeroconf/avahi name metadata. Unfortunately Lock also sets its name from zeroconf directly, rather than picking it up from the base class. This test updates it to be like the other homekit entities and use the base class.

(This is from my ongoing homekit_controller configentry branch).

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-24 18:21:04 -07:00
fabtesta
324a7c7875 Add ClickSend "caller" option (#20780)
* removed "from" parameter from ClickSend API call

Removed "from" parameter from API call to let ClickSend choose a random number and be more compliant with some cellular networks that do not allow incoming calls from the same recipient number.

* fixed "line too long (94 > 79 characters)" houndci code review

fixed "line too long (94 > 79 characters)" houndci code review

* Added new component optional parameter "caller".
If defined is used to override default logic that uses recipient phone number in "from" API call parameter

* Removed default value for CALLER parameter. If not defined then will take the RECIPIENT value.
2019-03-24 18:13:56 -07:00
Nick Horvath
c59d45caa3 Expose detailed Ecobee equipment status (#20767)
* ecobee: expose detailed equipment status

* Fix #18244 for ecobee by moving current_operation property to current_operation_mode which is more accurate and defining current_operation properly, thanks @ZetaPhoenix

* fix docstring and lint issue

* Revert "fix docstring and lint issue"

This reverts commit d3a645f075.

* Revert "Fix #18244 for ecobee by moving current_operation property to current_operation_mode which is more accurate and defining current_operation properly, thanks @ZetaPhoenix"

This reverts commit bfd90551ef.
2019-03-24 18:13:06 -07:00
Moritz Fey
f272ed3b91 Add 'method' parameter to forgiving_round method (#21708)
* Add 'method' parameter to forgiving_round method

Fixes #21707

* fix rounding behavior in round() filter

* add test cases for new rounding behaviour
2019-03-24 18:10:49 -07:00
karlkar
548371e94c Check if mac is set when more than 2 gateways (#21834)
* Check if mac is set when more than 2 gateways

When more than 2 gateways mac is required for each of them. Now voluptuous will require it.

* fix line length

* remove trailing whitespace

* Make it more readable
2019-03-24 17:59:12 -07:00
Jason Hu
1aee7a1673 Add aws component and consolidate aws notify platform (#22240)
* Add aws component

* Move notify config under aws component

* Add basic tests for aws component

* Add deprecated warning for notify.aws_*

* Add more tests
2019-03-24 17:58:20 -07:00
Fredrik Erlandsson
b6987a1235 Add support for Tfiac Climate component (#21823)
## Description:

Add support for AC-models that follows the Tfiac protocol. Built together with @mellado.

**Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** home-assistant/home-assistant.io#8910

## Example entry for `configuration.yaml` (if applicable):
```yaml
climate:
   platform: tfiac
   host: 192.168.10.26
```

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.

If user exposed functionality or configuration variables are added/changed:
  - [x] 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:
  - [x] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]).
  - [x] New dependencies are only imported inside functions that use them ([example][ex-import]).
  - [x] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
  - [x] New files were added to `.coveragerc`.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23


Co-authored-by: Robbie Trencheny <me@robbiet.us>
2019-03-24 17:57:53 -07:00
Steven Looman
d1f75fcf32 Properly connect sensors to hub (#21414)
* Properly connect sensors to hub
Refs #20958

* Don't connect (merge) with main device

* Provide manufacturer

* Linting

* Do connect upnp-sensors to main device

* Linting

* Fix requirements_all.txt
2019-03-24 17:46:15 -07:00
dilruacs
adca598172 Turn Panasonic Viera TV on without WOL (#22084)
* Turn the TV on via remote

* Turn the TV on via remote

* Use turn_on() from panasonic-viera==0.3.2

* make power option configurable

* add app_power as argument

* formatting
2019-03-24 17:41:16 -07:00
Hmmbob
7f940423ad Warn user about HTML5 GCM deprecation (#22351)
* Warn user about GCM deprecation

* Fixing hound

* Fixing typo

* Fixing Travis fail
2019-03-24 17:40:43 -07:00
Steven Looman
1b0e523a60 Add support for 'image' media type (#22353) 2019-03-24 17:40:27 -07:00
shanbs
0d46e2c0b5 Fix the crash due to absence of the "default_home" in HomeData from pyatmo (netatmo/climate) (#22363) 2019-03-25 01:31:22 +01:00
cgtobi
d2a83c2732 Upgrade netatmo smart_home module (#22365) 2019-03-25 01:30:21 +01:00
Robbie Trencheny
dc64634e21 Set Onkyo reset log to debug instead of info (#22369)
Onkyo logs this message somewhat frequently, and its spammy, so lets make it a debug message instead of info. 

See also: #20081
2019-03-24 17:15:07 -07:00
Jason Hunter
0ae38aece8 Prefer TCP for RTSP streams (#22338)
## Description:

For RTSP streams, set the `prefer_tcp` FFMPEG flag.  This should resolve some of the "green feed" issues that some users are reporting, likely due to packets being lost over UDP on their network.

Resources: [FFMPEG protocols documentation](https://ffmpeg.org/ffmpeg-protocols.html#rtsp)

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-24 17:13:20 -07:00
ktnrg45
88df2e0ea5 Fix ps4 no creds with additional device (#22300)
* Fix no creds with additional device.

* Update config_flow.py
2019-03-24 20:08:59 -04:00
Sebastian Muszynski
7421156dfc Add support for the power socket of the Xiaomi AC Partner V3 (#22205) 2019-03-24 20:15:29 +01:00
Sebastian Muszynski
d5732c4dba Add color support to Philips Moonlight (#22204) 2019-03-24 20:14:35 +01:00
Anders Melchiorsen
eabb68ad7d Do not warn when creating an empty database (#22343) 2019-03-24 12:00:29 -07:00
Robert Svensson
8d1cf553de Support deCONZ library with exception handling (#21952) 2019-03-24 19:27:32 +01:00
Yu
89f8203163 Fix xiaomi aqara cube with lumi.acpartner.v3 gateway (#22130) 2019-03-24 18:56:17 +01:00
MatthewFlamm
ed93c3b2c1 Fix pressure in dark sky and openweathermap and add pressure utility (#21210) 2019-03-24 18:37:31 +01:00
Robert Svensson
6988fe783c Axis config flow (#18543)
* Initial draft

* Add tests for init
Fix hound comments

* Add tests for device
Change parameter handling to make device easier to test

* Remove superfluous functionality per Martins request

* Fix hound comments

* Embedded platforms

* Fix device import

* Config flow retry

* Options default values will be set automatically to options in config entry before component can be used

* Clean up init
Add populate options
Fix small issues in config flow
Add tests covering init

* Improve device tests

* Add config flow tests

* Fix hound comments

* Rebase miss

* Initial tests for binary sensors

* Clean up
More binary sensor tests

* Hound comments

* Add camera tests

* Fix initial state of sensors

* Bump dependency to v17

* Fix pylint and flake8

* Fix comments
2019-03-24 16:16:50 +01:00
zewelor
9214934d47 Move yeelight into component (#21593) 2019-03-24 13:01:12 +01:00
René-Marc Simard
71ebc4f594 Define GTFS sensor as a timestamp device class (#21053) 2019-03-24 12:15:30 +01:00
uchagani
c5f4aa0466 show which component is causing translation errors (#22340) 2019-03-23 23:06:55 -07:00
Jason Hunter
49b92b5349 fix where PLATFORM_SCHEMA gets pulled from (#22334) 2019-03-23 23:49:44 -04:00
Paulus Schoutsen
1ddc249989 Consolidate more platforms (#22308)
* Consolidate final platforms

* Fix some tests

* Fix more tests

* Fix more tests
2019-03-23 20:22:35 -07:00
Fabian Affolter
4c4eff1d62 Update file header (#22318)
* Update file header

* Fix indent

* Fix lint issue
2019-03-23 22:05:47 +01:00
Thibault Maekelbergh
16dbf9b2ea Remove occupancy as it is not available in API (#22320) 2019-03-23 20:05:08 +01:00
Paulus Schoutsen
c68b621972 Google Assistant: Add camera stream trait (#22278)
* Add camera stream trait

* Lint
2019-03-23 09:16:43 -07:00
SNoof85
d81df1f0ae Add Freebox switch platform (#21710)
* Added Freebox switch and bump aiofreepybox version

* Added missing modified files

* removed unused import

* gen_requirements_all passed

* removed unused import

* Remove unused code

* lint fixes

* More lint fixe

* Bump aiofreepybox version and API version to Freebox

* Remove URL from log entry

* import relative

* Sort imports
2019-03-23 15:32:53 +01:00
Markus Jankowski
112ed88d64 Add homematicip cloud connection quality related attributes (#21990) 2019-03-23 13:21:55 +01:00
Fabian Affolter
5f34d3ccb9 Update abbreviation (#22317) 2019-03-23 12:07:32 +01:00
Fabian Affolter
3c811bbf1a Upgrade py-cpuinfo to 5.0.0 (#22287) 2019-03-23 08:00:43 +01:00
Fabian Affolter
90dfe72d31 Upgrade pylast to 3.1.0 (#22302) 2019-03-23 08:00:13 +01:00
Robbie Trencheny
89221bfab9 Fix for embedded MQTT server configuration (#22305)
## Description:

Passing in a configuration for the embedded MQTT server has been broken for a while. This fixes that. See related issue number for further details.

**Related issue (if applicable):** fixes #18228

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-22 16:01:58 -07:00
Robbie Trencheny
773c567563 Switch from using Google Maps API for elevation to Open Elevation API (#22306)
## Description:

Switches elevation helper to use [Open Elevation](https://open-elevation.com/) instead of Google Maps API which now requires a API key. It's a drop in replacement for Google Maps too!

**Related issue (if applicable):** fixes #19860

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-22 16:01:43 -07:00
Robbie Trencheny
58c23bc2d9 Update srpenergy library (#22307)
Fixes #18899
2019-03-22 16:01:21 -07:00
cgtobi
611597a87b Sort code owners alphabetically (#22304)
## Description:
Sort the code oweners list alphabetically.

**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>

## Example entry for `configuration.yaml` (if applicable):
```yaml

```

## Checklist:
  - [ ] 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.

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:
  - [ ] New dependencies have been added to the `REQUIREMENTS` variable ([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`.

If the code does not interact with devices:
  - [ ] Tests have been added to verify that the new code works.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
2019-03-22 14:05:26 -07:00
Penny Wood
ecabf92504 Update trait to support auto without ranges. (#21847) 2019-03-22 13:42:56 -07:00
Robbie Trencheny
e9cd9f88be Fix Prometheus casting issues (#22282)
## Description:

Fix Prometheus casting issues

**Related issue (if applicable):** fixes #8659.
## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-22 13:16:17 -07:00
Leonardo Merza
a58f1eedda Add sort by config and tests for Reddit integration (#22081)
* add sort type to reddit sensor

add sort type to reddit sensor

automated commit 14/03/2019 15:53:15

automated commit 15/03/2019 09:43:39

reddit sensor add tests and sort by config

reddit sensor add tests and sort by config

reddit sensor add tests and sort by config

reddit sensor add tests and sort by config

* Add reddit sensor sort_by config and tests

* Add reddit sensor sort_by config and tests

* Add reddit sensor sort_by config and tests

* Add reddit sensor sort_by config and tests

* Add reddit sensor sort_by config and tests
2019-03-22 21:05:08 +01:00
jjlawren
ce550206a4 Fix progress for Plex media_players (#22224)
* Return current position and last updated timestamp needed by UI

* Add throttling to position updating

* Simplify logic, don't clear position when refreshing

* Use seconds

* Update homeassistant/components/plex/media_player.py

Co-Authored-By: jjlawren <jjlawren@users.noreply.github.com>

* Add throttling to position updating

* Simplify logic, don't clear position when refreshing
2019-03-22 14:00:12 -06:00
Penny Wood
1ddc65a0ce Fixing the api_streams sensor (#22200)
* Fire events with websocket messages.

* Added tests to validate

* Fixed api_streams sensor to use new sensor

* Delete from coverageac as now works.

* Removed websocket request event.

* Use dispatcher instead of events.

* Moved sensor to under websocket_api

* Changes as per code review

* Fixed tests.

* Modified test

* Patch
2019-03-22 11:59:10 -07:00
Anders Melchiorsen
2b6e197deb Consolidate the netgear_lte configuration (#22105)
* Consolidate the netgear_lte configuration

* Simplfications from review

* Extract sensor_types

* Simplify defaults
2019-03-22 14:43:39 +01:00
Jeff Irion
b125514655 Improved exception handling and logging (#22268)
Catch RuntimeError exceptions. Don't log ADB command output if there isn't any.
2019-03-22 08:47:06 -04:00
Jeff Irion
c90e13bfef Bump androidtv to 0.0.13 (#22279)
* Bump androidtv to 0.0.13

* Bump androidtv to 0.0.13 in requirements_all.txt
2019-03-22 09:25:31 +01:00
jjlawren
30d4a9f12c Plex: Avoid refreshing by both device and session methods (#22266)
* Avoid refreshing by both device and session methods

* Fix indentation
2019-03-21 19:41:41 -07:00
Fabian Affolter
3432c5da9e Upgrade sqlalchemy to 1.3.0 (#22269) 2019-03-21 19:40:11 -07:00
Pascal Vizeli
5716d0aa1a Update hass-nabucasa 0.10 (#22267) 2019-03-21 14:21:13 -07:00
Daniel Høyer Iversen
86a510441c Upgrade tibber libary, support solar production (#22261) 2019-03-21 16:46:25 -04:00
Ryan Bahm
bc85d47878 Change .now() to .utcnow() (#22233)
ephem works in UTC time, not local time. As a result, our comparison needs to be in UTC for accurate results.
2019-03-21 12:59:07 -07:00
Paulus Schoutsen
72bb94de96 Update translations 2019-03-21 12:57:20 -07:00
Paulus Schoutsen
0a4251e08f Updated frontend to 20190321.0 2019-03-21 12:56:59 -07:00
Pascal Vizeli
1b66520e31 Update Hass-NabuCasa 0.9 (#22258) 2019-03-21 19:39:24 +01:00
Penny Wood
81bb928394 Handle on/off through TemperatrureSetting trait. (#21842) 2019-03-21 10:57:42 -07:00
Karim Roukoz
fe468ace34 Bump total-connect-client to 0.25, fixing issue with Total Connect (#22230)
* Bump total-connect-client to 0.25

* Bump version in requirements_all.txt
2019-03-21 09:39:30 -07:00
Andrew Sayre
6526c68e2d Fix validate webhook requirements (#22248) 2019-03-21 09:13:20 -07:00
Michaël Arnauts
f64a99878f Allow on/off on tado climate component. (#22242)
* Allow on/off on tado climate component. Bump python-tado version. Patch from @wmalgadey

* Revert wrongly change in tado device tracker
2019-03-21 08:24:30 -07:00
Alexei Chetroi
03855c18fc add ZHA channel name property (#22218)
* Make channel name a property.

* Cleanup Zigbee channels.

Use zcl.Cluster.ep_attribute as default channel name.
2019-03-21 07:40:12 -07:00
Jason Hu
2b02c0d0fc Fix build issue (#22251) 2019-03-21 07:32:13 -07:00
Jason Hunter
07dc23a0e3 Stream fixes (#22238)
* fix issues with out of order packets, and empty first packet on some IP camera models

* do not skip the first packet
2019-03-21 07:31:55 -07:00
Steven Looman
77635d40e2 Upgrade to async_upnp_client==0.14.6 (#22223)
Upgrade to async_upnp_client to 0.14.6
2019-03-21 08:58:04 +01:00
Sebastian Muszynski
f4102339c1 Bump python-miio version (#22202)
* Bump python-miio version

* Rename speed property to motor_speed

* Enable set_led service of the Air Humidifier

* Allow a favorite level in [0...17]

* Allow a scene in [0...6]
2019-03-21 08:56:36 +01:00
uchagani
21871b3d6b add date_time_iso to time_date sensor (#22199)
* add date_time_iso to time_date sensor

* hound fixes

* lint fixes
2019-03-21 08:55:30 +01:00
Quentin Stafford-Fraser
88be786e82 Make !include_dir_list use alphanumeric order (#21902)
* Make YAML includes such as !include_dir_list incorporate files in alphabetical order

* Test for !include_dir_list sorting
2019-03-20 23:10:08 -07:00
Paulus Schoutsen
4b1de61110 Use relative imports inside integrations (#22235)
* Use relative imports inside integrations

* Lint

* Fix automation tests

* Fix scene imports
2019-03-20 22:56:46 -07:00
Marco Orovecchia
ab17b22239 Removed overly broad exception handling for nanoleaf light (#22189) 2019-03-20 20:32:06 -07:00
Fabian Affolter
423d595edf Upgrade holidays to 0.9.10 (#22182) 2019-03-20 20:31:15 -07:00
Fabian Affolter
e044eace20 Upgrade psutil to 5.6.1 (#22183)
* Upgrade psutil to 5.6.1

* Upgrade speedtest-cli to 2.1.1
2019-03-20 20:30:52 -07:00
Alexei Chetroi
9653544144 Fix ZHA force polled entities. (#22222)
## Description:
Fix "force_polled" ZHA entities.

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.

[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
2019-03-20 19:15:21 -07:00
Paulus Schoutsen
01d8b5831e Updated frontend to 20190320.0 2019-03-20 07:51:38 -07:00
Penny Wood
62c2bbd59a Fixed typing errors (#22207) 2019-03-20 07:49:27 -07:00
Matt Snyder
398281959a Update codeowners (#22198) 2019-03-20 11:33:42 +01:00
CV
db07e45df8 Fix breaking on HTML email without images (#22143)
* Fix breaking on HTML email without images

If using html emails with no images the code breaks since it is not tested for empty (uninitialized) key images.

* fixed long line

* Implemented suggested better solution

Better solution to allow data -> html email without images.

* Protecting data -> without html key from crashing

If the data key does not contain the html key, sending the email would crash this "script". Preventing this by returning an default empty array.
2019-03-19 14:37:12 -07:00
Jc2k
0344c761fc Better handling of HomeKit accessory-information service (#22171)
* HomeKit controller: Better handling of accessory-information service

* Changes from review
2019-03-19 15:04:20 -04:00
Fabian Affolter
6cb8806085 Upgrade Sphinx to 1.8.5 (#22180) 2019-03-19 15:02:56 -04:00
Fabian Affolter
2b250a7ec8 Upgrade youtube_dl to 2019.03.18 (#22181) 2019-03-19 15:01:58 -04:00
Paulus Schoutsen
08849fd3e8 Updated frontend to 20190319.0 2019-03-19 11:38:05 -07:00
Paulus Schoutsen
92dc26bab3 Always load Hass.io component on Hass.io (#22185)
* Always load Hass.io component on Hass.io

* Lint

* Lint
2019-03-19 11:33:50 -07:00
Eliseo Martelli
88669c6543 removed iliad (#22175) 2019-03-19 16:16:29 +01:00
Daniel Høyer Iversen
350904870e restore entity for switchbot (#22087) 2019-03-19 16:16:10 +01:00
Pascal Vizeli
1499485a71 Update Hass-NabuCasa 0.8 (#22177) 2019-03-19 15:10:30 +01:00
Penny Wood
bf4b7a82b4 Move platforms patch (#22168)
* move mold sensor

* Get tests working

* Move moon and season sensor strings.

* Renamed sensor strings.
2019-03-19 06:43:15 -07:00
Jc2k
c2aa06d0d4 Add some tests for Koogeek LS1 (#22141) 2019-03-19 00:58:56 -07:00
uchagani
188293770e bump total_connect_client to 0.24 (#22166) 2019-03-19 00:51:42 -07:00
Andrew Hall
12df14b87b Change ATTR_BATTERY_STATE_UNPLUGGED for ios component (#22152)
* AH - Updated Text Description of ATTR_BATTERY_STATE_UNPLUGGED

* AH - updated device_tracker ios test to use new battery state description
2019-03-19 00:46:04 -07:00
Penny Wood
f195ecca4b Consolidate all platforms that have tests (#22109)
* Moved climate components with tests into platform dirs.

* Updated tests from climate component.

* Moved binary_sensor components with tests into platform dirs.

* Updated tests from binary_sensor component.

* Moved calendar components with tests into platform dirs.

* Updated tests from calendar component.

* Moved camera components with tests into platform dirs.

* Updated tests from camera component.

* Moved cover components with tests into platform dirs.

* Updated tests from cover component.

* Moved device_tracker components with tests into platform dirs.

* Updated tests from device_tracker component.

* Moved fan components with tests into platform dirs.

* Updated tests from fan component.

* Moved geo_location components with tests into platform dirs.

* Updated tests from geo_location component.

* Moved image_processing components with tests into platform dirs.

* Updated tests from image_processing component.

* Moved light components with tests into platform dirs.

* Updated tests from light component.

* Moved lock components with tests into platform dirs.

* Moved media_player components with tests into platform dirs.

* Updated tests from media_player component.

* Moved scene components with tests into platform dirs.

* Moved sensor components with tests into platform dirs.

* Updated tests from sensor component.

* Moved switch components with tests into platform dirs.

* Updated tests from sensor component.

* Moved vacuum components with tests into platform dirs.

* Updated tests from vacuum component.

* Moved weather components with tests into platform dirs.

* Fixed __init__.py files

* Fixes for stuff moved as part of this branch.

* Fix stuff needed to merge with balloob's branch.

* Formatting issues.

* Missing __init__.py files.

* Fix-ups

* Fixup

* Regenerated requirements.

* Linting errors fixed.

* Fixed more broken tests.

* Missing init files.

* Fix broken tests.

* More broken tests

* There seems to be a thread race condition.
I suspect the logger stuff is running in another thread, which means waiting until the aio loop is done is missing the log messages.
Used sleep instead because that allows the logger thread to run. I think the api_streams sensor might not be thread safe.

* Disabled tests, will remove sensor in #22147

* Updated coverage and codeowners.
2019-03-18 23:07:39 -07:00
David F. Mulcahey
46ece3603f Add dynamic subscription for ZHA add device page (#22164)
* add ws subscription for zha gateway messages
* add debug mode
* only relay certain logs
* add missing require admin
* add devices command
* add area_id
* fix manufacturer code
2019-03-18 22:35:03 -04:00
Paulus Schoutsen
05db444832 Updated frontend to 20190318.0 2019-03-18 17:04:04 -07:00
Pascal Vizeli
ecfe0fc3dd Remove config check over supervisor (#22156)
* Remove config check over supervisor

* Fix lint

* Fix tests
2019-03-18 16:58:48 -07:00
Franck Nijhof
e5a2ef9b8d Upgrade toonapilib to 3.2.2 + lower interval (#22160) 2019-03-18 16:56:57 -07:00
zewelor
9591aa66ba Fixx yeelight flow action param for declared effects (#22159) 2019-03-18 20:51:42 +01:00
Ben Lebherz
af473cddf0 replace einder lib with horimote (#22135) 2019-03-18 20:14:14 +01:00
James Hilliard
9c7ef13f91 Fix hlk-sw16 inverted switch state (#22059) 2019-03-18 10:57:44 -07:00
endor
9f96aab2f4 Additional sensors and fixed icons, attributes and device classes. (#22139) 2019-03-18 18:55:09 +01:00
Jason Hunter
ce5cf5803c Fix resetting access token on streams with keepalive (#22148) 2019-03-18 09:27:34 -04:00
WebSpider
e14b243336 Bump tado version (#22145)
* Bump python-tado, new API endpoint

* Change references of old API endpoint to new

* Update REQUIREMENTS
2019-03-18 08:54:24 -04:00
Paulus Schoutsen
29131a655d Allow non-admins to listen to certain events (#22137) 2019-03-17 19:13:06 -07:00
Aaron Bach
c020b7c47d Handle possible exception during Ambient PWS reconnect (#22134)
* Handle possible exception during Ambient PWS reconnect

* Hound
2019-03-17 13:06:19 -06:00
Aaron Bach
8529ad3ba1 Loosen field retrieval from Pollen.com (#22132) 2019-03-17 11:55:58 -06:00
Aaron Bach
0d42ed1861 Handle occassional 502 Bad Gateway from SimpliSafe (#22131) 2019-03-17 11:55:10 -06:00
cgtobi
ba923d2d66 Add service description for services. (#21897)
* Add service description for services.

* Make service description more clear
2019-03-17 13:04:09 +01:00
Tyler Page
9b1491a98d Fix AttributeError traceback with darksky (#22101)
* Update darksky.py

* fixes
2019-03-17 12:06:39 +01:00
Jason Hu
1aab551eed Remove hass.config from aws_lambda notify payload (#22125) 2019-03-17 11:42:49 +01:00
Daniel Høyer Iversen
54dfc3e2b4 Tibber, Add price level (#22085)
* Add price level to Tibber sensor

* bump pyTibber version
2019-03-17 09:34:50 +01:00
Otto Winter
cf5ba7d922 Add ESPHome Camera (#22107)
* Add ESPHome Camera

* Bump aioesphomeapi to 1.7.0
2019-03-16 23:36:31 -07:00
Paulus Schoutsen
d16c507f34 Updated frontend to 20190316.0 2019-03-16 23:23:28 -07:00
Jason Hunter
54489a3514 delete previously removed service option from services yaml (#22123) 2019-03-16 23:16:05 -07:00
Paulus Schoutsen
f5076188ef Consolidate all platforms that have no tests (#22096)
* Consolidate

* Fix tests

* Update imports

* Fix import

* Use importlib because integration and package share name

* Fix more tests

* Update .coveragerc and CODEOWNERS
2019-03-16 20:44:05 -07:00
mvn23
d33cad0b24 Improve opentherm gw startup (#22121)
* Improve fix in c90f0d5 (#22106). Schedule connect coroutine directly on the loop rather than waiting for EVENT_HOMEASSISTANT_START.

* Remove unused import.
2019-03-16 23:51:50 +01:00
mvn23
4423572682 Fix TypeError in current_temperature if no temperature is known. (#22112)
Don't set opentherm_gw climate temperatures to 0 on init.
2019-03-16 16:34:31 +01:00
mvn23
c90f0d5bd6 Fix opentherm_gw blocks HA startup when gateway unreachable. (#22106) 2019-03-16 16:32:51 +01:00
Andre Lengwenus
0466e43478 Restricted temperature units for Celsius and Fahrenheit to the standardized units (#22108) 2019-03-16 16:31:58 +01:00
Aaron Bach
7807b40925 Add available property to Ambient PWS (#22092)
* Add available property to Ambient PWS

* Linting

* remove blank line
2019-03-16 11:33:22 +01:00
Phil Bruckner
9e4bd88a06 Bump amcrest to 1.2.7 for correct RTSP port (#22099)
amcrest 1.2.7 now includes camera's configured RTSP port in generated URL. Necessary to make new stream component work correctly if camera does not use default RTSP port.
2019-03-16 08:20:49 +01:00
Ville Skyttä
b4f8d157d6 Upgrade pytest to 4.3.1 (#22088) 2019-03-16 08:13:45 +01:00
Paulus Schoutsen
ade86b9b8d Version bump to 0.91.0dev0 2019-03-15 23:25:48 -07:00
Paulus Schoutsen
179c2315be Updated frontend to 20190315.1 2019-03-15 23:24:37 -07:00
Jason Hunter
f396de623b Beta Fix: FFMPEG and Stream component (#22091)
* remove stream_source from ffmpeg and onvif and add to generic ip cam

* fix tests
2019-03-15 23:19:32 -07:00
Andre Lengwenus
d0365f5911 Add LCN sensor platform (#21440) 2019-03-15 22:10:56 -05:00
Paulus Schoutsen
dbdf5558e6 Prevent cloud remote UI when using 127.0.0.1 as trusted network (#22093)
* Prevent cloud remote UI when using trusted networks

* Limit to 127.0.0.1 trusted network

* Update error msg

* Disable ipv6 loopback
2019-03-15 19:26:10 -07:00
Nacho Barrientos
42265036ff Telegram_bot: Allow fetching data from unverified SSL endpoints (#22067) (#22069)
* Telegram_bot: Allow fetching data from unverified SSL endpoints (#22067)

This patch adds an extra option to the payload that describes the
resource to send to disable the SSL server verification when polling
data from URLs.

* Use the boolean interpretation of the variable directly

Co-Authored-By: nbarrientos <nacho@criptonita.com>
2019-03-16 09:18:10 +08:00
Jeff Irion
53b204347d Bump androidtv to 0.0.12 (#22072) 2019-03-15 12:25:09 -07:00
Paulus Schoutsen
dc656205c4 Fix func 2019-03-15 11:11:59 -07:00
Paulus Schoutsen
087748b5ff Updated frontend to 20190315.0 2019-03-15 10:43:32 -07:00
Pascal Vizeli
17ba33004c Binary Sensor for Remote UI & Fix timezone (#22076)
* Binary Sensor for Remote UI

* Fix lint

* Revert make hass public

* Add tests
2019-03-15 10:39:53 -07:00
Isabella Gross Alström
9520d38288 Update rest.py (#22077)
Added specific error logs for 5xx and 4xx responses, debug log for 2xx and other statuses.
2019-03-15 10:14:22 -07:00
Jason Hu
cf69f25354 Correct context (#22061) 2019-03-15 10:01:15 -07:00
Fabian Affolter
101225749b Upgrade ruamel.yaml to 0.15.89 (#22064) 2019-03-15 09:22:00 -07:00
Paulus Schoutsen
e581d9e249 Fix more test 2019-03-15 09:14:20 -07:00
Paulus Schoutsen
3ce50b0a6a Fix test 2019-03-15 07:47:13 -07:00
Paulus Schoutsen
941f9b29dc Return config entry ID after creation (#22060) 2019-03-15 07:41:34 -07:00
escoand
3b34594aa3 Add HTTP auth and SSL verification to REST notify (#22016)
* add HTTP auth and SSL verification

* use internal import

* fix long line

* avoid extra import
2019-03-15 08:43:54 +01:00
Robbie Trencheny
5a9e8b2d3e Mobile App: Expose Cloud Remote UI FQDN in registration response (#22055)
* Add a callback to get the cloud remote UI FQDN

* Expose Cloud Remote UI FQDN in the registration response

* Return a URL instead of FQDN
2019-03-14 19:46:59 -07:00
David F. Mulcahey
89c96279ce Cleanup remaining constants stuff in ZHA (#22050)
* clean up constants
* fix quirks until it can be upgradded
2019-03-14 21:00:49 -04:00
Robbie Trencheny
851378739f Fix cloud services.yaml 2019-03-14 17:48:38 -07:00
Alexei Chetroi
9575c20b7c Minor ZHA consts fixes (#22049)
* Use consts for zha.core.consts

* Fix ZHA battery reporting config.
2019-03-14 20:29:12 -04:00
Robbie Trencheny
dcaced1966 Mobile App: Sensors (#21854)
## Description:

**Related issue (if applicable):** fixes #21782

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-14 17:24:53 -07:00
Pascal Vizeli
6a80ffa8cc Fix Google Assistant User with Cloud (#22042)
* Fix Google Assistant User with Cloud

* Fix User Agent ID

* respell

* Fix object

* Fix tests

* fix lint

* Fix lint
2019-03-14 16:18:31 -07:00
Robbie Trencheny
3769f5893a Mobile App: Register devices into the registry (#21856)
* Register devices into the registry

* Switch to device ID instead of webhook ID

* Rearchitect mobile_app to support config entries

* Kill DATA_REGISTRATIONS by migrating registrations into config entries

* Fix tests

* Improve how we get the config_entry_id

* Remove single_instance_allowed

* Simplify setup_registration

* Move webhook registering functions into __init__.py since they are only ever used once

* Kill get_registration websocket command

* Support description_placeholders in async_abort

* Add link to mobile_app implementing apps in abort dialog

* Store config entry and device registry entry in hass.data instead of looking it up

* Add testing to ensure that the config entry is created at registration

* Fix busted async_abort test

* Remove unnecessary check for entry is None
2019-03-14 12:57:50 -07:00
Charles Garwood
62f12d242a Z-Wave usb_path in configuration.yaml overrides config entry usb_path (#22038)
* usb_path in configuration.yaml overrides config entry

* Minor text update

* Update __init__.py
2019-03-14 12:29:21 -07:00
emontnemery
b25e951dcc Update additional platforms to use new MQTT message callback (#22030)
* Move additional platforms to new MQTT callback

* Fix automation.mqtt
2019-03-14 10:58:32 -07:00
Phil Bruckner
8d2d71c16a Bump amcrest to 1.2.6 & use new exceptions (#22040)
* Bump amcrest to 1.2.6 & use new exceptions

* Fix lint failure

* Use AmcrestError instead of individual ones
2019-03-14 10:56:33 -07:00
Fredrik Erlandsson
4e84e8a15e Async support for Daikin (#21638)
* asyncio support for Daikin

* version bump pydaikin

* pass session to pydaikin.Appliance

* all entities should have update
2019-03-14 18:33:43 +01:00
cgtobi
018a5d5c1f Bring back the boiler status (#22021) 2019-03-14 10:18:25 -07:00
Fabian Affolter
bd930b6e96 Upgrade youtube_dl to 2019.03.09 (#22041) 2019-03-14 10:14:27 -07:00
ktnrg45
ef2e3f607a Ps4 remove throttling (#21961)
* Remove throttling

* Correct docstring
2019-03-14 17:49:57 +01:00
Jason Hu
e480f75d6d Fix lifx light async error (#22031) 2019-03-14 17:10:36 +01:00
David F. Mulcahey
300384410f Refactor ZHA gateway into modules and add admin protections to API (#22023)
* refactor

* cleanup

* fix tests

* admin all the things
2019-03-14 10:20:25 -04:00
Daniel Høyer Iversen
b022428cb6 change logging to debug for nmap (#22036) 2019-03-14 10:00:19 -04:00
mvn23
2b25c25ca8 Bump pyotgw to 0.4b2 (#21973) 2019-03-14 13:11:04 +01:00
Jason Hu
4ff8a46acf Upgrade prefetched tox env to py37 (#22029) 2019-03-14 13:09:32 +01:00
kbickar
abf2e763b1 Add sense guard clause (#22014) 2019-03-14 11:46:44 +01:00
Jeff Irion
6381242eca Bump androidtv to 0.0.11 (#22025) 2019-03-14 17:25:07 +08:00
Robbie Trencheny
e75b12b92a Add myself to CODEOWNERS 2019-03-14 00:34:52 -07:00
Robbie Trencheny
95da6d41f9 Mobile App: Discovery to default configuration.yaml, zeroconf to default_config (#22028)
* Move discovery into default configuration.yaml

* Add zeroconf to default_config
2019-03-13 22:05:56 -07:00
Robbie Trencheny
3fcfba0a1e Mobile App: Enable loading via discovery (surprise inside!) (#22027)
![](http://funpeep.com/wp-content/uploads/2014/04/Cute-White-Cat-Wallpaper.jpg)
2019-03-13 21:55:30 -07:00
Phil Hawthorne
2787671de5 Remove UTF8 decoding for Waze (#22020)
Removes the UFT8 decoding for the Waze sensor, which broke in 0.89

Fixes #21739
2019-03-13 19:08:23 -07:00
Robbie Trencheny
673c8907e3 Mobile App: Update Location schema updates & device ID generation (#21849)
* Update location schema

* Generate a random device ID at registration time for later use with device_tracker.see

* Remove host name from device_tracker.see payload

* Drop consider_home from the payload

* Remove stale consider_home in schema

* Remove source_type
2019-03-13 15:38:53 -07:00
Robbie Trencheny
5ef602bc2e Mobile App: Support rendering multiple templates at once (#21851)
* Support rendering multiple templates at once

* Only catch TemplateError and dont log the error
2019-03-13 15:33:37 -07:00
Robbie Trencheny
acc44aaf6c Mobile App: Require encryption for registrations that support it (#21852)
## Description:

**Related issue (if applicable):** fixes #21758

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.
2019-03-13 15:22:43 -07:00
4561 changed files with 177699 additions and 147471 deletions

272
.circleci/config.yml Normal file
View File

@@ -0,0 +1,272 @@
# Python CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-python/ for more details
#
version: 2.1
executors:
python:
parameters:
tag:
type: string
default: latest
docker:
- image: circleci/python:<< parameters.tag >>
- image: circleci/buildpack-deps:stretch
working_directory: ~/repo
commands:
docker-prereqs:
description: Set up docker prerequisite requirement
steps:
- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends
libudev-dev libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev
libswscale-dev libswresample-dev libavfilter-dev
install-requirements:
description: Set up venv and install requirements python packages with cache support
parameters:
python:
type: string
default: latest
all:
description: pip install -r requirements_all.txt
type: boolean
default: false
test:
description: pip install -r requirements_test.txt
type: boolean
default: false
test_all:
description: pip install -r requirements_test_all.txt
type: boolean
default: false
steps:
- restore_cache:
keys:
- v1-<< parameters.python >>-{{ checksum "homeassistant/package_constraints.txt" }}-<<# parameters.all >>{{ checksum "requirements_all.txt" }}<</ parameters.all>>-<<# parameters.test >>{{ checksum "requirements_test.txt" }}<</ parameters.test>>-<<# parameters.test_all >>{{ checksum "requirements_test_all.txt" }}<</ parameters.test_all>>
- run:
name: install dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install -q -U pip
pip install -q -U setuptools
<<# 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
- save_cache:
paths:
- ./venv
key: v1-<< parameters.python >>-{{ checksum "homeassistant/package_constraints.txt" }}-<<# parameters.all >>{{ checksum "requirements_all.txt" }}<</ parameters.all>>-<<# parameters.test >>{{ checksum "requirements_test.txt" }}<</ parameters.test>>-<<# parameters.test_all >>{{ checksum "requirements_test_all.txt" }}<</ parameters.test_all>>
install:
description: Install Home Assistant
steps:
- run:
name: install
command: |
. venv/bin/activate
pip install -q --progress-bar off -e .
jobs:
static-check:
executor:
name: python
tag: 3.5.5-stretch
steps:
- checkout
- docker-prereqs
- install-requirements:
python: 3.5.5-stretch
test: true
- run:
name: run static check
command: |
. venv/bin/activate
flake8
- run:
name: run static type check
command: |
. venv/bin/activate
TYPING_FILES=$(cat mypyrc)
mypy $TYPING_FILES
- install
- run:
name: validate manifests
command: |
. venv/bin/activate
python -m script.hassfest validate
- run:
name: run gen_requirements_all
command: |
. venv/bin/activate
python script/gen_requirements_all.py validate
pre-install-all-requirements:
executor:
name: python
tag: 3.5.5-stretch
steps:
- checkout
- docker-prereqs
- install-requirements:
python: 3.5.5-stretch
all: true
test: true
pylint:
executor:
name: python
tag: 3.5.5-stretch
parallelism: 2
steps:
- checkout
- docker-prereqs
- install-requirements:
python: 3.5.5-stretch
all: true
test: true
- install
- run:
name: run pylint
command: |
. venv/bin/activate
PYFILES=$(circleci tests glob "homeassistant/**/*.py" | circleci tests split)
pylint ${PYFILES}
no_output_timeout: 15m
pre-test:
parameters:
python:
type: string
executor:
name: python
tag: << parameters.python >>
steps:
- checkout
- docker-prereqs
- install-requirements:
python: << parameters.python >>
test_all: true
test:
parameters:
python:
type: string
executor:
name: python
tag: << parameters.python >>
parallelism: 2
steps:
- checkout
- docker-prereqs
- install-requirements:
python: << parameters.python >>
test_all: true
- install
- run:
name: run tests with code coverage
command: |
. venv/bin/activate
CC_SWITCH="--cov --cov-report="
TESTFILES=$(circleci tests glob "tests/**/test_*.py" | circleci tests split --split-by=timings)
pytest --timeout=9 --durations=10 --junitxml=test-reports/homeassistant/results.xml -qq -o junit_family=xunit2 -o junit_suite_name=homeassistant -o console_output_style=count -p no:sugar $CC_SWITCH -- ${TESTFILES}
script/check_dirty
codecov
- store_test_results:
path: test-reports
- store_artifacts:
path: htmlcov
destination: cov-reports
- store_artifacts:
path: test-reports
destination: test-reports
# This job use machine executor, e.g. classic CircleCI VM because we need both lokalise-cli and a Python runtime.
# Classic CircleCI included python 2.7.12 and python 3.5.2 managed by pyenv, the Python version may need change if
# CircleCI changed its VM in future.
upload-translations:
machine: true
steps:
- checkout
- run:
name: upload english translations
command: |
pyenv versions
pyenv global 3.5.2
docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21
script/translations_upload
workflows:
version: 2
build:
jobs:
- static-check
- pre-install-all-requirements:
requires:
- static-check
- pylint:
requires:
- pre-install-all-requirements
- pre-test:
name: pre-test 3.5.5
requires:
- static-check
python: 3.5.5-stretch
- pre-test:
name: pre-test 3.6
requires:
- static-check
python: 3.6-stretch
- pre-test:
name: pre-test 3.7
requires:
- static-check
python: 3.7-stretch
- test:
name: test 3.5.5
requires:
- pre-test 3.5.5
python: 3.5.5-stretch
- test:
name: test 3.6
requires:
- pre-test 3.6
python: 3.6-stretch
- test:
name: test 3.7
requires:
- pre-test 3.7
python: 3.7-stretch
# CircleCI does not allow failure yet
# - test:
# name: test 3.8
# python: 3.8-rc-stretch
- upload-translations:
requires:
- static-check
filters:
branches:
only: dev

15
.codecov.yml Normal file
View File

@@ -0,0 +1,15 @@
codecov:
branch: dev
coverage:
status:
project:
default:
target: 90
threshold: 0.09
notify:
# Notify codecov room in Discord. The webhook URL (encrypted below) ends in /slack which is why we configure a Slack notification.
slack:
default:
url: "secret:TgWDUM4Jw0w7wMJxuxNF/yhSOHglIo1fGwInJnRLEVPy2P2aLimkoK1mtKCowH5TFw+baUXVXT3eAqefbdvIuM8BjRR4aRji95C6CYyD0QHy4N8i7nn1SQkWDPpS8IthYTg07rUDF7s5guurkKv2RrgoCdnnqjAMSzHoExMOF7xUmblMdhBTWJgBpWEhASJy85w/xxjlsE1xoTkzeJu9Q67pTXtRcn+5kb5/vIzPSYg="
comment:
require_changes: yes

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,8 @@ 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:
- [ ] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]).
- [ ] [_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`.
@@ -31,5 +32,7 @@ If the code communicates with devices, web services, or third-party tools:
If the code does not interact with devices:
- [ ] Tests have been added to verify that the new code works.
[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
[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_

45
.github/main.workflow vendored
View File

@@ -1,41 +1,14 @@
workflow "Python 3.7 - tox" {
resolves = ["Python 3.7 - tests"]
on = "push"
workflow "Mention CODEOWNERS of integrations when integration label is added to an issue" {
on = "issues"
resolves = "codeowners-mention"
}
action "Python 3.7 - tests" {
uses = "home-assistant/actions/py37-tox@master"
args = "-e py37"
workflow "Mention CODEOWNERS of integrations when integration label is added to an PRs" {
on = "pull_request"
resolves = "codeowners-mention"
}
workflow "Python 3.6 - tox" {
resolves = ["Python 3.6 - tests"]
on = "push"
}
action "Python 3.6 - tests" {
uses = "home-assistant/actions/py36-tox@master"
args = "-e py36"
}
workflow "Python 3.5 - tox" {
resolves = ["Pyton 3.5 - typing"]
on = "push"
}
action "Python 3.5 - tests" {
uses = "home-assistant/actions/py35-tox@master"
args = "-e py35"
}
action "Python 3.5 - lints" {
uses = "home-assistant/actions/py35-tox@master"
needs = ["Python 3.5 - tests"]
args = "-e lint"
}
action "Pyton 3.5 - typing" {
uses = "home-assistant/actions/py35-tox@master"
args = "-e typing"
needs = ["Python 3.5 - lints"]
action "codeowners-mention" {
uses = "home-assistant/codeowners-mention@master"
secrets = ["GITHUB_TOKEN"]
}

1
.gitignore vendored
View File

@@ -55,6 +55,7 @@ pip-log.txt
.tox
nosetests.xml
htmlcov/
test-reports/
# Translations
*.mo

View File

@@ -1,55 +0,0 @@
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=cov
after_success: coveralls
- python: "3.6"
env: TOXENV=py36
- python: "3.7"
env: TOXENV=py37
- python: "3.8-dev"
env: TOXENV=py38
if: branch = dev AND type = push
allow_failures:
- python: "3.8-dev"
env: TOXENV=py38
cache:
directories:
- $HOME/.cache/pip
install: pip install -U tox coveralls
language: python
script: travis_wait 40 tox --develop
services:
- docker
before_deploy:
- docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21
deploy:
skip_cleanup: true
provider: script
script: script/travis_deploy
on:
branch: dev
condition: $TOXENV = lint

View File

@@ -1,3 +1,4 @@
# This file is generated by script/manifest/codeowners.py
# People marked here will be automatically requested for a review
# when the code that they own is touched.
# https://github.com/blog/2392-introducing-code-owners
@@ -7,259 +8,255 @@ setup.py @home-assistant/core
homeassistant/*.py @home-assistant/core
homeassistant/helpers/* @home-assistant/core
homeassistant/util/* @home-assistant/core
homeassistant/components/api/* @home-assistant/core
homeassistant/components/auth/* @home-assistant/core
homeassistant/components/automation/* @home-assistant/core
homeassistant/components/cloud/* @home-assistant/core
homeassistant/components/config/* @home-assistant/core
homeassistant/components/configurator/* @home-assistant/core
homeassistant/components/conversation/* @home-assistant/core
homeassistant/components/frontend/* @home-assistant/core
homeassistant/components/group/* @home-assistant/core
homeassistant/components/history/* @home-assistant/core
homeassistant/components/http/* @home-assistant/core
homeassistant/components/input_*.py @home-assistant/core
homeassistant/components/introduction/* @home-assistant/core
homeassistant/components/logger/* @home-assistant/core
homeassistant/components/lovelace/* @home-assistant/core
homeassistant/components/mqtt/* @home-assistant/core
homeassistant/components/panel_custom/* @home-assistant/core
homeassistant/components/panel_iframe/* @home-assistant/core
homeassistant/components/onboarding/* @home-assistant/core
homeassistant/components/persistent_notification/* @home-assistant/core
homeassistant/components/scene/__init__.py @home-assistant/core
homeassistant/components/scene/homeassistant.py @home-assistant/core
homeassistant/components/script/* @home-assistant/core
homeassistant/components/shell_command/* @home-assistant/core
homeassistant/components/sun/* @home-assistant/core
homeassistant/components/updater/* @home-assistant/core
homeassistant/components/weblink/* @home-assistant/core
homeassistant/components/websocket_api/* @home-assistant/core
homeassistant/components/zone/* @home-assistant/core
# Home Assistant Developer Teams
# Virtualization
Dockerfile @home-assistant/docker
virtualization/Docker/* @home-assistant/docker
homeassistant/components/zwave/* @home-assistant/z-wave
homeassistant/components/*/zwave.py @home-assistant/z-wave
# Other code
homeassistant/scripts/check_config.py @kellerza
homeassistant/components/hassio/* @home-assistant/hassio
# Individual platforms
homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell
homeassistant/components/binary_sensor/hikvision.py @mezz64
homeassistant/components/binary_sensor/threshold.py @fabaff
homeassistant/components/binary_sensor/uptimerobot.py @ludeeus
homeassistant/components/camera/push.py @dgomes
homeassistant/components/camera/yi.py @bachya
homeassistant/components/climate/coolmaster.py @OnFreund
homeassistant/components/climate/ephember.py @ttroy50
homeassistant/components/climate/eq3btsmart.py @rytilahti
homeassistant/components/climate/mill.py @danielhiversen
homeassistant/components/climate/sensibo.py @andrey-git
homeassistant/components/cover/brunt.py @eavanvalkenburg
homeassistant/components/cover/group.py @cdce8p
homeassistant/components/cover/template.py @PhracturedBlue
homeassistant/components/device_tracker/asuswrt.py @kennedyshead
homeassistant/components/device_tracker/automatic.py @armills
homeassistant/components/device_tracker/bt_smarthub.py @jxwolstenholme
homeassistant/components/device_tracker/huawei_router.py @abmantis
homeassistant/components/device_tracker/quantum_gateway.py @cisasteelersfan
homeassistant/components/device_tracker/tile.py @bachya
homeassistant/components/device_tracker/traccar.py @ludeeus
homeassistant/components/device_tracker/synology_srm.py @aerialls
homeassistant/components/device_tracker/xfinity.py @cisasteelersfan
homeassistant/components/light/lifx_legacy.py @amelchio
homeassistant/components/light/yeelight.py @rytilahti
homeassistant/components/light/yeelightsunflower.py @lindsaymarkward
homeassistant/components/lock/nello.py @pschmitt
homeassistant/components/lock/nuki.py @pschmitt
homeassistant/components/media_player/emby.py @mezz64
homeassistant/components/media_player/kodi.py @armills
homeassistant/components/media_player/liveboxplaytv.py @pschmitt
homeassistant/components/media_player/mediaroom.py @dgomes
homeassistant/components/media_player/monoprice.py @etsinko
homeassistant/components/media_player/mpd.py @fabaff
homeassistant/components/media_player/xiaomi_tv.py @fattdev
homeassistant/components/media_player/yamaha_musiccast.py @jalmeroth
homeassistant/components/notify/file.py @fabaff
homeassistant/components/notify/flock.py @fabaff
homeassistant/components/notify/mastodon.py @fabaff
homeassistant/components/notify/smtp.py @fabaff
homeassistant/components/notify/syslog.py @fabaff
homeassistant/components/notify/xmpp.py @fabaff
homeassistant/components/notify/yessssms.py @flowolf
homeassistant/components/scene/lifx_cloud.py @amelchio
homeassistant/components/sensor/airvisual.py @bachya
homeassistant/components/sensor/alpha_vantage.py @fabaff
homeassistant/components/sensor/bitcoin.py @fabaff
homeassistant/components/sensor/cpuspeed.py @fabaff
homeassistant/components/sensor/cups.py @fabaff
homeassistant/components/sensor/darksky.py @fabaff
homeassistant/components/sensor/discogs.py @thibmaek
homeassistant/components/sensor/file.py @fabaff
homeassistant/components/sensor/filter.py @dgomes
homeassistant/components/sensor/fixer.py @fabaff
homeassistant/components/sensor/flunearyou.py @bachya
homeassistant/components/sensor/gearbest.py @HerrHofrat
homeassistant/components/sensor/gitter.py @fabaff
homeassistant/components/sensor/glances.py @fabaff
homeassistant/components/sensor/gpsd.py @fabaff
homeassistant/components/sensor/integration.py @dgomes
homeassistant/components/sensor/irish_rail_transport.py @ttroy50
homeassistant/components/sensor/jewish_calendar.py @tsvi
homeassistant/components/sensor/launch_library.py @ludeeus
homeassistant/components/sensor/linux_battery.py @fabaff
homeassistant/components/sensor/miflora.py @danielhiversen @ChristianKuehnel
homeassistant/components/sensor/min_max.py @fabaff
homeassistant/components/sensor/moon.py @fabaff
homeassistant/components/sensor/netdata.py @fabaff
homeassistant/components/sensor/nmbs.py @thibmaek
homeassistant/components/sensor/nsw_fuel_station.py @nickw444
homeassistant/components/sensor/pi_hole.py @fabaff
homeassistant/components/sensor/pollen.py @bachya
homeassistant/components/sensor/pvoutput.py @fabaff
homeassistant/components/sensor/qnap.py @colinodell
homeassistant/components/sensor/ruter.py @ludeeus
homeassistant/components/sensor/scrape.py @fabaff
homeassistant/components/sensor/serial.py @fabaff
homeassistant/components/sensor/seventeentrack.py @bachya
homeassistant/components/sensor/shodan.py @fabaff
homeassistant/components/sensor/sma.py @kellerza
homeassistant/components/sensor/sql.py @dgomes
homeassistant/components/sensor/statistics.py @fabaff
homeassistant/components/sensor/swiss*.py @fabaff
homeassistant/components/sensor/sytadin.py @gautric
homeassistant/components/sensor/tautulli.py @ludeeus
homeassistant/components/sensor/time_date.py @fabaff
homeassistant/components/sensor/version.py @fabaff
homeassistant/components/sensor/waqi.py @andrey-git
homeassistant/components/sensor/worldclock.py @fabaff
homeassistant/components/switch/switchbot.py @danielhiversen
homeassistant/components/switch/switchmate.py @danielhiversen
homeassistant/components/vacuum/roomba.py @pschmitt
homeassistant/components/weather/__init__.py @fabaff
homeassistant/components/weather/darksky.py @fabaff
homeassistant/components/weather/demo.py @fabaff
homeassistant/components/weather/met.py @danielhiversen
homeassistant/components/weather/openweathermap.py @fabaff
# A
# Integrations
homeassistant/components/airvisual/* @bachya
homeassistant/components/alarm_control_panel/* @colinodell
homeassistant/components/alpha_vantage/* @fabaff
homeassistant/components/amazon_polly/* @robbiet480
homeassistant/components/ambient_station/* @bachya
homeassistant/components/api/* @home-assistant/core
homeassistant/components/arduino/* @fabaff
homeassistant/components/arest/* @fabaff
homeassistant/components/asuswrt/* @kennedyshead
homeassistant/components/auth/* @home-assistant/core
homeassistant/components/automatic/* @armills
homeassistant/components/automation/* @home-assistant/core
homeassistant/components/aws/* @awarecan @robbiet480
homeassistant/components/axis/* @kane610
homeassistant/components/*/arest.py @fabaff
# B
homeassistant/components/bitcoin/* @fabaff
homeassistant/components/blink/* @fronzbot
homeassistant/components/bmw_connected_drive/* @ChristianKuehnel
homeassistant/components/*/broadlink.py @danielhiversen
# C
homeassistant/components/braviatv/* @robbiet480
homeassistant/components/broadlink/* @danielhiversen
homeassistant/components/brunt/* @eavanvalkenburg
homeassistant/components/bt_smarthub/* @jxwolstenholme
homeassistant/components/cisco_ios/* @fbradyirl
homeassistant/components/cisco_mobility_express/* @fbradyirl
homeassistant/components/cisco_webex_teams/* @fbradyirl
homeassistant/components/ciscospark/* @fbradyirl
homeassistant/components/cloud/* @home-assistant/core
homeassistant/components/cloudflare/* @ludeeus
homeassistant/components/config/* @home-assistant/core
homeassistant/components/configurator/* @home-assistant/core
homeassistant/components/conversation/* @home-assistant/core
homeassistant/components/coolmaster/* @OnFreund
homeassistant/components/counter/* @fabaff
# D
homeassistant/components/cover/* @home-assistant/core
homeassistant/components/cpuspeed/* @fabaff
homeassistant/components/cups/* @fabaff
homeassistant/components/daikin/* @fredrike @rofrantz
homeassistant/components/darksky/* @fabaff
homeassistant/components/deconz/* @kane610
homeassistant/components/demo/* @home-assistant/core
homeassistant/components/digital_ocean/* @fabaff
homeassistant/components/discogs/* @thibmaek
homeassistant/components/doorbird/* @oblogic7
homeassistant/components/dweet/* @fabaff
# E
homeassistant/components/ecovacs/* @OverloadUT
homeassistant/components/edp_redy/* @abmantis
homeassistant/components/eight_sleep/* @mezz64
homeassistant/components/egardia/* @jeroenterheerdt
homeassistant/components/esphome/*.py @OttoWinter
# F
homeassistant/components/freebox/*.py @snoof85
# G
homeassistant/components/eight_sleep/* @mezz64
homeassistant/components/emby/* @mezz64
homeassistant/components/enigma2/* @fbradyirl
homeassistant/components/ephember/* @ttroy50
homeassistant/components/epsonworkforce/* @ThaStealth
homeassistant/components/eq3btsmart/* @rytilahti
homeassistant/components/esphome/* @OttoWinter
homeassistant/components/file/* @fabaff
homeassistant/components/filter/* @dgomes
homeassistant/components/fitbit/* @robbiet480
homeassistant/components/fixer/* @fabaff
homeassistant/components/flock/* @fabaff
homeassistant/components/flunearyou/* @bachya
homeassistant/components/foursquare/* @robbiet480
homeassistant/components/freebox/* @snoof85
homeassistant/components/frontend/* @home-assistant/core
homeassistant/components/gearbest/* @HerrHofrat
homeassistant/components/gitter/* @fabaff
homeassistant/components/glances/* @fabaff
homeassistant/components/gntp/* @robbiet480
homeassistant/components/google_translate/* @awarecan
homeassistant/components/google_travel_time/* @robbiet480
homeassistant/components/googlehome/* @ludeeus
# H
homeassistant/components/gpsd/* @fabaff
homeassistant/components/group/* @home-assistant/core
homeassistant/components/gtfs/* @robbiet480
homeassistant/components/harmony/* @ehendrix23
homeassistant/components/hassio/* @home-assistant/hass-io
homeassistant/components/heos/* @andrewsayre
homeassistant/components/hikvision/* @mezz64
homeassistant/components/hikvisioncam/* @fbradyirl
homeassistant/components/history/* @home-assistant/core
homeassistant/components/history_graph/* @andrey-git
homeassistant/components/hive/* @Rendili @KJonline
homeassistant/components/homeassistant/* @home-assistant/core
homeassistant/components/homekit/* @cdce8p
homeassistant/components/homematic/* @pvizeli @danielperna84
homeassistant/components/html5/* @robbiet480
homeassistant/components/http/* @home-assistant/core
homeassistant/components/huawei_lte/* @scop
# I
homeassistant/components/influx/* @fabaff
homeassistant/components/huawei_router/* @abmantis
homeassistant/components/hue/* @balloob
homeassistant/components/ign_sismologia/* @exxamalte
homeassistant/components/influxdb/* @fabaff
homeassistant/components/input_boolean/* @home-assistant/core
homeassistant/components/input_datetime/* @home-assistant/core
homeassistant/components/input_number/* @home-assistant/core
homeassistant/components/input_select/* @home-assistant/core
homeassistant/components/input_text/* @home-assistant/core
homeassistant/components/integration/* @dgomes
homeassistant/components/ios/* @robbiet480
homeassistant/components/ipma/* @dgomes
# K
homeassistant/components/irish_rail_transport/* @ttroy50
homeassistant/components/jewish_calendar/* @tsvi
homeassistant/components/knx/* @Julius2342
homeassistant/components/kodi/* @armills
homeassistant/components/konnected/* @heythisisnate
# L
homeassistant/components/lametric/* @robbiet480
homeassistant/components/launch_library/* @ludeeus
homeassistant/components/lifx/* @amelchio
homeassistant/components/lifx_cloud/* @amelchio
homeassistant/components/lifx_legacy/* @amelchio
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/luci/* @fbradyirl
homeassistant/components/luftdaten/* @fabaff
# M
homeassistant/components/mastodon/* @fabaff
homeassistant/components/matrix/* @tinloaf
homeassistant/components/mediaroom/* @dgomes
homeassistant/components/melissa/* @kennedyshead
homeassistant/components/*/melissa.py @kennedyshead
homeassistant/components/*/mystrom.py @fabaff
# N
homeassistant/components/met/* @danielhiversen
homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel
homeassistant/components/mill/* @danielhiversen
homeassistant/components/min_max/* @fabaff
homeassistant/components/mobile_app/* @robbiet480
homeassistant/components/monoprice/* @etsinko
homeassistant/components/moon/* @fabaff
homeassistant/components/mpd/* @fabaff
homeassistant/components/mqtt/* @home-assistant/core
homeassistant/components/mystrom/* @fabaff
homeassistant/components/nello/* @pschmitt
homeassistant/components/ness_alarm/* @nickw444
homeassistant/components/*/ness_alarm.py @nickw444
homeassistant/components/nest/* @awarecan
homeassistant/components/netdata/* @fabaff
homeassistant/components/nissan_leaf/* @filcole
homeassistant/components/nmbs/* @thibmaek
homeassistant/components/no_ip/* @fabaff
# O
homeassistant/components/notify/* @flowolf
homeassistant/components/nsw_fuel_station/* @nickw444
homeassistant/components/nuki/* @pschmitt
homeassistant/components/ohmconnect/* @robbiet480
homeassistant/components/onboarding/* @home-assistant/core
homeassistant/components/openuv/* @bachya
# P
homeassistant/components/openweathermap/* @fabaff
homeassistant/components/owlet/* @oblogic7
homeassistant/components/panel_custom/* @home-assistant/core
homeassistant/components/panel_iframe/* @home-assistant/core
homeassistant/components/persistent_notification/* @home-assistant/core
homeassistant/components/pi_hole/* @fabaff
homeassistant/components/plant/* @ChristianKuehnel
homeassistant/components/point/* @fredrike
# Q
homeassistant/components/pollen/* @bachya
homeassistant/components/push/* @dgomes
homeassistant/components/pvoutput/* @fabaff
homeassistant/components/qnap/* @colinodell
homeassistant/components/quantum_gateway/* @cisasteelersfan
homeassistant/components/qwikswitch/* @kellerza
# R
homeassistant/components/raincloud/* @vanstinator
homeassistant/components/rainmachine/* @bachya
homeassistant/components/random/* @fabaff
homeassistant/components/rfxtrx/* @danielhiversen
homeassistant/components/*/random.py @fabaff
# S
homeassistant/components/rmvtransport/* @cgtobi
homeassistant/components/roomba/* @pschmitt
homeassistant/components/ruter/* @ludeeus
homeassistant/components/scene/* @home-assistant/core
homeassistant/components/scrape/* @fabaff
homeassistant/components/script/* @home-assistant/core
homeassistant/components/sensibo/* @andrey-git
homeassistant/components/serial/* @fabaff
homeassistant/components/seventeentrack/* @bachya
homeassistant/components/shell_command/* @home-assistant/core
homeassistant/components/shiftr/* @fabaff
homeassistant/components/shodan/* @fabaff
homeassistant/components/simplisafe/* @bachya
homeassistant/components/sma/* @kellerza
homeassistant/components/smartthings/* @andrewsayre
homeassistant/components/smtp/* @fabaff
homeassistant/components/sonos/* @amelchio
homeassistant/components/spaceapi/* @fabaff
homeassistant/components/spider/* @peternijssen
# T
homeassistant/components/sql/* @dgomes
homeassistant/components/statistics/* @fabaff
homeassistant/components/stiebel_eltron/* @fucm
homeassistant/components/sun/* @home-assistant/core
homeassistant/components/supla/* @mwegrzynek
homeassistant/components/swiss_hydrological_data/* @fabaff
homeassistant/components/swiss_public_transport/* @fabaff
homeassistant/components/switchbot/* @danielhiversen
homeassistant/components/switchmate/* @danielhiversen
homeassistant/components/synology_srm/* @aerialls
homeassistant/components/syslog/* @fabaff
homeassistant/components/sytadin/* @gautric
homeassistant/components/tahoma/* @philklei
homeassistant/components/tellduslive/*.py @fredrike
homeassistant/components/tautulli/* @ludeeus
homeassistant/components/tellduslive/* @fredrike
homeassistant/components/template/* @PhracturedBlue
homeassistant/components/tesla/* @zabuldon
homeassistant/components/tfiac/* @fredrike @mellado
homeassistant/components/thethingsnetwork/* @fabaff
homeassistant/components/threshold/* @fabaff
homeassistant/components/tibber/* @danielhiversen
homeassistant/components/tplink/* @rytilahti
homeassistant/components/tradfri/* @ggravlingen
homeassistant/components/tile/* @bachya
homeassistant/components/time_date/* @fabaff
homeassistant/components/toon/* @frenck
# U
homeassistant/components/tplink/* @rytilahti
homeassistant/components/traccar/* @ludeeus
homeassistant/components/tradfri/* @ggravlingen
homeassistant/components/tts/* @robbiet480
homeassistant/components/twilio_call/* @robbiet480
homeassistant/components/twilio_sms/* @robbiet480
homeassistant/components/uber/* @robbiet480
homeassistant/components/unifi/* @kane610
homeassistant/components/upcloud/* @scop
homeassistant/components/updater/* @home-assistant/core
homeassistant/components/upnp/* @robbiet480
homeassistant/components/uptimerobot/* @ludeeus
homeassistant/components/utility_meter/* @dgomes
# V
homeassistant/components/velux/* @Julius2342
# W
homeassistant/components/version/* @fabaff
homeassistant/components/waqi/* @andrey-git
homeassistant/components/weather/* @fabaff
homeassistant/components/weblink/* @home-assistant/core
homeassistant/components/websocket_api/* @home-assistant/core
homeassistant/components/wemo/* @sqldiablo
# X
homeassistant/components/worldclock/* @fabaff
homeassistant/components/xfinity/* @cisasteelersfan
homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi
homeassistant/components/xiaomi_miio/* @rytilahti @syssi
# Z
homeassistant/components/xiaomi_tv/* @fattdev
homeassistant/components/xmpp/* @fabaff
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/zha/* @dmulcahey @adminiuga
homeassistant/components/zone/* @home-assistant/core
homeassistant/components/zoneminder/* @rohankapoorcom
homeassistant/components/zwave/* @home-assistant/z-wave
# Other code
homeassistant/scripts/check_config.py @kellerza
# Individual files
homeassistant/components/group/cover @cdce8p
homeassistant/components/demo/weather @fabaff

View File

@@ -27,7 +27,7 @@ COPY requirements_all.txt requirements_all.txt
# Uninstall enum34 because some dependencies install it but breaks Python 3.4+.
# See PR #8103 for more info.
RUN pip3 install --no-cache-dir -r requirements_all.txt && \
pip3 install --no-cache-dir mysqlclient psycopg2 uvloop==0.11.3 cchardet cython tensorflow
pip3 install --no-cache-dir mysqlclient psycopg2 uvloop==0.12.2 cchardet cython tensorflow
# Copy source
COPY . .

View File

@@ -1,4 +1,4 @@
Home Assistant |Build Status| |Coverage Status| |Chat Status|
Home Assistant |Build Status| |CI Status| |Coverage Status| |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,8 +27,10 @@ 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=master
.. |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

View File

@@ -18,8 +18,26 @@ from ..models import Credentials, UserMeta
IPAddress = Union[IPv4Address, IPv6Address]
IPNetwork = Union[IPv4Network, IPv6Network]
CONF_TRUSTED_NETWORKS = 'trusted_networks'
CONF_TRUSTED_USERS = 'trusted_users'
CONF_GROUP = 'group'
CONF_ALLOW_BYPASS_LOGIN = 'allow_bypass_login'
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend({
vol.Required('trusted_networks'): vol.All(cv.ensure_list, [ip_network])
vol.Required(CONF_TRUSTED_NETWORKS): vol.All(
cv.ensure_list, [ip_network]
),
vol.Optional(CONF_TRUSTED_USERS, default={}): vol.Schema(
# we only validate the format of user_id or group_id
{ip_network: vol.All(
cv.ensure_list,
[vol.Or(
cv.uuid4_hex,
vol.Schema({vol.Required(CONF_GROUP): cv.uuid4_hex}),
)],
)}
),
vol.Optional(CONF_ALLOW_BYPASS_LOGIN, default=False): cv.boolean,
}, extra=vol.PREVENT_EXTRA)
@@ -43,7 +61,12 @@ class TrustedNetworksAuthProvider(AuthProvider):
@property
def trusted_networks(self) -> List[IPNetwork]:
"""Return trusted networks."""
return cast(List[IPNetwork], self.config['trusted_networks'])
return cast(List[IPNetwork], self.config[CONF_TRUSTED_NETWORKS])
@property
def trusted_users(self) -> Dict[IPNetwork, Any]:
"""Return trusted users per network."""
return cast(Dict[IPNetwork, Any], self.config[CONF_TRUSTED_USERS])
@property
def support_mfa(self) -> bool:
@@ -53,13 +76,34 @@ class TrustedNetworksAuthProvider(AuthProvider):
async def async_login_flow(self, context: Optional[Dict]) -> LoginFlow:
"""Return a flow to login."""
assert context is not None
ip_addr = cast(IPAddress, context.get('ip_address'))
users = await self.store.async_get_users()
available_users = {user.id: user.name
for user in users
if not user.system_generated and user.is_active}
available_users = [user for user in users
if not user.system_generated and user.is_active]
for ip_net, user_or_group_list in self.trusted_users.items():
if ip_addr in ip_net:
user_list = [user_id for user_id in user_or_group_list
if isinstance(user_id, str)]
group_list = [group[CONF_GROUP] for group in user_or_group_list
if isinstance(group, dict)]
flattened_group_list = [group for sublist in group_list
for group in sublist]
available_users = [
user for user in available_users
if (user.id in user_list or
any([group.id in flattened_group_list
for group in user.groups]))
]
break
return TrustedNetworksLoginFlow(
self, cast(IPAddress, context.get('ip_address')), available_users)
self,
ip_addr,
{
user.id: user.name for user in available_users
},
self.config[CONF_ALLOW_BYPASS_LOGIN],
)
async def async_get_or_create_credentials(
self, flow_result: Dict[str, str]) -> Credentials:
@@ -109,11 +153,13 @@ class TrustedNetworksLoginFlow(LoginFlow):
def __init__(self, auth_provider: TrustedNetworksAuthProvider,
ip_addr: IPAddress,
available_users: Dict[str, Optional[str]]) -> None:
available_users: Dict[str, Optional[str]],
allow_bypass_login: bool) -> None:
"""Initialize the login flow."""
super().__init__(auth_provider)
self._available_users = available_users
self._ip_address = ip_addr
self._allow_bypass_login = allow_bypass_login
async def async_step_init(
self, user_input: Optional[Dict[str, str]] = None) \
@@ -131,6 +177,11 @@ class TrustedNetworksLoginFlow(LoginFlow):
if user_input is not None:
return await self.async_finish(user_input)
if self._allow_bypass_login and len(self._available_users) == 1:
return await self.async_finish({
'user': next(iter(self._available_users.keys()))
})
return self.async_show_form(
step_id='init',
data_schema=vol.Schema({'user': vol.In(self._available_users)}),

View File

@@ -1,4 +1,5 @@
"""Provide methods to bootstrap a Home Assistant instance."""
import asyncio
import logging
import logging.handlers
import os
@@ -9,10 +10,7 @@ from typing import Any, Optional, Dict, Set
import voluptuous as vol
from homeassistant import (
core, config as conf_util, config_entries, components as core_components,
loader)
from homeassistant.components import persistent_notification
from homeassistant import core, config as conf_util, config_entries, loader
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component
from homeassistant.util.logging import AsyncHandler
@@ -28,50 +26,16 @@ ERROR_LOG_FILENAME = 'home-assistant.log'
# hass.data key for logging information.
DATA_LOGGING = 'logging'
LOGGING_COMPONENT = {'logger', 'system_log'}
FIRST_INIT_COMPONENT = {
CORE_INTEGRATIONS = ('homeassistant', 'persistent_notification')
LOGGING_INTEGRATIONS = {'logger', 'system_log'}
STAGE_1_INTEGRATIONS = {
# To record data
'recorder',
'mqtt',
# To make sure we forward data to other instances
'mqtt_eventstream',
'introduction',
'frontend',
'history',
}
def from_config_dict(config: Dict[str, Any],
hass: Optional[core.HomeAssistant] = None,
config_dir: Optional[str] = None,
enable_log: bool = True,
verbose: bool = False,
skip_pip: bool = False,
log_rotate_days: Any = None,
log_file: Any = None,
log_no_color: bool = False) \
-> Optional[core.HomeAssistant]:
"""Try to configure Home Assistant from a configuration dictionary.
Dynamically loads required components and its dependencies.
"""
if hass is None:
hass = core.HomeAssistant()
if config_dir is not None:
config_dir = os.path.abspath(config_dir)
hass.config.config_dir = config_dir
if not is_virtual_env():
hass.loop.run_until_complete(
async_mount_local_lib_path(config_dir))
# run task
hass = hass.loop.run_until_complete(
async_from_config_dict(
config, hass, config_dir, enable_log, verbose, skip_pip,
log_rotate_days, log_file, log_no_color)
)
return hass
async def async_from_config_dict(config: Dict[str, Any],
hass: core.HomeAssistant,
config_dir: Optional[str] = None,
@@ -114,64 +78,17 @@ async def async_from_config_dict(config: Dict[str, Any],
"Further initialization aborted")
return None
await hass.async_add_executor_job(
conf_util.process_ha_config_upgrade, hass)
# Make a copy because we are mutating it.
config = OrderedDict(config)
# Merge packages
conf_util.merge_packages_config(
await conf_util.merge_packages_config(
hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))
hass.config_entries = config_entries.ConfigEntries(hass, config)
await hass.config_entries.async_initialize()
components = _get_components(hass, config)
# Resolve all dependencies of all components.
for component in list(components):
try:
components.update(loader.component_dependencies(hass, component))
except loader.LoaderError:
# Ignore it, or we'll break startup
# It will be properly handled during setup.
pass
# setup components
res = await core_components.async_setup(hass, config)
if not res:
_LOGGER.error("Home Assistant core failed to initialize. "
"Further initialization aborted")
return hass
await persistent_notification.async_setup(hass, config)
_LOGGER.info("Home Assistant core initialized")
# stage 0, load logging components
for component in components:
if component in LOGGING_COMPONENT:
hass.async_create_task(
async_setup_component(hass, component, config))
await hass.async_block_till_done()
# stage 1
for component in components:
if component in FIRST_INIT_COMPONENT:
hass.async_create_task(
async_setup_component(hass, component, config))
await hass.async_block_till_done()
# stage 2
for component in components:
if component in FIRST_INIT_COMPONENT or component in LOGGING_COMPONENT:
continue
hass.async_create_task(async_setup_component(hass, component, config))
await hass.async_block_till_done()
await _async_set_up_integrations(hass, config)
stop = time()
_LOGGER.info("Home Assistant initialized in %.2fs", stop-start)
@@ -224,32 +141,6 @@ async def async_from_config_dict(config: Dict[str, Any],
return hass
def from_config_file(config_path: str,
hass: Optional[core.HomeAssistant] = None,
verbose: bool = False,
skip_pip: bool = True,
log_rotate_days: Any = None,
log_file: Any = None,
log_no_color: bool = False)\
-> Optional[core.HomeAssistant]:
"""Read the configuration file and try to start all the functionality.
Will add functionality to 'hass' parameter if given,
instantiates a new Home Assistant object if 'hass' is not given.
"""
if hass is None:
hass = core.HomeAssistant()
# run task
hass = hass.loop.run_until_complete(
async_from_config_file(
config_path, hass, verbose, skip_pip,
log_rotate_days, log_file, log_no_color)
)
return hass
async def async_from_config_file(config_path: str,
hass: core.HomeAssistant,
verbose: bool = False,
@@ -273,6 +164,9 @@ async def async_from_config_file(config_path: str,
async_enable_logging(hass, verbose, log_rotate_days, log_file,
log_no_color)
await hass.async_add_executor_job(
conf_util.process_ha_config_upgrade, hass)
try:
config_dict = await hass.async_add_executor_job(
conf_util.load_yaml_config_file, config_path)
@@ -391,18 +285,127 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
@core.callback
def _get_components(hass: core.HomeAssistant,
config: Dict[str, Any]) -> Set[str]:
"""Get components to set up."""
def _get_domains(hass: core.HomeAssistant, config: Dict[str, Any]) -> Set[str]:
"""Get domains of components to set up."""
# Filter out the repeating and common config section [homeassistant]
components = set(key.split(' ')[0] for key in config.keys()
if key != core.DOMAIN)
domains = set(key.split(' ')[0] for key in config.keys()
if key != core.DOMAIN)
# Add config entry domains
components.update(hass.config_entries.async_domains()) # type: ignore
domains.update(hass.config_entries.async_domains()) # type: ignore
# Make sure the Hass.io component is loaded
if 'HASSIO' in os.environ:
components.add('hassio')
domains.add('hassio')
return components
return domains
async def _async_set_up_integrations(
hass: core.HomeAssistant, config: Dict[str, Any]) -> None:
"""Set up all the integrations."""
domains = _get_domains(hass, config)
# Resolve all dependencies of all components so we can find the logging
# and integrations that need faster initialization.
resolved_domains_task = asyncio.gather(*[
loader.async_component_dependencies(hass, domain)
for domain in domains
], return_exceptions=True)
# Set up core.
_LOGGER.debug("Setting up %s", CORE_INTEGRATIONS)
if not all(await asyncio.gather(*[
async_setup_component(hass, domain, config)
for domain in CORE_INTEGRATIONS
])):
_LOGGER.error("Home Assistant core failed to initialize. "
"Further initialization aborted")
return
_LOGGER.debug("Home Assistant core initialized")
# Finish resolving domains
for dep_domains in await resolved_domains_task:
# Result is either a set or an exception. We ignore exceptions
# It will be properly handled during setup of the domain.
if isinstance(dep_domains, set):
domains.update(dep_domains)
# setup components
logging_domains = domains & LOGGING_INTEGRATIONS
stage_1_domains = domains & STAGE_1_INTEGRATIONS
stage_2_domains = domains - logging_domains - stage_1_domains
if logging_domains:
_LOGGER.debug("Setting up %s", logging_domains)
await asyncio.gather(*[
async_setup_component(hass, domain, config)
for domain in logging_domains
])
# Kick off loading the registries. They don't need to be awaited.
asyncio.gather(
hass.helpers.device_registry.async_get_registry(),
hass.helpers.entity_registry.async_get_registry(),
hass.helpers.area_registry.async_get_registry())
if stage_1_domains:
await asyncio.gather(*[
async_setup_component(hass, domain, config)
for domain in stage_1_domains
])
# Load all integrations
after_dependencies = {} # type: Dict[str, Set[str]]
for int_or_exc in await asyncio.gather(*[
loader.async_get_integration(hass, domain)
for domain in stage_2_domains
], return_exceptions=True):
# Exceptions are handled in async_setup_component.
if (isinstance(int_or_exc, loader.Integration) and
int_or_exc.after_dependencies):
after_dependencies[int_or_exc.domain] = set(
int_or_exc.after_dependencies
)
last_load = None
while stage_2_domains:
domains_to_load = set()
for domain in stage_2_domains:
after_deps = after_dependencies.get(domain)
# Load if integration has no after_dependencies or they are
# all loaded
if (not after_deps or
not after_deps-hass.config.components):
domains_to_load.add(domain)
if not domains_to_load or domains_to_load == last_load:
break
_LOGGER.debug("Setting up %s", domains_to_load)
await asyncio.gather(*[
async_setup_component(hass, domain, config)
for domain in domains_to_load
])
last_load = domains_to_load
stage_2_domains -= domains_to_load
# These are stage 2 domains that never have their after_dependencies
# satisfied.
if stage_2_domains:
_LOGGER.debug("Final set up: %s", stage_2_domains)
await asyncio.gather(*[
async_setup_component(hass, domain, config)
for domain in stage_2_domains
])
# Wrap up startup
await hass.async_block_till_done()

View File

@@ -7,33 +7,12 @@ Component design guidelines:
format "<DOMAIN>.<OBJECT_ID>".
- Each component should publish services only under its own domain.
"""
import asyncio
import itertools as it
import logging
from typing import Awaitable
import voluptuous as vol
import homeassistant.core as ha
import homeassistant.config as conf_util
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.service import async_extract_entity_ids
from homeassistant.helpers import intent
from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART,
RESTART_EXIT_CODE)
from homeassistant.helpers import config_validation as cv
from homeassistant.core import split_entity_id
_LOGGER = logging.getLogger(__name__)
SERVICE_RELOAD_CORE_CONFIG = 'reload_core_config'
SERVICE_CHECK_CONFIG = 'check_config'
SERVICE_UPDATE_ENTITY = 'update_entity'
SCHEMA_UPDATE_ENTITY = vol.Schema({
ATTR_ENTITY_ID: cv.entity_ids
})
def is_on(hass, entity_id=None):
"""Load up the module to call the is_on method.
@@ -46,7 +25,7 @@ def is_on(hass, entity_id=None):
entity_ids = hass.states.entity_ids()
for ent_id in entity_ids:
domain = ha.split_entity_id(ent_id)[0]
domain = split_entity_id(ent_id)[0]
try:
component = getattr(hass.components, domain)
@@ -64,113 +43,3 @@ def is_on(hass, entity_id=None):
return True
return False
async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
"""Set up general services related to Home Assistant."""
async def async_handle_turn_service(service):
"""Handle calls to homeassistant.turn_on/off."""
entity_ids = await async_extract_entity_ids(hass, service)
# Generic turn on/off method requires entity id
if not entity_ids:
_LOGGER.error(
"homeassistant/%s cannot be called without entity_id",
service.service)
return
# Group entity_ids by domain. groupby requires sorted data.
by_domain = it.groupby(sorted(entity_ids),
lambda item: ha.split_entity_id(item)[0])
tasks = []
for domain, ent_ids in by_domain:
# We want to block for all calls and only return when all calls
# have been processed. If a service does not exist it causes a 10
# second delay while we're blocking waiting for a response.
# But services can be registered on other HA instances that are
# listening to the bus too. So as an in between solution, we'll
# block only if the service is defined in the current HA instance.
blocking = hass.services.has_service(domain, service.service)
# Create a new dict for this call
data = dict(service.data)
# ent_ids is a generator, convert it to a list.
data[ATTR_ENTITY_ID] = list(ent_ids)
tasks.append(hass.services.async_call(
domain, service.service, data, blocking))
await asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
ha.DOMAIN, SERVICE_TURN_OFF, async_handle_turn_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_TURN_ON, async_handle_turn_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_TOGGLE, async_handle_turn_service)
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
intent.INTENT_TURN_ON, ha.DOMAIN, SERVICE_TURN_ON, "Turned {} on"))
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
intent.INTENT_TURN_OFF, ha.DOMAIN, SERVICE_TURN_OFF,
"Turned {} off"))
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
intent.INTENT_TOGGLE, ha.DOMAIN, SERVICE_TOGGLE, "Toggled {}"))
async def async_handle_core_service(call):
"""Service handler for handling core services."""
if call.service == SERVICE_HOMEASSISTANT_STOP:
hass.async_create_task(hass.async_stop())
return
try:
errors = await conf_util.async_check_ha_config_file(hass)
except HomeAssistantError:
return
if errors:
_LOGGER.error(errors)
hass.components.persistent_notification.async_create(
"Config error. See dev-info panel for details.",
"Config validating", "{0}.check_config".format(ha.DOMAIN))
return
if call.service == SERVICE_HOMEASSISTANT_RESTART:
hass.async_create_task(hass.async_stop(RESTART_EXIT_CODE))
async def async_handle_update_service(call):
"""Service handler for updating an entity."""
tasks = [hass.helpers.entity_component.async_update_entity(entity)
for entity in call.data[ATTR_ENTITY_ID]]
if tasks:
await asyncio.wait(tasks)
hass.services.async_register(
ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP, async_handle_core_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART, async_handle_core_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_CHECK_CONFIG, async_handle_core_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_UPDATE_ENTITY, async_handle_update_service,
schema=SCHEMA_UPDATE_ENTITY)
async def async_handle_reload_config(call):
"""Service handler for reloading core config."""
try:
conf = await conf_util.async_hass_config_yaml(hass)
except HomeAssistantError as err:
_LOGGER.error(err)
return
# auth only processed during startup
await conf_util.async_process_ha_core_config(
hass, conf.get(ha.DOMAIN) or {})
hass.services.async_register(
ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, async_handle_reload_config)
return True

View File

@@ -13,8 +13,6 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import discovery
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['abodepy==0.15.0']
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Data provided by goabode.com"

View File

@@ -2,13 +2,11 @@
import logging
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.abode import ATTRIBUTION, AbodeDevice
from homeassistant.components.abode import DOMAIN as ABODE_DOMAIN
from homeassistant.const import (
ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED)
DEPENDENCIES = ['abode']
from . import ATTRIBUTION, DOMAIN as ABODE_DOMAIN, AbodeDevice
_LOGGER = logging.getLogger(__name__)

View File

@@ -1,13 +1,11 @@
"""Support for Abode Security System binary sensors."""
import logging
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
DOMAIN as ABODE_DOMAIN)
from homeassistant.components.binary_sensor import BinarySensorDevice
_LOGGER = logging.getLogger(__name__)
from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None):

View File

@@ -1,14 +1,13 @@
"""Support for Abode Security System cameras."""
from datetime import timedelta
import logging
from datetime import timedelta
import requests
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
from homeassistant.components.camera import Camera
from homeassistant.util import Throttle
DEPENDENCIES = ['abode']
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)

View File

@@ -1,10 +1,9 @@
"""Support for Abode Security System covers."""
import logging
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
from homeassistant.components.cover import CoverDevice
DEPENDENCIES = ['abode']
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
_LOGGER = logging.getLogger(__name__)

View File

@@ -1,15 +1,14 @@
"""Support for Abode Security System lights."""
import logging
from math import ceil
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_HS_COLOR, ATTR_COLOR_TEMP,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, Light)
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, SUPPORT_BRIGHTNESS,
SUPPORT_COLOR, SUPPORT_COLOR_TEMP, Light)
from homeassistant.util.color import (
color_temperature_kelvin_to_mired, color_temperature_mired_to_kelvin)
DEPENDENCIES = ['abode']
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
_LOGGER = logging.getLogger(__name__)

View File

@@ -1,10 +1,9 @@
"""Support for Abode Security System locks."""
import logging
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
from homeassistant.components.lock import LockDevice
DEPENDENCIES = ['abode']
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
_LOGGER = logging.getLogger(__name__)

View File

@@ -0,0 +1,10 @@
{
"domain": "abode",
"name": "Abode",
"documentation": "https://www.home-assistant.io/components/abode",
"requirements": [
"abodepy==0.15.0"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -1,13 +1,12 @@
"""Support for Abode Security System sensors."""
import logging
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
from homeassistant.const import (
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE)
_LOGGER = logging.getLogger(__name__)
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__)
# Sensor types: Name, icon
SENSOR_TYPES = {

View File

@@ -1,13 +1,11 @@
"""Support for Abode Security System switches."""
import logging
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
DOMAIN as ABODE_DOMAIN)
from homeassistant.components.switch import SwitchDevice
_LOGGER = logging.getLogger(__name__)
from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None):

View File

@@ -0,0 +1 @@
"""The acer_projector component."""

View File

@@ -0,0 +1,10 @@
{
"domain": "acer_projector",
"name": "Acer projector",
"documentation": "https://www.home-assistant.io/components/acer_projector",
"requirements": [
"pyserial==3.1.1"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -0,0 +1,161 @@
"""Use serial protocol of Acer projector to obtain state of the projector."""
import logging
import re
import voluptuous as vol
from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
from homeassistant.const import (
STATE_ON, STATE_OFF, STATE_UNKNOWN, CONF_NAME, CONF_FILENAME)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
CONF_TIMEOUT = 'timeout'
CONF_WRITE_TIMEOUT = 'write_timeout'
DEFAULT_NAME = 'Acer Projector'
DEFAULT_TIMEOUT = 1
DEFAULT_WRITE_TIMEOUT = 1
ECO_MODE = 'ECO Mode'
ICON = 'mdi:projector'
INPUT_SOURCE = 'Input Source'
LAMP = 'Lamp'
LAMP_HOURS = 'Lamp Hours'
MODEL = 'Model'
# Commands known to the projector
CMD_DICT = {
LAMP: '* 0 Lamp ?\r',
LAMP_HOURS: '* 0 Lamp\r',
INPUT_SOURCE: '* 0 Src ?\r',
ECO_MODE: '* 0 IR 052\r',
MODEL: '* 0 IR 035\r',
STATE_ON: '* 0 IR 001\r',
STATE_OFF: '* 0 IR 002\r',
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_FILENAME): cv.isdevice,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
vol.Optional(CONF_WRITE_TIMEOUT, default=DEFAULT_WRITE_TIMEOUT):
cv.positive_int,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Connect with serial port and return Acer Projector."""
serial_port = config.get(CONF_FILENAME)
name = config.get(CONF_NAME)
timeout = config.get(CONF_TIMEOUT)
write_timeout = config.get(CONF_WRITE_TIMEOUT)
add_entities([AcerSwitch(serial_port, name, timeout, write_timeout)], True)
class AcerSwitch(SwitchDevice):
"""Represents an Acer Projector as a switch."""
def __init__(self, serial_port, name, timeout, write_timeout, **kwargs):
"""Init of the Acer projector."""
import serial
self.ser = serial.Serial(
port=serial_port, timeout=timeout, write_timeout=write_timeout,
**kwargs)
self._serial_port = serial_port
self._name = name
self._state = False
self._available = False
self._attributes = {
LAMP_HOURS: STATE_UNKNOWN,
INPUT_SOURCE: STATE_UNKNOWN,
ECO_MODE: STATE_UNKNOWN,
}
def _write_read(self, msg):
"""Write to the projector and read the return."""
import serial
ret = ""
# Sometimes the projector won't answer for no reason or the projector
# was disconnected during runtime.
# This way the projector can be reconnected and will still work
try:
if not self.ser.is_open:
self.ser.open()
msg = msg.encode('utf-8')
self.ser.write(msg)
# Size is an experience value there is no real limit.
# AFAIK there is no limit and no end character so we will usually
# need to wait for timeout
ret = self.ser.read_until(size=20).decode('utf-8')
except serial.SerialException:
_LOGGER.error('Problem communicating with %s', self._serial_port)
self.ser.close()
return ret
def _write_read_format(self, msg):
"""Write msg, obtain answer and format output."""
# answers are formatted as ***\answer\r***
awns = self._write_read(msg)
match = re.search(r'\r(.+)\r', awns)
if match:
return match.group(1)
return STATE_UNKNOWN
@property
def available(self):
"""Return if projector is available."""
return self._available
@property
def name(self):
"""Return name of the projector."""
return self._name
@property
def is_on(self):
"""Return if the projector is turned on."""
return self._state
@property
def state_attributes(self):
"""Return state attributes."""
return self._attributes
def update(self):
"""Get the latest state from the projector."""
msg = CMD_DICT[LAMP]
awns = self._write_read_format(msg)
if awns == 'Lamp 1':
self._state = True
self._available = True
elif awns == 'Lamp 0':
self._state = False
self._available = True
else:
self._available = False
for key in self._attributes:
msg = CMD_DICT.get(key, None)
if msg:
awns = self._write_read_format(msg)
self._attributes[key] = awns
def turn_on(self, **kwargs):
"""Turn the projector on."""
msg = CMD_DICT[STATE_ON]
self._write_read(msg)
self._state = STATE_ON
def turn_off(self, **kwargs):
"""Turn the projector off."""
msg = CMD_DICT[STATE_OFF]
self._write_read(msg)
self._state = STATE_OFF

View File

@@ -0,0 +1 @@
"""The actiontec component."""

View File

@@ -0,0 +1,115 @@
"""Support for Actiontec MI424WR (Verizon FIOS) routers."""
import logging
import re
import telnetlib
from collections import namedtuple
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
import homeassistant.util.dt as dt_util
from homeassistant.components.device_tracker import (
DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
_LOGGER = logging.getLogger(__name__)
_LEASES_REGEX = re.compile(
r'(?P<ip>([0-9]{1,3}[\.]){3}[0-9]{1,3})' +
r'\smac:\s(?P<mac>([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))' +
r'\svalid\sfor:\s(?P<timevalid>(-?\d+))' +
r'\ssec')
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string
})
def get_scanner(hass, config):
"""Validate the configuration and return an Actiontec scanner."""
scanner = ActiontecDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None
Device = namedtuple('Device', ['mac', 'ip', 'last_update'])
class ActiontecDeviceScanner(DeviceScanner):
"""This class queries an actiontec router for connected devices."""
def __init__(self, config):
"""Initialize the scanner."""
self.host = config[CONF_HOST]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]
self.last_results = []
data = self.get_actiontec_data()
self.success_init = data is not None
_LOGGER.info("canner initialized")
def scan_devices(self):
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client.mac for client in self.last_results]
def get_device_name(self, device):
"""Return the name of the given device or None if we don't know."""
if not self.last_results:
return None
for client in self.last_results:
if client.mac == device:
return client.ip
return None
def _update_info(self):
"""Ensure the information from the router is up to date.
Return boolean if scanning successful.
"""
_LOGGER.info("Scanning")
if not self.success_init:
return False
now = dt_util.now()
actiontec_data = self.get_actiontec_data()
if not actiontec_data:
return False
self.last_results = [Device(data['mac'], name, now)
for name, data in actiontec_data.items()
if data['timevalid'] > -60]
_LOGGER.info("Scan successful")
return True
def get_actiontec_data(self):
"""Retrieve data from Actiontec MI424WR and return parsed result."""
try:
telnet = telnetlib.Telnet(self.host)
telnet.read_until(b'Username: ')
telnet.write((self.username + '\n').encode('ascii'))
telnet.read_until(b'Password: ')
telnet.write((self.password + '\n').encode('ascii'))
prompt = telnet.read_until(
b'Wireless Broadband Router> ').split(b'\n')[-1]
telnet.write('firewall mac_cache_dump\n'.encode('ascii'))
telnet.write('\n'.encode('ascii'))
telnet.read_until(prompt)
leases_result = telnet.read_until(prompt).split(b'\n')[1:-1]
telnet.write('exit\n'.encode('ascii'))
except EOFError:
_LOGGER.exception("Unexpected response from router")
return
except ConnectionRefusedError:
_LOGGER.exception("Connection refused by router. Telnet enabled?")
return None
devices = {}
for lease in leases_result:
match = _LEASES_REGEX.search(lease.decode('utf-8'))
if match is not None:
devices[match.group('ip')] = {
'ip': match.group('ip'),
'mac': match.group('mac').upper(),
'timevalid': int(match.group('timevalid'))
}
return devices

View File

@@ -0,0 +1,8 @@
{
"domain": "actiontec",
"name": "Actiontec",
"documentation": "https://www.home-assistant.io/components/actiontec",
"requirements": [],
"dependencies": [],
"codeowners": []
}

View File

@@ -4,14 +4,15 @@ import struct
import logging
import ctypes
from collections import namedtuple
import asyncio
import async_timeout
import voluptuous as vol
from homeassistant.const import (
CONF_DEVICE, CONF_IP_ADDRESS, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyads==3.0.7']
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
@@ -31,6 +32,9 @@ CONF_ADS_VALUE = 'value'
CONF_ADS_VAR = 'adsvar'
CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness'
STATE_KEY_STATE = 'state'
STATE_KEY_BRIGHTNESS = 'brightness'
DOMAIN = 'ads'
SERVICE_WRITE_DATA_BY_NAME = 'write_data_by_name'
@@ -154,28 +158,41 @@ class AdsHub:
def write_by_name(self, name, value, plc_datatype):
"""Write a value to the device."""
import pyads
with self._lock:
return self._client.write_by_name(name, value, plc_datatype)
try:
return self._client.write_by_name(name, value, plc_datatype)
except pyads.ADSError as err:
_LOGGER.error("Error writing %s: %s", name, err)
def read_by_name(self, name, plc_datatype):
"""Read a value from the device."""
import pyads
with self._lock:
return self._client.read_by_name(name, plc_datatype)
try:
return self._client.read_by_name(name, plc_datatype)
except pyads.ADSError as err:
_LOGGER.error("Error reading %s: %s", name, err)
def add_device_notification(self, name, plc_datatype, callback):
"""Add a notification to the ADS devices."""
from pyads import NotificationAttrib
attr = NotificationAttrib(ctypes.sizeof(plc_datatype))
import pyads
attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype))
with self._lock:
hnotify, huser = self._client.add_device_notification(
name, attr, self._device_notification_callback)
hnotify = int(hnotify)
self._notification_items[hnotify] = NotificationItem(
hnotify, huser, name, plc_datatype, callback)
try:
hnotify, huser = self._client.add_device_notification(
name, attr, self._device_notification_callback)
except pyads.ADSError as err:
_LOGGER.error("Error subscribing to %s: %s", name, err)
else:
hnotify = int(hnotify)
self._notification_items[hnotify] = NotificationItem(
hnotify, huser, name, plc_datatype, callback)
_LOGGER.debug(
"Added device notification %d for variable %s", hnotify, name)
_LOGGER.debug(
"Added device notification %d for variable %s",
hnotify, name)
def _device_notification_callback(self, notification, name):
"""Handle device notifications."""
@@ -210,3 +227,68 @@ class AdsHub:
_LOGGER.warning("No callback available for this datatype")
notification_item.callback(notification_item.name, value)
class AdsEntity(Entity):
"""Representation of ADS entity."""
def __init__(self, ads_hub, name, ads_var):
"""Initialize ADS binary sensor."""
self._name = name
self._unique_id = ads_var
self._state_dict = {}
self._state_dict[STATE_KEY_STATE] = None
self._ads_hub = ads_hub
self._ads_var = ads_var
self._event = None
async def async_initialize_device(
self, ads_var, plctype, state_key=STATE_KEY_STATE, factor=None):
"""Register device notification."""
def update(name, value):
"""Handle device notifications."""
_LOGGER.debug('Variable %s changed its value to %d', name, value)
if factor is None:
self._state_dict[state_key] = value
else:
self._state_dict[state_key] = value / factor
asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop)
self.schedule_update_ha_state()
async def async_event_set():
"""Set event in async context."""
self._event.set()
self._event = asyncio.Event()
await self.hass.async_add_executor_job(
self._ads_hub.add_device_notification,
ads_var, plctype, update)
try:
with async_timeout.timeout(10):
await self._event.wait()
except asyncio.TimeoutError:
_LOGGER.debug('Variable %s: Timeout during first update',
ads_var)
@property
def name(self):
"""Return the default name of the binary sensor."""
return self._name
@property
def unique_id(self):
"""Return an unique identifier for this entity."""
return self._unique_id
@property
def should_poll(self):
"""Return False because entity pushes its state to HA."""
return False
@property
def available(self):
"""Return False if state has not been updated yet."""
return self._state_dict[STATE_KEY_STATE] is not None

View File

@@ -3,17 +3,16 @@ import logging
import voluptuous as vol
from homeassistant.components.ads import CONF_ADS_VAR, DATA_ADS
from homeassistant.components.binary_sensor import (
DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA, BinarySensorDevice)
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, DATA_ADS, AdsEntity, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'ADS binary sensor'
DEPENDENCIES = ['ads']
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
@@ -33,51 +32,25 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
add_entities([ads_sensor])
class AdsBinarySensor(BinarySensorDevice):
class AdsBinarySensor(AdsEntity, BinarySensorDevice):
"""Representation of ADS binary sensors."""
def __init__(self, ads_hub, name, ads_var, device_class):
"""Initialize ADS binary sensor."""
self._name = name
self._unique_id = ads_var
self._state = False
super().__init__(ads_hub, name, ads_var)
self._device_class = device_class or 'moving'
self._ads_hub = ads_hub
self.ads_var = ads_var
async def async_added_to_hass(self):
"""Register device notification."""
def update(name, value):
"""Handle device notifications."""
_LOGGER.debug('Variable %s changed its value to %d', name, value)
self._state = value
self.schedule_update_ha_state()
self.hass.async_add_job(
self._ads_hub.add_device_notification,
self.ads_var, self._ads_hub.PLCTYPE_BOOL, update)
await self.async_initialize_device(self._ads_var,
self._ads_hub.PLCTYPE_BOOL)
@property
def name(self):
"""Return the default name of the binary sensor."""
return self._name
@property
def unique_id(self):
"""Return an unique identifier for this entity."""
return self._unique_id
def is_on(self):
"""Return True if the entity is on."""
return self._state_dict[STATE_KEY_STATE]
@property
def device_class(self):
"""Return the device class."""
return self._device_class
@property
def is_on(self):
"""Return if the binary sensor is on."""
return self._state
@property
def should_poll(self):
"""Return False because entity pushes its state to HA."""
return False

View File

@@ -1,17 +1,18 @@
"""Support for ADS light sources."""
import logging
import voluptuous as vol
from homeassistant.components.light import Light, ATTR_BRIGHTNESS, \
SUPPORT_BRIGHTNESS, PLATFORM_SCHEMA
from homeassistant.components.light import (
ATTR_BRIGHTNESS, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, Light)
from homeassistant.const import CONF_NAME
from homeassistant.components.ads import DATA_ADS, CONF_ADS_VAR, \
CONF_ADS_VAR_BRIGHTNESS
import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS, \
AdsEntity, STATE_KEY_BRIGHTNESS, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ads']
DEFAULT_NAME = 'ADS Light'
CONF_ADSVAR_BRIGHTNESS = 'adsvar_brightness'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_ADS_VAR_BRIGHTNESS): cv.string,
@@ -28,91 +29,57 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
name = config.get(CONF_NAME)
add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness,
name)], True)
name)])
class AdsLight(Light):
class AdsLight(AdsEntity, Light):
"""Representation of ADS light."""
def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name):
"""Initialize AdsLight entity."""
self._ads_hub = ads_hub
self._on_state = False
self._brightness = None
self._name = name
self._unique_id = ads_var_enable
self.ads_var_enable = ads_var_enable
self.ads_var_brightness = ads_var_brightness
super().__init__(ads_hub, name, ads_var_enable)
self._state_dict[STATE_KEY_BRIGHTNESS] = None
self._ads_var_brightness = ads_var_brightness
async def async_added_to_hass(self):
"""Register device notification."""
def update_on_state(name, value):
"""Handle device notifications for state."""
_LOGGER.debug('Variable %s changed its value to %d', name, value)
self._on_state = value
self.schedule_update_ha_state()
await self.async_initialize_device(self._ads_var,
self._ads_hub.PLCTYPE_BOOL)
def update_brightness(name, value):
"""Handle device notification for brightness."""
_LOGGER.debug('Variable %s changed its value to %d', name, value)
self._brightness = value
self.schedule_update_ha_state()
self.hass.async_add_executor_job(
self._ads_hub.add_device_notification,
self.ads_var_enable, self._ads_hub.PLCTYPE_BOOL, update_on_state
)
if self.ads_var_brightness is not None:
self.hass.async_add_executor_job(
self._ads_hub.add_device_notification,
self.ads_var_brightness, self._ads_hub.PLCTYPE_INT,
update_brightness
)
@property
def name(self):
"""Return the name of the device if any."""
return self._name
@property
def unique_id(self):
"""Return an unique identifier for this entity."""
return self._unique_id
if self._ads_var_brightness is not None:
await self.async_initialize_device(self._ads_var_brightness,
self._ads_hub.PLCTYPE_UINT,
STATE_KEY_BRIGHTNESS)
@property
def brightness(self):
"""Return the brightness of the light (0..255)."""
return self._brightness
@property
def is_on(self):
"""Return if light is on."""
return self._on_state
@property
def should_poll(self):
"""Return False because entity pushes its state to HA."""
return False
return self._state_dict[STATE_KEY_BRIGHTNESS]
@property
def supported_features(self):
"""Flag supported features."""
support = 0
if self.ads_var_brightness is not None:
if self._ads_var_brightness is not None:
support = SUPPORT_BRIGHTNESS
return support
@property
def is_on(self):
"""Return True if the entity is on."""
return self._state_dict[STATE_KEY_STATE]
def turn_on(self, **kwargs):
"""Turn the light on or set a specific dimmer value."""
brightness = kwargs.get(ATTR_BRIGHTNESS)
self._ads_hub.write_by_name(self.ads_var_enable, True,
self._ads_hub.write_by_name(self._ads_var, True,
self._ads_hub.PLCTYPE_BOOL)
if self.ads_var_brightness is not None and brightness is not None:
self._ads_hub.write_by_name(self.ads_var_brightness, brightness,
if self._ads_var_brightness is not None and brightness is not None:
self._ads_hub.write_by_name(self._ads_var_brightness, brightness,
self._ads_hub.PLCTYPE_UINT)
def turn_off(self, **kwargs):
"""Turn the light off."""
self._ads_hub.write_by_name(self.ads_var_enable, False,
self._ads_hub.write_by_name(self._ads_var, False,
self._ads_hub.PLCTYPE_BOOL)

View File

@@ -0,0 +1,10 @@
{
"domain": "ads",
"name": "Ads",
"documentation": "https://www.home-assistant.io/components/ads",
"requirements": [
"pyads==3.0.7"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -4,18 +4,16 @@ import logging
import voluptuous as vol
from homeassistant.components import ads
from homeassistant.components.ads import (
CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR)
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR, \
AdsEntity, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "ADS sensor"
DEPENDENCIES = ['ads']
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_ADS_FACTOR): cv.positive_int,
@@ -43,60 +41,31 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
add_entities([entity])
class AdsSensor(Entity):
class AdsSensor(AdsEntity):
"""Representation of an ADS sensor entity."""
def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement,
factor):
"""Initialize AdsSensor entity."""
self._ads_hub = ads_hub
self._name = name
self._unique_id = ads_var
self._value = None
super().__init__(ads_hub, name, ads_var)
self._unit_of_measurement = unit_of_measurement
self.ads_var = ads_var
self.ads_type = ads_type
self.factor = factor
self._ads_type = ads_type
self._factor = factor
async def async_added_to_hass(self):
"""Register device notification."""
def update(name, value):
"""Handle device notifications."""
_LOGGER.debug("Variable %s changed its value to %d", name, value)
# If factor is set use it otherwise not
if self.factor is None:
self._value = value
else:
self._value = value / self.factor
self.schedule_update_ha_state()
self.hass.async_add_job(
self._ads_hub.add_device_notification,
self.ads_var, self._ads_hub.ADS_TYPEMAP[self.ads_type], update
)
@property
def name(self):
"""Return the name of the entity."""
return self._name
@property
def unique_id(self):
"""Return an unique identifier for this entity."""
return self._unique_id
await self.async_initialize_device(
self._ads_var,
self._ads_hub.ADS_TYPEMAP[self._ads_type],
STATE_KEY_STATE,
self._factor)
@property
def state(self):
"""Return the state of the device."""
return self._value
return self._state_dict[STATE_KEY_STATE]
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit_of_measurement
@property
def should_poll(self):
"""Return False because entity pushes its state."""
return False

View File

@@ -3,16 +3,14 @@ import logging
import voluptuous as vol
from homeassistant.components.ads import CONF_ADS_VAR, DATA_ADS
from homeassistant.components.switch import PLATFORM_SCHEMA
from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity
from . import CONF_ADS_VAR, DATA_ADS, AdsEntity, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ads']
DEFAULT_NAME = 'ADS Switch'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@@ -28,58 +26,28 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
name = config.get(CONF_NAME)
ads_var = config.get(CONF_ADS_VAR)
add_entities([AdsSwitch(ads_hub, name, ads_var)], True)
add_entities([AdsSwitch(ads_hub, name, ads_var)])
class AdsSwitch(ToggleEntity):
class AdsSwitch(AdsEntity, SwitchDevice):
"""Representation of an ADS switch device."""
def __init__(self, ads_hub, name, ads_var):
"""Initialize the AdsSwitch entity."""
self._ads_hub = ads_hub
self._on_state = False
self._name = name
self._unique_id = ads_var
self.ads_var = ads_var
async def async_added_to_hass(self):
"""Register device notification."""
def update(name, value):
"""Handle device notification."""
_LOGGER.debug("Variable %s changed its value to %d", name, value)
self._on_state = value
self.schedule_update_ha_state()
self.hass.async_add_job(
self._ads_hub.add_device_notification,
self.ads_var, self._ads_hub.PLCTYPE_BOOL, update)
await self.async_initialize_device(self._ads_var,
self._ads_hub.PLCTYPE_BOOL)
@property
def is_on(self):
"""Return if the switch is turned on."""
return self._on_state
@property
def name(self):
"""Return the name of the entity."""
return self._name
@property
def unique_id(self):
"""Return an unique identifier for this entity."""
return self._unique_id
@property
def should_poll(self):
"""Return False because entity pushes its state to HA."""
return False
"""Return True if the entity is on."""
return self._state_dict[STATE_KEY_STATE]
def turn_on(self, **kwargs):
"""Turn the switch on."""
self._ads_hub.write_by_name(
self.ads_var, True, self._ads_hub.PLCTYPE_BOOL)
self._ads_var, True, self._ads_hub.PLCTYPE_BOOL)
def turn_off(self, **kwargs):
"""Turn the switch off."""
self._ads_hub.write_by_name(
self.ads_var, False, self._ads_hub.PLCTYPE_BOOL)
self._ads_var, False, self._ads_hub.PLCTYPE_BOOL)

View File

@@ -0,0 +1 @@
"""The aftership component."""

View File

@@ -0,0 +1,2 @@
"""Constants for the Aftership integration."""
DOMAIN = 'aftership'

View File

@@ -0,0 +1,10 @@
{
"domain": "aftership",
"name": "Aftership",
"documentation": "https://www.home-assistant.io/components/aftership",
"requirements": [
"pyaftership==0.1.2"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -0,0 +1,204 @@
"""Support for non-delivered packages recorded in AfterShip."""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = 'Information provided by AfterShip'
ATTR_TRACKINGS = 'trackings'
BASE = 'https://track.aftership.com/'
CONF_SLUG = 'slug'
CONF_TITLE = 'title'
CONF_TRACKING_NUMBER = 'tracking_number'
DEFAULT_NAME = 'aftership'
UPDATE_TOPIC = DOMAIN + '_update'
ICON = 'mdi:package-variant-closed'
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)
SERVICE_ADD_TRACKING = 'add_tracking'
SERVICE_REMOVE_TRACKING = 'remove_tracking'
ADD_TRACKING_SERVICE_SCHEMA = vol.Schema(
{
vol.Required(CONF_TRACKING_NUMBER): cv.string,
vol.Optional(CONF_TITLE): cv.string,
vol.Optional(CONF_SLUG): cv.string,
}
)
REMOVE_TRACKING_SERVICE_SCHEMA = vol.Schema(
{vol.Required(CONF_SLUG): cv.string,
vol.Required(CONF_TRACKING_NUMBER): cv.string}
)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the AfterShip sensor platform."""
from pyaftership.tracker import Tracking
apikey = config[CONF_API_KEY]
name = config[CONF_NAME]
session = async_get_clientsession(hass)
aftership = Tracking(hass.loop, session, apikey)
await aftership.get_trackings()
if not aftership.meta or aftership.meta['code'] != 200:
_LOGGER.error("No tracking data found. Check API key is correct: %s",
aftership.meta)
return
instance = AfterShipSensor(aftership, name)
async_add_entities([instance], True)
async def handle_add_tracking(call):
"""Call when a user adds a new Aftership tracking from HASS."""
title = call.data.get(CONF_TITLE)
slug = call.data.get(CONF_SLUG)
tracking_number = call.data[CONF_TRACKING_NUMBER]
await aftership.add_package_tracking(tracking_number, title, slug)
async_dispatcher_send(hass, UPDATE_TOPIC)
hass.services.async_register(
DOMAIN,
SERVICE_ADD_TRACKING,
handle_add_tracking,
schema=ADD_TRACKING_SERVICE_SCHEMA,
)
async def handle_remove_tracking(call):
"""Call when a user removes an Aftership tracking from HASS."""
slug = call.data[CONF_SLUG]
tracking_number = call.data[CONF_TRACKING_NUMBER]
await aftership.remove_package_tracking(slug, tracking_number)
async_dispatcher_send(hass, UPDATE_TOPIC)
hass.services.async_register(
DOMAIN,
SERVICE_REMOVE_TRACKING,
handle_remove_tracking,
schema=REMOVE_TRACKING_SERVICE_SCHEMA,
)
class AfterShipSensor(Entity):
"""Representation of a AfterShip sensor."""
def __init__(self, aftership, name):
"""Initialize the sensor."""
self._attributes = {}
self._name = name
self._state = None
self.aftership = aftership
@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 this entity, if any."""
return 'packages'
@property
def device_state_attributes(self):
"""Return attributes for the sensor."""
return self._attributes
@property
def icon(self):
"""Icon to use in the frontend."""
return ICON
async def async_added_to_hass(self):
"""Register callbacks."""
self.hass.helpers.dispatcher.async_dispatcher_connect(
UPDATE_TOPIC, self.force_update)
async def force_update(self):
"""Force update of data."""
await self.async_update(no_throttle=True)
await self.async_update_ha_state()
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self, **kwargs):
"""Get the latest data from the AfterShip API."""
await self.aftership.get_trackings()
if not self.aftership.meta:
_LOGGER.error("Unknown errors when querying")
return
if self.aftership.meta['code'] != 200:
_LOGGER.error(
"Errors when querying AfterShip. %s", str(self.aftership.meta))
return
status_to_ignore = {'delivered'}
status_counts = {}
trackings = []
not_delivered_count = 0
for track in self.aftership.trackings['trackings']:
status = track['tag'].lower()
name = (
track['tracking_number']
if track['title'] is None
else track['title']
)
status_counts[status] = status_counts.get(status, 0) + 1
trackings.append({
'name': name,
'tracking_number': track['tracking_number'],
'slug': track['slug'],
'link': '%s%s/%s' %
(BASE, track['slug'], track['tracking_number']),
'last_update': track['updated_at'],
'expected_delivery': track['expected_delivery'],
'status': track['tag'],
'last_checkpoint': track['checkpoints'][-1]
})
if status not in status_to_ignore:
not_delivered_count += 1
else:
_LOGGER.debug("Ignoring %s as it has status: %s", name, status)
self._attributes = {
ATTR_ATTRIBUTION: ATTRIBUTION,
**status_counts,
ATTR_TRACKINGS: trackings,
}
self._state = not_delivered_count

View File

@@ -0,0 +1,24 @@
# Describes the format for available aftership services
add_tracking:
description: Add new tracking to Aftership.
fields:
tracking_number:
description: Tracking number for the new tracking
example: '123456789'
title:
description: A custom title for the new tracking
example: 'Laptop'
slug:
description: Slug (carrier) of the new tracking
example: 'USPS'
remove_tracking:
description: Remove a tracking from Aftership.
fields:
tracking_number:
description: Tracking number of the tracking to remove
example: '123456789'
slug:
description: Slug (carrier) of the tracking to remove
example: 'USPS'

View File

@@ -1,9 +1,4 @@
"""
Component for handling Air Quality data for your location.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/air_quality/
"""
"""Component for handling Air Quality data for your location."""
from datetime import timedelta
import logging

View File

@@ -1,56 +0,0 @@
"""
Demo platform that offers fake air quality data.
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/demo/
"""
from homeassistant.components.air_quality import AirQualityEntity
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Air Quality."""
add_entities([
DemoAirQuality('Home', 14, 23, 100),
DemoAirQuality('Office', 4, 16, None)
])
class DemoAirQuality(AirQualityEntity):
"""Representation of Air Quality data."""
def __init__(self, name, pm_2_5, pm_10, n2o):
"""Initialize the Demo Air Quality."""
self._name = name
self._pm_2_5 = pm_2_5
self._pm_10 = pm_10
self._n2o = n2o
@property
def name(self):
"""Return the name of the sensor."""
return '{} {}'.format('Demo Air Quality', self._name)
@property
def should_poll(self):
"""No polling needed for Demo Air Quality."""
return False
@property
def particulate_matter_2_5(self):
"""Return the particulate matter 2.5 level."""
return self._pm_2_5
@property
def particulate_matter_10(self):
"""Return the particulate matter 10 level."""
return self._pm_10
@property
def nitrogen_oxide(self):
"""Return the nitrogen oxide (N2O) level."""
return self._n2o
@property
def attribution(self):
"""Return the attribution."""
return 'Powered by Home Assistant'

View File

@@ -0,0 +1,8 @@
{
"domain": "air_quality",
"name": "Air quality",
"documentation": "https://www.home-assistant.io/components/air_quality",
"requirements": [],
"dependencies": [],
"codeowners": []
}

View File

@@ -1,252 +0,0 @@
"""
Sensor for checking the air quality around Norway.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/air_quality.nilu/
"""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.air_quality import (
PLATFORM_SCHEMA, AirQualityEntity)
from homeassistant.const import (
CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_SHOW_ON_MAP)
import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle
REQUIREMENTS = ['niluclient==0.1.2']
_LOGGER = logging.getLogger(__name__)
ATTR_AREA = 'area'
ATTR_POLLUTION_INDEX = 'nilu_pollution_index'
ATTRIBUTION = "Data provided by luftkvalitet.info and nilu.no"
CONF_AREA = 'area'
CONF_STATION = 'stations'
DEFAULT_NAME = 'NILU'
SCAN_INTERVAL = timedelta(minutes=30)
CONF_ALLOWED_AREAS = [
'Bergen',
'Birkenes',
'Bodø',
'Brumunddal',
'Bærum',
'Drammen',
'Elverum',
'Fredrikstad',
'Gjøvik',
'Grenland',
'Halden',
'Hamar',
'Harstad',
'Hurdal',
'Karasjok',
'Kristiansand',
'Kårvatn',
'Lillehammer',
'Lillesand',
'Lillestrøm',
'Lørenskog',
'Mo i Rana',
'Moss',
'Narvik',
'Oslo',
'Prestebakke',
'Sandve',
'Sarpsborg',
'Stavanger',
'Sør-Varanger',
'Tromsø',
'Trondheim',
'Tustervatn',
'Zeppelinfjellet',
'Ålesund',
]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Inclusive(CONF_LATITUDE, 'coordinates',
'Latitude and longitude must exist together'): cv.latitude,
vol.Inclusive(CONF_LONGITUDE, 'coordinates',
'Latitude and longitude must exist together'): cv.longitude,
vol.Exclusive(CONF_AREA, 'station_collection',
'Can only configure one specific station or '
'stations in a specific area pr sensor. '
'Please only configure station or area.'
): vol.All(cv.string, vol.In(CONF_ALLOWED_AREAS)),
vol.Exclusive(CONF_STATION, 'station_collection',
'Can only configure one specific station or '
'stations in a specific area pr sensor. '
'Please only configure station or area.'
): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_SHOW_ON_MAP, default=False): cv.boolean,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the NILU air quality sensor."""
import niluclient as nilu
name = config.get(CONF_NAME)
area = config.get(CONF_AREA)
stations = config.get(CONF_STATION)
show_on_map = config.get(CONF_SHOW_ON_MAP)
sensors = []
if area:
stations = nilu.lookup_stations_in_area(area)
elif not area and not stations:
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
location_client = nilu.create_location_client(latitude, longitude)
stations = location_client.station_names
for station in stations:
client = NiluData(nilu.create_station_client(station))
client.update()
if client.data.sensors:
sensors.append(NiluSensor(client, name, show_on_map))
else:
_LOGGER.warning("%s didn't give any sensors results", station)
add_entities(sensors, True)
class NiluData:
"""Class for handling the data retrieval."""
def __init__(self, api):
"""Initialize the data object."""
self.api = api
@property
def data(self):
"""Get data cached in client."""
return self.api.data
@Throttle(SCAN_INTERVAL)
def update(self):
"""Get the latest data from nilu API."""
self.api.update()
class NiluSensor(AirQualityEntity):
"""Single nilu station air sensor."""
def __init__(self, api_data: NiluData, name: str, show_on_map: bool):
"""Initialize the sensor."""
self._api = api_data
self._name = "{} {}".format(name, api_data.data.name)
self._max_aqi = None
self._attrs = {}
if show_on_map:
self._attrs[CONF_LATITUDE] = api_data.data.latitude
self._attrs[CONF_LONGITUDE] = api_data.data.longitude
@property
def attribution(self) -> str:
"""Return the attribution."""
return ATTRIBUTION
@property
def device_state_attributes(self) -> dict:
"""Return other details about the sensor state."""
return self._attrs
@property
def name(self) -> str:
"""Return the name of the sensor."""
return self._name
@property
def air_quality_index(self) -> str:
"""Return the Air Quality Index (AQI)."""
return self._max_aqi
@property
def carbon_monoxide(self) -> str:
"""Return the CO (carbon monoxide) level."""
from niluclient import CO
return self.get_component_state(CO)
@property
def carbon_dioxide(self) -> str:
"""Return the CO2 (carbon dioxide) level."""
from niluclient import CO2
return self.get_component_state(CO2)
@property
def nitrogen_oxide(self) -> str:
"""Return the N2O (nitrogen oxide) level."""
from niluclient import NOX
return self.get_component_state(NOX)
@property
def nitrogen_monoxide(self) -> str:
"""Return the NO (nitrogen monoxide) level."""
from niluclient import NO
return self.get_component_state(NO)
@property
def nitrogen_dioxide(self) -> str:
"""Return the NO2 (nitrogen dioxide) level."""
from niluclient import NO2
return self.get_component_state(NO2)
@property
def ozone(self) -> str:
"""Return the O3 (ozone) level."""
from niluclient import OZONE
return self.get_component_state(OZONE)
@property
def particulate_matter_2_5(self) -> str:
"""Return the particulate matter 2.5 level."""
from niluclient import PM25
return self.get_component_state(PM25)
@property
def particulate_matter_10(self) -> str:
"""Return the particulate matter 10 level."""
from niluclient import PM10
return self.get_component_state(PM10)
@property
def particulate_matter_0_1(self) -> str:
"""Return the particulate matter 0.1 level."""
from niluclient import PM1
return self.get_component_state(PM1)
@property
def sulphur_dioxide(self) -> str:
"""Return the SO2 (sulphur dioxide) level."""
from niluclient import SO2
return self.get_component_state(SO2)
def get_component_state(self, component_name: str) -> str:
"""Return formatted value of specified component."""
if component_name in self._api.data.sensors:
sensor = self._api.data.sensors[component_name]
return sensor.value
return None
def update(self) -> None:
"""Update the sensor."""
import niluclient as nilu
self._api.update()
sensors = self._api.data.sensors.values()
if sensors:
max_index = max([s.pollution_index for s in sensors])
self._max_aqi = max_index
self._attrs[ATTR_POLLUTION_INDEX] = \
nilu.POLLUTION_INDEX[self._max_aqi]
self._attrs[ATTR_AREA] = self._api.data.area

View File

@@ -1,140 +0,0 @@
"""
Sensor for checking the air quality forecast around Norway.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/air_quality.norway_air/
"""
import logging
from datetime import timedelta
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.air_quality import (
PLATFORM_SCHEMA, AirQualityEntity)
from homeassistant.const import (CONF_LATITUDE, CONF_LONGITUDE,
CONF_NAME)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
REQUIREMENTS = ['pyMetno==0.4.6']
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Air quality from " \
"https://luftkvalitet.miljostatus.no/, " \
"delivered by the Norwegian Meteorological Institute."
# https://api.met.no/license_data.html
CONF_FORECAST = 'forecast'
DEFAULT_FORECAST = 0
DEFAULT_NAME = 'Air quality Norway'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_FORECAST, default=DEFAULT_FORECAST): vol.Coerce(int),
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
SCAN_INTERVAL = timedelta(minutes=5)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the air_quality norway sensor."""
forecast = config.get(CONF_FORECAST)
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
name = config.get(CONF_NAME)
if None in (latitude, longitude):
_LOGGER.error("Latitude or longitude not set in Home Assistant config")
return
coordinates = {
'lat': str(latitude),
'lon': str(longitude),
}
async_add_entities([AirSensor(name, coordinates,
forecast, async_get_clientsession(hass),
)],
True)
def round_state(func):
"""Round state."""
def _decorator(self):
res = func(self)
if isinstance(res, float):
return round(res, 2)
return res
return _decorator
class AirSensor(AirQualityEntity):
"""Representation of an Yr.no sensor."""
def __init__(self, name, coordinates, forecast, session):
"""Initialize the sensor."""
import metno
self._name = name
self._api = metno.AirQualityData(coordinates, forecast, session)
@property
def attribution(self) -> str:
"""Return the attribution."""
return ATTRIBUTION
@property
def device_state_attributes(self) -> dict:
"""Return other details about the sensor state."""
return {'level': self._api.data.get('level'),
'location': self._api.data.get('location'),
}
@property
def name(self) -> str:
"""Return the name of the sensor."""
return self._name
@property
@round_state
def air_quality_index(self):
"""Return the Air Quality Index (AQI)."""
return self._api.data.get('aqi')
@property
@round_state
def nitrogen_dioxide(self):
"""Return the NO2 (nitrogen dioxide) level."""
return self._api.data.get('no2_concentration')
@property
@round_state
def ozone(self):
"""Return the O3 (ozone) level."""
return self._api.data.get('o3_concentration')
@property
@round_state
def particulate_matter_2_5(self):
"""Return the particulate matter 2.5 level."""
return self._api.data.get('pm25_concentration')
@property
@round_state
def particulate_matter_10(self):
"""Return the particulate matter 10 level."""
return self._api.data.get('pm10_concentration')
@property
def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._api.units.get('pm25_concentration')
async def async_update(self) -> None:
"""Update the sensor."""
await self._api.update()

View File

@@ -1,100 +0,0 @@
"""Support for openSenseMap Air Quality data."""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.air_quality import (
PLATFORM_SCHEMA, AirQualityEntity)
from homeassistant.const import CONF_NAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle
REQUIREMENTS = ['opensensemap-api==0.1.5']
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = 'Data provided by openSenseMap'
CONF_STATION_ID = 'station_id'
SCAN_INTERVAL = timedelta(minutes=10)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_STATION_ID): cv.string,
vol.Optional(CONF_NAME): cv.string,
})
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the openSenseMap air quality platform."""
from opensensemap_api import OpenSenseMap
name = config.get(CONF_NAME)
station_id = config[CONF_STATION_ID]
session = async_get_clientsession(hass)
osm_api = OpenSenseMapData(OpenSenseMap(station_id, hass.loop, session))
await osm_api.async_update()
if 'name' not in osm_api.api.data:
_LOGGER.error("Station %s is not available", station_id)
return
station_name = osm_api.api.data['name'] if name is None else name
async_add_entities([OpenSenseMapQuality(station_name, osm_api)], True)
class OpenSenseMapQuality(AirQualityEntity):
"""Implementation of an openSenseMap air quality entity."""
def __init__(self, name, osm):
"""Initialize the air quality entity."""
self._name = name
self._osm = osm
@property
def name(self):
"""Return the name of the air quality entity."""
return self._name
@property
def particulate_matter_2_5(self):
"""Return the particulate matter 2.5 level."""
return self._osm.api.pm2_5
@property
def particulate_matter_10(self):
"""Return the particulate matter 10 level."""
return self._osm.api.pm10
@property
def attribution(self):
"""Return the attribution."""
return ATTRIBUTION
async def async_update(self):
"""Get the latest data from the openSenseMap API."""
await self._osm.async_update()
class OpenSenseMapData:
"""Get the latest data and update the states."""
def __init__(self, api):
"""Initialize the data object."""
self.api = api
@Throttle(SCAN_INTERVAL)
async def async_update(self):
"""Get the latest data from the Pi-hole."""
from opensensemap_api.exceptions import OpenSenseMapError
try:
await self.api.get_data()
except OpenSenseMapError as err:
_LOGGER.error("Unable to fetch data: %s", err)

View File

@@ -0,0 +1 @@
"""The airvisual component."""

View File

@@ -0,0 +1,12 @@
{
"domain": "airvisual",
"name": "Airvisual",
"documentation": "https://www.home-assistant.io/components/airvisual",
"requirements": [
"pyairvisual==3.0.1"
],
"dependencies": [],
"codeowners": [
"@bachya"
]
}

View File

@@ -0,0 +1,294 @@
"""Support for AirVisual air quality sensors."""
from logging import getLogger
from datetime import timedelta
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_API_KEY,
CONF_LATITUDE, CONF_LONGITUDE, CONF_MONITORED_CONDITIONS,
CONF_SCAN_INTERVAL, CONF_STATE, CONF_SHOW_ON_MAP)
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
_LOGGER = getLogger(__name__)
ATTR_CITY = 'city'
ATTR_COUNTRY = 'country'
ATTR_POLLUTANT_SYMBOL = 'pollutant_symbol'
ATTR_POLLUTANT_UNIT = 'pollutant_unit'
ATTR_REGION = 'region'
CONF_CITY = 'city'
CONF_COUNTRY = 'country'
DEFAULT_ATTRIBUTION = "Data provided by AirVisual"
DEFAULT_SCAN_INTERVAL = timedelta(minutes=10)
MASS_PARTS_PER_MILLION = 'ppm'
MASS_PARTS_PER_BILLION = 'ppb'
VOLUME_MICROGRAMS_PER_CUBIC_METER = 'µg/m3'
SENSOR_TYPE_LEVEL = 'air_pollution_level'
SENSOR_TYPE_AQI = 'air_quality_index'
SENSOR_TYPE_POLLUTANT = 'main_pollutant'
SENSORS = [
(SENSOR_TYPE_LEVEL, 'Air Pollution Level', 'mdi:gauge', None),
(SENSOR_TYPE_AQI, 'Air Quality Index', 'mdi:chart-line', 'AQI'),
(SENSOR_TYPE_POLLUTANT, 'Main Pollutant', 'mdi:chemical-weapon', None),
]
POLLUTANT_LEVEL_MAPPING = [{
'label': 'Good',
'icon': 'mdi:emoticon-excited',
'minimum': 0,
'maximum': 50
}, {
'label': 'Moderate',
'icon': 'mdi:emoticon-happy',
'minimum': 51,
'maximum': 100
}, {
'label': 'Unhealthy for sensitive groups',
'icon': 'mdi:emoticon-neutral',
'minimum': 101,
'maximum': 150
}, {
'label': 'Unhealthy',
'icon': 'mdi:emoticon-sad',
'minimum': 151,
'maximum': 200
}, {
'label': 'Very Unhealthy',
'icon': 'mdi:emoticon-dead',
'minimum': 201,
'maximum': 300
}, {
'label': 'Hazardous',
'icon': 'mdi:biohazard',
'minimum': 301,
'maximum': 10000
}]
POLLUTANT_MAPPING = {
'co': {
'label': 'Carbon Monoxide',
'unit': MASS_PARTS_PER_MILLION
},
'n2': {
'label': 'Nitrogen Dioxide',
'unit': MASS_PARTS_PER_BILLION
},
'o3': {
'label': 'Ozone',
'unit': MASS_PARTS_PER_BILLION
},
'p1': {
'label': 'PM10',
'unit': VOLUME_MICROGRAMS_PER_CUBIC_METER
},
'p2': {
'label': 'PM2.5',
'unit': VOLUME_MICROGRAMS_PER_CUBIC_METER
},
's2': {
'label': 'Sulfur Dioxide',
'unit': MASS_PARTS_PER_BILLION
},
}
SENSOR_LOCALES = {'cn': 'Chinese', 'us': 'U.S.'}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_API_KEY): cv.string,
vol.Required(CONF_MONITORED_CONDITIONS, default=list(SENSOR_LOCALES)):
vol.All(cv.ensure_list, [vol.In(SENSOR_LOCALES)]),
vol.Inclusive(CONF_CITY, 'city'): cv.string,
vol.Inclusive(CONF_COUNTRY, 'city'): cv.string,
vol.Inclusive(CONF_LATITUDE, 'coords'): cv.latitude,
vol.Inclusive(CONF_LONGITUDE, 'coords'): cv.longitude,
vol.Optional(CONF_SHOW_ON_MAP, default=True): cv.boolean,
vol.Inclusive(CONF_STATE, 'city'): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL):
cv.time_period
})
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Configure the platform and add the sensors."""
from pyairvisual import Client
city = config.get(CONF_CITY)
state = config.get(CONF_STATE)
country = config.get(CONF_COUNTRY)
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
websession = aiohttp_client.async_get_clientsession(hass)
if city and state and country:
_LOGGER.debug(
"Using city, state, and country: %s, %s, %s", city, state, country)
location_id = ','.join((city, state, country))
data = AirVisualData(
Client(websession, api_key=config[CONF_API_KEY]),
city=city,
state=state,
country=country,
show_on_map=config[CONF_SHOW_ON_MAP],
scan_interval=config[CONF_SCAN_INTERVAL])
else:
_LOGGER.debug(
"Using latitude and longitude: %s, %s", latitude, longitude)
location_id = ','.join((str(latitude), str(longitude)))
data = AirVisualData(
Client(websession, api_key=config[CONF_API_KEY]),
latitude=latitude,
longitude=longitude,
show_on_map=config[CONF_SHOW_ON_MAP],
scan_interval=config[CONF_SCAN_INTERVAL])
await data.async_update()
sensors = []
for locale in config[CONF_MONITORED_CONDITIONS]:
for kind, name, icon, unit in SENSORS:
sensors.append(
AirVisualSensor(
data, kind, name, icon, unit, locale, location_id))
async_add_entities(sensors, True)
class AirVisualSensor(Entity):
"""Define an AirVisual sensor."""
def __init__(self, airvisual, kind, name, icon, unit, locale, location_id):
"""Initialize."""
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._icon = icon
self._locale = locale
self._location_id = location_id
self._name = name
self._state = None
self._type = kind
self._unit = unit
self.airvisual = airvisual
@property
def device_state_attributes(self):
"""Return the device state attributes."""
if self.airvisual.show_on_map:
self._attrs[ATTR_LATITUDE] = self.airvisual.latitude
self._attrs[ATTR_LONGITUDE] = self.airvisual.longitude
else:
self._attrs['lati'] = self.airvisual.latitude
self._attrs['long'] = self.airvisual.longitude
return self._attrs
@property
def available(self):
"""Return True if entity is available."""
return bool(self.airvisual.pollution_info)
@property
def icon(self):
"""Return the icon."""
return self._icon
@property
def name(self):
"""Return the name."""
return '{0} {1}'.format(SENSOR_LOCALES[self._locale], self._name)
@property
def state(self):
"""Return the state."""
return self._state
@property
def unique_id(self):
"""Return a unique, HASS-friendly identifier for this entity."""
return '{0}_{1}_{2}'.format(
self._location_id, self._locale, self._type)
@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit
async def async_update(self):
"""Update the sensor."""
await self.airvisual.async_update()
data = self.airvisual.pollution_info
if not data:
return
if self._type == SENSOR_TYPE_LEVEL:
aqi = data['aqi{0}'.format(self._locale)]
[level] = [
i for i in POLLUTANT_LEVEL_MAPPING
if i['minimum'] <= aqi <= i['maximum']
]
self._state = level['label']
self._icon = level['icon']
elif self._type == SENSOR_TYPE_AQI:
self._state = data['aqi{0}'.format(self._locale)]
elif self._type == SENSOR_TYPE_POLLUTANT:
symbol = data['main{0}'.format(self._locale)]
self._state = POLLUTANT_MAPPING[symbol]['label']
self._attrs.update({
ATTR_POLLUTANT_SYMBOL: symbol,
ATTR_POLLUTANT_UNIT: POLLUTANT_MAPPING[symbol]['unit']
})
class AirVisualData:
"""Define an object to hold sensor data."""
def __init__(self, client, **kwargs):
"""Initialize."""
self._client = client
self.city = kwargs.get(CONF_CITY)
self.country = kwargs.get(CONF_COUNTRY)
self.latitude = kwargs.get(CONF_LATITUDE)
self.longitude = kwargs.get(CONF_LONGITUDE)
self.pollution_info = {}
self.show_on_map = kwargs.get(CONF_SHOW_ON_MAP)
self.state = kwargs.get(CONF_STATE)
self.async_update = Throttle(
kwargs[CONF_SCAN_INTERVAL])(self._async_update)
async def _async_update(self):
"""Update AirVisual data."""
from pyairvisual.errors import AirVisualError
try:
if self.city and self.state and self.country:
resp = await self._client.api.city(
self.city, self.state, self.country)
self.longitude, self.latitude = resp['location']['coordinates']
else:
resp = await self._client.api.nearest_city(
self.latitude, self.longitude)
_LOGGER.debug("New data retrieved: %s", resp)
self.pollution_info = resp['current']['pollution']
except (KeyError, AirVisualError) as err:
if self.city and self.state and self.country:
location = (self.city, self.state, self.country)
else:
location = (self.latitude, self.longitude)
_LOGGER.error(
"Can't retrieve data for location: %s (%s)", location,
err)
self.pollution_info = {}

View File

@@ -0,0 +1 @@
"""The aladdin_connect component."""

View File

@@ -0,0 +1,113 @@
"""Platform for the Aladdin Connect cover component."""
import logging
import voluptuous as vol
from homeassistant.components.cover import (CoverDevice, PLATFORM_SCHEMA,
SUPPORT_OPEN, SUPPORT_CLOSE)
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, STATE_CLOSED,
STATE_OPENING, STATE_CLOSING, STATE_OPEN)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
NOTIFICATION_ID = 'aladdin_notification'
NOTIFICATION_TITLE = 'Aladdin Connect Cover Setup'
STATES_MAP = {
'open': STATE_OPEN,
'opening': STATE_OPENING,
'closed': STATE_CLOSED,
'closing': STATE_CLOSING
}
SUPPORTED_FEATURES = SUPPORT_OPEN | SUPPORT_CLOSE
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Aladdin Connect platform."""
from aladdin_connect import AladdinConnectClient
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
acc = AladdinConnectClient(username, password)
try:
if not acc.login():
raise ValueError("Username or Password is incorrect")
add_entities(AladdinDevice(acc, door) for door in acc.get_doors())
except (TypeError, KeyError, NameError, ValueError) as ex:
_LOGGER.error("%s", ex)
hass.components.persistent_notification.create(
'Error: {}<br />'
'You will need to restart hass after fixing.'
''.format(ex),
title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID)
class AladdinDevice(CoverDevice):
"""Representation of Aladdin Connect cover."""
def __init__(self, acc, device):
"""Initialize the cover."""
self._acc = acc
self._device_id = device['device_id']
self._number = device['door_number']
self._name = device['name']
self._status = STATES_MAP.get(device['status'])
@property
def device_class(self):
"""Define this cover as a garage door."""
return 'garage'
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORTED_FEATURES
@property
def unique_id(self):
"""Return a unique ID."""
return '{}-{}'.format(self._device_id, self._number)
@property
def name(self):
"""Return the name of the garage door."""
return self._name
@property
def is_opening(self):
"""Return if the cover is opening or not."""
return self._status == STATE_OPENING
@property
def is_closing(self):
"""Return if the cover is closing or not."""
return self._status == STATE_CLOSING
@property
def is_closed(self):
"""Return None if status is unknown, True if closed, else False."""
if self._status is None:
return None
return self._status == STATE_CLOSED
def close_cover(self, **kwargs):
"""Issue close command to cover."""
self._acc.close_door(self._device_id, self._number)
def open_cover(self, **kwargs):
"""Issue open command to cover."""
self._acc.open_door(self._device_id, self._number)
def update(self):
"""Update status of cover."""
acc_status = self._acc.get_door_status(self._device_id, self._number)
self._status = STATES_MAP.get(acc_status)

View File

@@ -0,0 +1,10 @@
{
"domain": "aladdin_connect",
"name": "Aladdin connect",
"documentation": "https://www.home-assistant.io/components/aladdin_connect",
"requirements": [
"aladdin_connect==0.3"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -1,9 +1,4 @@
"""
Component to interface with an alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel/
"""
"""Component to interface with an alarm control panel."""
from datetime import timedelta
import logging

View File

@@ -1,125 +0,0 @@
"""
Interfaces with Alarm.com alarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.alarmdotcom/
"""
import logging
import re
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_CODE, CONF_NAME, CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyalarmdotcom==0.3.2']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Alarm.com'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_CODE): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a Alarm.com control panel."""
name = config.get(CONF_NAME)
code = config.get(CONF_CODE)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
alarmdotcom = AlarmDotCom(hass, name, code, username, password)
await alarmdotcom.async_login()
async_add_entities([alarmdotcom])
class AlarmDotCom(alarm.AlarmControlPanel):
"""Representation of an Alarm.com status."""
def __init__(self, hass, name, code, username, password):
"""Initialize the Alarm.com status."""
from pyalarmdotcom import Alarmdotcom
_LOGGER.debug('Setting up Alarm.com...')
self._hass = hass
self._name = name
self._code = str(code) if code else None
self._username = username
self._password = password
self._websession = async_get_clientsession(self._hass)
self._state = None
self._alarm = Alarmdotcom(
username, password, self._websession, hass.loop)
async def async_login(self):
"""Login to Alarm.com."""
await self._alarm.async_login()
async def async_update(self):
"""Fetch the latest state."""
await self._alarm.async_update()
return self._alarm.state
@property
def name(self):
"""Return the name of the alarm."""
return self._name
@property
def code_format(self):
"""Return one or more digits/characters."""
if self._code is None:
return None
if isinstance(self._code, str) and re.search('^\\d+$', self._code):
return alarm.FORMAT_NUMBER
return alarm.FORMAT_TEXT
@property
def state(self):
"""Return the state of the device."""
if self._alarm.state.lower() == 'disarmed':
return STATE_ALARM_DISARMED
if self._alarm.state.lower() == 'armed stay':
return STATE_ALARM_ARMED_HOME
if self._alarm.state.lower() == 'armed away':
return STATE_ALARM_ARMED_AWAY
return None
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
'sensor_status': self._alarm.sensor_status
}
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
if self._validate_code(code):
await self._alarm.async_alarm_disarm()
async def async_alarm_arm_home(self, code=None):
"""Send arm hom command."""
if self._validate_code(code):
await self._alarm.async_alarm_arm_home()
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
if self._validate_code(code):
await self._alarm.async_alarm_arm_away()
def _validate_code(self, code):
"""Validate given code."""
check = self._code is None or code == self._code
if not check:
_LOGGER.warning("Wrong code entered")
return check

View File

@@ -1,91 +0,0 @@
"""
Support for Canary alarm.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.canary/
"""
import logging
from homeassistant.components.alarm_control_panel import AlarmControlPanel
from homeassistant.components.canary import DATA_CANARY
from homeassistant.const import STATE_ALARM_DISARMED, STATE_ALARM_ARMED_AWAY, \
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMED_HOME
DEPENDENCIES = ['canary']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Canary alarms."""
data = hass.data[DATA_CANARY]
devices = []
for location in data.locations:
devices.append(CanaryAlarm(data, location.location_id))
add_entities(devices, True)
class CanaryAlarm(AlarmControlPanel):
"""Representation of a Canary alarm control panel."""
def __init__(self, data, location_id):
"""Initialize a Canary security camera."""
self._data = data
self._location_id = location_id
@property
def name(self):
"""Return the name of the alarm."""
location = self._data.get_location(self._location_id)
return location.name
@property
def state(self):
"""Return the state of the device."""
from canary.api import LOCATION_MODE_AWAY, LOCATION_MODE_HOME, \
LOCATION_MODE_NIGHT
location = self._data.get_location(self._location_id)
if location.is_private:
return STATE_ALARM_DISARMED
mode = location.mode
if mode.name == LOCATION_MODE_AWAY:
return STATE_ALARM_ARMED_AWAY
if mode.name == LOCATION_MODE_HOME:
return STATE_ALARM_ARMED_HOME
if mode.name == LOCATION_MODE_NIGHT:
return STATE_ALARM_ARMED_NIGHT
return None
@property
def device_state_attributes(self):
"""Return the state attributes."""
location = self._data.get_location(self._location_id)
return {
'private': location.is_private
}
def alarm_disarm(self, code=None):
"""Send disarm command."""
location = self._data.get_location(self._location_id)
self._data.set_location_mode(self._location_id, location.mode.name,
True)
def alarm_arm_home(self, code=None):
"""Send arm home command."""
from canary.api import LOCATION_MODE_HOME
self._data.set_location_mode(self._location_id, LOCATION_MODE_HOME)
def alarm_arm_away(self, code=None):
"""Send arm away command."""
from canary.api import LOCATION_MODE_AWAY
self._data.set_location_mode(self._location_id, LOCATION_MODE_AWAY)
def alarm_arm_night(self, code=None):
"""Send arm night command."""
from canary.api import LOCATION_MODE_NIGHT
self._data.set_location_mode(self._location_id, LOCATION_MODE_NIGHT)

View File

@@ -1,109 +0,0 @@
"""
Support for Concord232 alarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.concord232/
"""
import datetime
import logging
import requests
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
import homeassistant.helpers.config_validation as cv
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_HOST, CONF_NAME, CONF_PORT, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED)
REQUIREMENTS = ['concord232==0.15']
_LOGGER = logging.getLogger(__name__)
DEFAULT_HOST = 'localhost'
DEFAULT_NAME = 'CONCORD232'
DEFAULT_PORT = 5007
SCAN_INTERVAL = datetime.timedelta(seconds=10)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Concord232 alarm control panel platform."""
name = config.get(CONF_NAME)
host = config.get(CONF_HOST)
port = config.get(CONF_PORT)
url = 'http://{}:{}'.format(host, port)
try:
add_entities([Concord232Alarm(url, name)], True)
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to Concord232: %s", str(ex))
class Concord232Alarm(alarm.AlarmControlPanel):
"""Representation of the Concord232-based alarm panel."""
def __init__(self, url, name):
"""Initialize the Concord232 alarm panel."""
from concord232 import client as concord232_client
self._state = None
self._name = name
self._url = url
self._alarm = concord232_client.Client(self._url)
self._alarm.partitions = self._alarm.list_partitions()
self._alarm.last_partition_update = datetime.datetime.now()
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def code_format(self):
"""Return the characters if code is defined."""
return alarm.FORMAT_NUMBER
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Update values from API."""
try:
part = self._alarm.list_partitions()[0]
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to %(host)s: %(reason)s",
dict(host=self._url, reason=ex))
return
except IndexError:
_LOGGER.error("Concord232 reports no partitions")
return
if part['arming_level'] == 'Off':
self._state = STATE_ALARM_DISARMED
elif 'Home' in part['arming_level']:
self._state = STATE_ALARM_ARMED_HOME
else:
self._state = STATE_ALARM_ARMED_AWAY
def alarm_disarm(self, code=None):
"""Send disarm command."""
self._alarm.disarm(code)
def alarm_arm_home(self, code=None):
"""Send arm home command."""
self._alarm.arm('stay')
def alarm_arm_away(self, code=None):
"""Send arm away command."""
self._alarm.arm('away')

View File

@@ -1,49 +0,0 @@
"""
Demo platform that has two fake alarm control panels.
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/demo/
"""
import datetime
from homeassistant.components.alarm_control_panel import manual
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, CONF_DELAY_TIME,
CONF_PENDING_TIME, CONF_TRIGGER_TIME)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Demo alarm control panel platform."""
async_add_entities([
manual.ManualAlarm(hass, 'Alarm', '1234', None, False, {
STATE_ALARM_ARMED_AWAY: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_PENDING_TIME: datetime.timedelta(seconds=5),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_HOME: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_PENDING_TIME: datetime.timedelta(seconds=5),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_NIGHT: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_PENDING_TIME: datetime.timedelta(seconds=5),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_DISARMED: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_CUSTOM_BYPASS: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_PENDING_TIME: datetime.timedelta(seconds=5),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_TRIGGERED: {
CONF_PENDING_TIME: datetime.timedelta(seconds=5),
},
}),
])

View File

@@ -1,133 +0,0 @@
"""
Interfaces with iAlarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.ialarm/
"""
import logging
import re
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_CODE, CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyialarm==0.3']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'iAlarm'
def no_application_protocol(value):
"""Validate that value is without the application protocol."""
protocol_separator = "://"
if not value or protocol_separator in value:
raise vol.Invalid(
'Invalid host, {} is not allowed'.format(protocol_separator))
return value
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): vol.All(cv.string, no_application_protocol),
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_CODE): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up an iAlarm control panel."""
name = config.get(CONF_NAME)
code = config.get(CONF_CODE)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
host = config.get(CONF_HOST)
url = 'http://{}'.format(host)
ialarm = IAlarmPanel(name, code, username, password, url)
add_entities([ialarm], True)
class IAlarmPanel(alarm.AlarmControlPanel):
"""Representation of an iAlarm status."""
def __init__(self, name, code, username, password, url):
"""Initialize the iAlarm status."""
from pyialarm import IAlarm
self._name = name
self._code = str(code) if code else None
self._username = username
self._password = password
self._url = url
self._state = None
self._client = IAlarm(username, password, url)
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def code_format(self):
"""Return one or more digits/characters."""
if self._code is None:
return None
if isinstance(self._code, str) and re.search('^\\d+$', self._code):
return alarm.FORMAT_NUMBER
return alarm.FORMAT_TEXT
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Return the state of the device."""
status = self._client.get_status()
_LOGGER.debug('iAlarm status: %s', status)
if status:
status = int(status)
if status == self._client.DISARMED:
state = STATE_ALARM_DISARMED
elif status == self._client.ARMED_AWAY:
state = STATE_ALARM_ARMED_AWAY
elif status == self._client.ARMED_STAY:
state = STATE_ALARM_ARMED_HOME
elif status == self._client.TRIGGERED:
state = STATE_ALARM_TRIGGERED
else:
state = None
self._state = state
def alarm_disarm(self, code=None):
"""Send disarm command."""
if self._validate_code(code):
self._client.disarm()
def alarm_arm_away(self, code=None):
"""Send arm away command."""
if self._validate_code(code):
self._client.arm_away()
def alarm_arm_home(self, code=None):
"""Send arm home command."""
if self._validate_code(code):
self._client.arm_stay()
def _validate_code(self, code):
"""Validate given code."""
check = self._code is None or code == self._code
if not check:
_LOGGER.warning("Wrong code entered")
return check

View File

@@ -0,0 +1,10 @@
{
"domain": "alarm_control_panel",
"name": "Alarm control panel",
"documentation": "https://www.home-assistant.io/components/alarm_control_panel",
"requirements": [],
"dependencies": [],
"codeowners": [
"@colinodell"
]
}

View File

@@ -1,324 +0,0 @@
"""
Support for manual alarms.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.manual/
"""
import copy
import datetime
import logging
import re
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.const import (
CONF_CODE, CONF_DELAY_TIME, CONF_DISARM_AFTER_TRIGGER, CONF_NAME,
CONF_PENDING_TIME, CONF_PLATFORM, CONF_TRIGGER_TIME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import track_point_in_time
import homeassistant.util.dt as dt_util
from homeassistant.helpers.restore_state import RestoreEntity
_LOGGER = logging.getLogger(__name__)
CONF_CODE_TEMPLATE = 'code_template'
DEFAULT_ALARM_NAME = 'HA Alarm'
DEFAULT_DELAY_TIME = datetime.timedelta(seconds=0)
DEFAULT_PENDING_TIME = datetime.timedelta(seconds=60)
DEFAULT_TRIGGER_TIME = datetime.timedelta(seconds=120)
DEFAULT_DISARM_AFTER_TRIGGER = False
SUPPORTED_STATES = [STATE_ALARM_DISARMED, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_TRIGGERED]
SUPPORTED_PRETRIGGER_STATES = [state for state in SUPPORTED_STATES
if state != STATE_ALARM_TRIGGERED]
SUPPORTED_PENDING_STATES = [state for state in SUPPORTED_STATES
if state != STATE_ALARM_DISARMED]
ATTR_PRE_PENDING_STATE = 'pre_pending_state'
ATTR_POST_PENDING_STATE = 'post_pending_state'
def _state_validator(config):
"""Validate the state."""
config = copy.deepcopy(config)
for state in SUPPORTED_PRETRIGGER_STATES:
if CONF_DELAY_TIME not in config[state]:
config[state][CONF_DELAY_TIME] = config[CONF_DELAY_TIME]
if CONF_TRIGGER_TIME not in config[state]:
config[state][CONF_TRIGGER_TIME] = config[CONF_TRIGGER_TIME]
for state in SUPPORTED_PENDING_STATES:
if CONF_PENDING_TIME not in config[state]:
config[state][CONF_PENDING_TIME] = config[CONF_PENDING_TIME]
return config
def _state_schema(state):
"""Validate the state."""
schema = {}
if state in SUPPORTED_PRETRIGGER_STATES:
schema[vol.Optional(CONF_DELAY_TIME)] = vol.All(
cv.time_period, cv.positive_timedelta)
schema[vol.Optional(CONF_TRIGGER_TIME)] = vol.All(
cv.time_period, cv.positive_timedelta)
if state in SUPPORTED_PENDING_STATES:
schema[vol.Optional(CONF_PENDING_TIME)] = vol.All(
cv.time_period, cv.positive_timedelta)
return vol.Schema(schema)
PLATFORM_SCHEMA = vol.Schema(vol.All({
vol.Required(CONF_PLATFORM): 'manual',
vol.Optional(CONF_NAME, default=DEFAULT_ALARM_NAME): cv.string,
vol.Exclusive(CONF_CODE, 'code validation'): cv.string,
vol.Exclusive(CONF_CODE_TEMPLATE, 'code validation'): cv.template,
vol.Optional(CONF_DELAY_TIME, default=DEFAULT_DELAY_TIME):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_PENDING_TIME, default=DEFAULT_PENDING_TIME):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_TRIGGER_TIME, default=DEFAULT_TRIGGER_TIME):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_DISARM_AFTER_TRIGGER,
default=DEFAULT_DISARM_AFTER_TRIGGER): cv.boolean,
vol.Optional(STATE_ALARM_ARMED_AWAY, default={}):
_state_schema(STATE_ALARM_ARMED_AWAY),
vol.Optional(STATE_ALARM_ARMED_HOME, default={}):
_state_schema(STATE_ALARM_ARMED_HOME),
vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}):
_state_schema(STATE_ALARM_ARMED_NIGHT),
vol.Optional(STATE_ALARM_ARMED_CUSTOM_BYPASS, default={}):
_state_schema(STATE_ALARM_ARMED_CUSTOM_BYPASS),
vol.Optional(STATE_ALARM_DISARMED, default={}):
_state_schema(STATE_ALARM_DISARMED),
vol.Optional(STATE_ALARM_TRIGGERED, default={}):
_state_schema(STATE_ALARM_TRIGGERED),
}, _state_validator))
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the manual alarm platform."""
add_entities([ManualAlarm(
hass,
config[CONF_NAME],
config.get(CONF_CODE),
config.get(CONF_CODE_TEMPLATE),
config.get(CONF_DISARM_AFTER_TRIGGER, DEFAULT_DISARM_AFTER_TRIGGER),
config
)])
class ManualAlarm(alarm.AlarmControlPanel, RestoreEntity):
"""
Representation of an alarm status.
When armed, will be pending for 'pending_time', after that armed.
When triggered, will be pending for the triggering state's 'delay_time'
plus the triggered state's 'pending_time'.
After that will be triggered for 'trigger_time', after that we return to
the previous state or disarm if `disarm_after_trigger` is true.
A trigger_time of zero disables the alarm_trigger service.
"""
def __init__(self, hass, name, code, code_template,
disarm_after_trigger, config):
"""Init the manual alarm panel."""
self._state = STATE_ALARM_DISARMED
self._hass = hass
self._name = name
if code_template:
self._code = code_template
self._code.hass = hass
else:
self._code = code or None
self._disarm_after_trigger = disarm_after_trigger
self._previous_state = self._state
self._state_ts = None
self._delay_time_by_state = {
state: config[state][CONF_DELAY_TIME]
for state in SUPPORTED_PRETRIGGER_STATES}
self._trigger_time_by_state = {
state: config[state][CONF_TRIGGER_TIME]
for state in SUPPORTED_PRETRIGGER_STATES}
self._pending_time_by_state = {
state: config[state][CONF_PENDING_TIME]
for state in SUPPORTED_PENDING_STATES}
@property
def should_poll(self):
"""Return the polling state."""
return False
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
if self._state == STATE_ALARM_TRIGGERED:
if self._within_pending_time(self._state):
return STATE_ALARM_PENDING
trigger_time = self._trigger_time_by_state[self._previous_state]
if (self._state_ts + self._pending_time(self._state) +
trigger_time) < dt_util.utcnow():
if self._disarm_after_trigger:
return STATE_ALARM_DISARMED
self._state = self._previous_state
return self._state
if self._state in SUPPORTED_PENDING_STATES and \
self._within_pending_time(self._state):
return STATE_ALARM_PENDING
return self._state
@property
def _active_state(self):
"""Get the current state."""
if self.state == STATE_ALARM_PENDING:
return self._previous_state
return self._state
def _pending_time(self, state):
"""Get the pending time."""
pending_time = self._pending_time_by_state[state]
if state == STATE_ALARM_TRIGGERED:
pending_time += self._delay_time_by_state[self._previous_state]
return pending_time
def _within_pending_time(self, state):
"""Get if the action is in the pending time window."""
return self._state_ts + self._pending_time(state) > dt_util.utcnow()
@property
def code_format(self):
"""Return one or more digits/characters."""
if self._code is None:
return None
if isinstance(self._code, str) and re.search('^\\d+$', self._code):
return alarm.FORMAT_NUMBER
return alarm.FORMAT_TEXT
def alarm_disarm(self, code=None):
"""Send disarm command."""
if not self._validate_code(code, STATE_ALARM_DISARMED):
return
self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow()
self.schedule_update_ha_state()
def alarm_arm_home(self, code=None):
"""Send arm home command."""
if not self._validate_code(code, STATE_ALARM_ARMED_HOME):
return
self._update_state(STATE_ALARM_ARMED_HOME)
def alarm_arm_away(self, code=None):
"""Send arm away command."""
if not self._validate_code(code, STATE_ALARM_ARMED_AWAY):
return
self._update_state(STATE_ALARM_ARMED_AWAY)
def alarm_arm_night(self, code=None):
"""Send arm night command."""
if not self._validate_code(code, STATE_ALARM_ARMED_NIGHT):
return
self._update_state(STATE_ALARM_ARMED_NIGHT)
def alarm_arm_custom_bypass(self, code=None):
"""Send arm custom bypass command."""
if not self._validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS):
return
self._update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
def alarm_trigger(self, code=None):
"""
Send alarm trigger command.
No code needed, a trigger time of zero for the current state
disables the alarm.
"""
if not self._trigger_time_by_state[self._active_state]:
return
self._update_state(STATE_ALARM_TRIGGERED)
def _update_state(self, state):
"""Update the state."""
if self._state == state:
return
self._previous_state = self._state
self._state = state
self._state_ts = dt_util.utcnow()
self.schedule_update_ha_state()
pending_time = self._pending_time(state)
if state == STATE_ALARM_TRIGGERED:
track_point_in_time(
self._hass, self.async_update_ha_state,
self._state_ts + pending_time)
trigger_time = self._trigger_time_by_state[self._previous_state]
track_point_in_time(
self._hass, self.async_update_ha_state,
self._state_ts + pending_time + trigger_time)
elif state in SUPPORTED_PENDING_STATES and pending_time:
track_point_in_time(
self._hass, self.async_update_ha_state,
self._state_ts + pending_time)
def _validate_code(self, code, state):
"""Validate given code."""
if self._code is None:
return True
if isinstance(self._code, str):
alarm_code = self._code
else:
alarm_code = self._code.render(from_state=self._state,
to_state=state)
check = not alarm_code or code == alarm_code
if not check:
_LOGGER.warning("Invalid code given for %s", state)
return check
@property
def device_state_attributes(self):
"""Return the state attributes."""
state_attr = {}
if self.state == STATE_ALARM_PENDING:
state_attr[ATTR_PRE_PENDING_STATE] = self._previous_state
state_attr[ATTR_POST_PENDING_STATE] = self._state
return state_attr
async def async_added_to_hass(self):
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
state = await self.async_get_last_state()
if state:
if state.state == STATE_ALARM_PENDING and \
hasattr(state, 'attributes') and \
state.attributes['pre_pending_state']:
# If in pending state, we return to the pre_pending_state
self._state = state.attributes['pre_pending_state']
self._state_ts = dt_util.utcnow()
else:
self._state = state.state
self._state_ts = state.last_updated

View File

@@ -1,366 +0,0 @@
"""
Support for manual alarms controllable via MQTT.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.manual_mqtt/
"""
import copy
import datetime
import logging
import re
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
import homeassistant.util.dt as dt_util
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED, STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED,
CONF_PLATFORM, CONF_NAME, CONF_CODE, CONF_DELAY_TIME, CONF_PENDING_TIME,
CONF_TRIGGER_TIME, CONF_DISARM_AFTER_TRIGGER)
from homeassistant.components import mqtt
from homeassistant.helpers.event import async_track_state_change
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import track_point_in_time
_LOGGER = logging.getLogger(__name__)
CONF_CODE_TEMPLATE = 'code_template'
CONF_PAYLOAD_DISARM = 'payload_disarm'
CONF_PAYLOAD_ARM_HOME = 'payload_arm_home'
CONF_PAYLOAD_ARM_AWAY = 'payload_arm_away'
CONF_PAYLOAD_ARM_NIGHT = 'payload_arm_night'
DEFAULT_ALARM_NAME = 'HA Alarm'
DEFAULT_DELAY_TIME = datetime.timedelta(seconds=0)
DEFAULT_PENDING_TIME = datetime.timedelta(seconds=60)
DEFAULT_TRIGGER_TIME = datetime.timedelta(seconds=120)
DEFAULT_DISARM_AFTER_TRIGGER = False
DEFAULT_ARM_AWAY = 'ARM_AWAY'
DEFAULT_ARM_HOME = 'ARM_HOME'
DEFAULT_ARM_NIGHT = 'ARM_NIGHT'
DEFAULT_DISARM = 'DISARM'
SUPPORTED_STATES = [STATE_ALARM_DISARMED, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_TRIGGERED]
SUPPORTED_PRETRIGGER_STATES = [state for state in SUPPORTED_STATES
if state != STATE_ALARM_TRIGGERED]
SUPPORTED_PENDING_STATES = [state for state in SUPPORTED_STATES
if state != STATE_ALARM_DISARMED]
ATTR_PRE_PENDING_STATE = 'pre_pending_state'
ATTR_POST_PENDING_STATE = 'post_pending_state'
def _state_validator(config):
"""Validate the state."""
config = copy.deepcopy(config)
for state in SUPPORTED_PRETRIGGER_STATES:
if CONF_DELAY_TIME not in config[state]:
config[state][CONF_DELAY_TIME] = config[CONF_DELAY_TIME]
if CONF_TRIGGER_TIME not in config[state]:
config[state][CONF_TRIGGER_TIME] = config[CONF_TRIGGER_TIME]
for state in SUPPORTED_PENDING_STATES:
if CONF_PENDING_TIME not in config[state]:
config[state][CONF_PENDING_TIME] = config[CONF_PENDING_TIME]
return config
def _state_schema(state):
"""Validate the state."""
schema = {}
if state in SUPPORTED_PRETRIGGER_STATES:
schema[vol.Optional(CONF_DELAY_TIME)] = vol.All(
cv.time_period, cv.positive_timedelta)
schema[vol.Optional(CONF_TRIGGER_TIME)] = vol.All(
cv.time_period, cv.positive_timedelta)
if state in SUPPORTED_PENDING_STATES:
schema[vol.Optional(CONF_PENDING_TIME)] = vol.All(
cv.time_period, cv.positive_timedelta)
return vol.Schema(schema)
DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = vol.Schema(vol.All(mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
vol.Required(CONF_PLATFORM): 'manual_mqtt',
vol.Optional(CONF_NAME, default=DEFAULT_ALARM_NAME): cv.string,
vol.Exclusive(CONF_CODE, 'code validation'): cv.string,
vol.Exclusive(CONF_CODE_TEMPLATE, 'code validation'): cv.template,
vol.Optional(CONF_DELAY_TIME, default=DEFAULT_DELAY_TIME):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_PENDING_TIME, default=DEFAULT_PENDING_TIME):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_TRIGGER_TIME, default=DEFAULT_TRIGGER_TIME):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_DISARM_AFTER_TRIGGER,
default=DEFAULT_DISARM_AFTER_TRIGGER): cv.boolean,
vol.Optional(STATE_ALARM_ARMED_AWAY, default={}):
_state_schema(STATE_ALARM_ARMED_AWAY),
vol.Optional(STATE_ALARM_ARMED_HOME, default={}):
_state_schema(STATE_ALARM_ARMED_HOME),
vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}):
_state_schema(STATE_ALARM_ARMED_NIGHT),
vol.Optional(STATE_ALARM_DISARMED, default={}):
_state_schema(STATE_ALARM_DISARMED),
vol.Optional(STATE_ALARM_TRIGGERED, default={}):
_state_schema(STATE_ALARM_TRIGGERED),
vol.Required(mqtt.CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Required(mqtt.CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string,
vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string,
vol.Optional(CONF_PAYLOAD_ARM_NIGHT, default=DEFAULT_ARM_NIGHT): cv.string,
vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string,
}), _state_validator))
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the manual MQTT alarm platform."""
add_entities([ManualMQTTAlarm(
hass,
config[CONF_NAME],
config.get(CONF_CODE),
config.get(CONF_CODE_TEMPLATE),
config.get(CONF_DISARM_AFTER_TRIGGER, DEFAULT_DISARM_AFTER_TRIGGER),
config.get(mqtt.CONF_STATE_TOPIC),
config.get(mqtt.CONF_COMMAND_TOPIC),
config.get(mqtt.CONF_QOS),
config.get(CONF_PAYLOAD_DISARM),
config.get(CONF_PAYLOAD_ARM_HOME),
config.get(CONF_PAYLOAD_ARM_AWAY),
config.get(CONF_PAYLOAD_ARM_NIGHT),
config)])
class ManualMQTTAlarm(alarm.AlarmControlPanel):
"""
Representation of an alarm status.
When armed, will be pending for 'pending_time', after that armed.
When triggered, will be pending for the triggering state's 'delay_time'
plus the triggered state's 'pending_time'.
After that will be triggered for 'trigger_time', after that we return to
the previous state or disarm if `disarm_after_trigger` is true.
A trigger_time of zero disables the alarm_trigger service.
"""
def __init__(self, hass, name, code, code_template, disarm_after_trigger,
state_topic, command_topic, qos, payload_disarm,
payload_arm_home, payload_arm_away, payload_arm_night,
config):
"""Init the manual MQTT alarm panel."""
self._state = STATE_ALARM_DISARMED
self._hass = hass
self._name = name
if code_template:
self._code = code_template
self._code.hass = hass
else:
self._code = code or None
self._disarm_after_trigger = disarm_after_trigger
self._previous_state = self._state
self._state_ts = None
self._delay_time_by_state = {
state: config[state][CONF_DELAY_TIME]
for state in SUPPORTED_PRETRIGGER_STATES}
self._trigger_time_by_state = {
state: config[state][CONF_TRIGGER_TIME]
for state in SUPPORTED_PRETRIGGER_STATES}
self._pending_time_by_state = {
state: config[state][CONF_PENDING_TIME]
for state in SUPPORTED_PENDING_STATES}
self._state_topic = state_topic
self._command_topic = command_topic
self._qos = qos
self._payload_disarm = payload_disarm
self._payload_arm_home = payload_arm_home
self._payload_arm_away = payload_arm_away
self._payload_arm_night = payload_arm_night
@property
def should_poll(self):
"""Return the polling state."""
return False
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
if self._state == STATE_ALARM_TRIGGERED:
if self._within_pending_time(self._state):
return STATE_ALARM_PENDING
trigger_time = self._trigger_time_by_state[self._previous_state]
if (self._state_ts + self._pending_time(self._state) +
trigger_time) < dt_util.utcnow():
if self._disarm_after_trigger:
return STATE_ALARM_DISARMED
self._state = self._previous_state
return self._state
if self._state in SUPPORTED_PENDING_STATES and \
self._within_pending_time(self._state):
return STATE_ALARM_PENDING
return self._state
@property
def _active_state(self):
"""Get the current state."""
if self.state == STATE_ALARM_PENDING:
return self._previous_state
return self._state
def _pending_time(self, state):
"""Get the pending time."""
pending_time = self._pending_time_by_state[state]
if state == STATE_ALARM_TRIGGERED:
pending_time += self._delay_time_by_state[self._previous_state]
return pending_time
def _within_pending_time(self, state):
"""Get if the action is in the pending time window."""
return self._state_ts + self._pending_time(state) > dt_util.utcnow()
@property
def code_format(self):
"""Return one or more digits/characters."""
if self._code is None:
return None
if isinstance(self._code, str) and re.search('^\\d+$', self._code):
return alarm.FORMAT_NUMBER
return alarm.FORMAT_TEXT
def alarm_disarm(self, code=None):
"""Send disarm command."""
if not self._validate_code(code, STATE_ALARM_DISARMED):
return
self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow()
self.schedule_update_ha_state()
def alarm_arm_home(self, code=None):
"""Send arm home command."""
if not self._validate_code(code, STATE_ALARM_ARMED_HOME):
return
self._update_state(STATE_ALARM_ARMED_HOME)
def alarm_arm_away(self, code=None):
"""Send arm away command."""
if not self._validate_code(code, STATE_ALARM_ARMED_AWAY):
return
self._update_state(STATE_ALARM_ARMED_AWAY)
def alarm_arm_night(self, code=None):
"""Send arm night command."""
if not self._validate_code(code, STATE_ALARM_ARMED_NIGHT):
return
self._update_state(STATE_ALARM_ARMED_NIGHT)
def alarm_trigger(self, code=None):
"""
Send alarm trigger command.
No code needed, a trigger time of zero for the current state
disables the alarm.
"""
if not self._trigger_time_by_state[self._active_state]:
return
self._update_state(STATE_ALARM_TRIGGERED)
def _update_state(self, state):
"""Update the state."""
if self._state == state:
return
self._previous_state = self._state
self._state = state
self._state_ts = dt_util.utcnow()
self.schedule_update_ha_state()
pending_time = self._pending_time(state)
if state == STATE_ALARM_TRIGGERED:
track_point_in_time(
self._hass, self.async_update_ha_state,
self._state_ts + pending_time)
trigger_time = self._trigger_time_by_state[self._previous_state]
track_point_in_time(
self._hass, self.async_update_ha_state,
self._state_ts + pending_time + trigger_time)
elif state in SUPPORTED_PENDING_STATES and pending_time:
track_point_in_time(
self._hass, self.async_update_ha_state,
self._state_ts + pending_time)
def _validate_code(self, code, state):
"""Validate given code."""
if self._code is None:
return True
if isinstance(self._code, str):
alarm_code = self._code
else:
alarm_code = self._code.render(from_state=self._state,
to_state=state)
check = not alarm_code or code == alarm_code
if not check:
_LOGGER.warning("Invalid code given for %s", state)
return check
@property
def device_state_attributes(self):
"""Return the state attributes."""
state_attr = {}
if self.state == STATE_ALARM_PENDING:
state_attr[ATTR_PRE_PENDING_STATE] = self._previous_state
state_attr[ATTR_POST_PENDING_STATE] = self._state
return state_attr
async def async_added_to_hass(self):
"""Subscribe to MQTT events."""
async_track_state_change(
self.hass, self.entity_id, self._async_state_changed_listener
)
@callback
def message_received(msg):
"""Run when new MQTT message has been received."""
if msg.payload == self._payload_disarm:
self.async_alarm_disarm(self._code)
elif msg.payload == self._payload_arm_home:
self.async_alarm_arm_home(self._code)
elif msg.payload == self._payload_arm_away:
self.async_alarm_arm_away(self._code)
elif msg.payload == self._payload_arm_night:
self.async_alarm_arm_night(self._code)
else:
_LOGGER.warning("Received unexpected payload: %s", msg.payload)
return
await mqtt.async_subscribe(
self.hass, self._command_topic, message_received, self._qos)
async def _async_state_changed_listener(self, entity_id, old_state,
new_state):
"""Publish state change to MQTT."""
mqtt.async_publish(
self.hass, self._state_topic, new_state.state, self._qos, True)

View File

@@ -1,107 +0,0 @@
"""
Support for Ness D8X/D16X alarm panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.ness_alarm/
"""
import logging
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.ness_alarm import (
DATA_NESS, SIGNAL_ARMING_STATE_CHANGED)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMING,
STATE_ALARM_TRIGGERED, STATE_ALARM_PENDING, STATE_ALARM_DISARMED)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ness_alarm']
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Ness Alarm alarm control panel devices."""
if discovery_info is None:
return
device = NessAlarmPanel(hass.data[DATA_NESS], 'Alarm Panel')
async_add_entities([device])
class NessAlarmPanel(alarm.AlarmControlPanel):
"""Representation of a Ness alarm panel."""
def __init__(self, client, name):
"""Initialize the alarm panel."""
self._client = client
self._name = name
self._state = None
async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_ARMING_STATE_CHANGED,
self._handle_arming_state_change)
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def should_poll(self):
"""Return the polling state."""
return False
@property
def code_format(self):
"""Return the regex for code format or None if no code is required."""
return alarm.FORMAT_NUMBER
@property
def state(self):
"""Return the state of the device."""
return self._state
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
await self._client.disarm(code)
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
await self._client.arm_away(code)
async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
await self._client.arm_home(code)
async def async_alarm_trigger(self, code=None):
"""Send trigger/panic command."""
await self._client.panic(code)
@callback
def _handle_arming_state_change(self, arming_state):
"""Handle arming state update."""
from nessclient import ArmingState
if arming_state == ArmingState.UNKNOWN:
self._state = None
elif arming_state == ArmingState.DISARMED:
self._state = STATE_ALARM_DISARMED
elif arming_state == ArmingState.ARMING:
self._state = STATE_ALARM_ARMING
elif arming_state == ArmingState.EXIT_DELAY:
self._state = STATE_ALARM_ARMING
elif arming_state == ArmingState.ARMED:
self._state = STATE_ALARM_ARMED_AWAY
elif arming_state == ArmingState.ENTRY_DELAY:
self._state = STATE_ALARM_PENDING
elif arming_state == ArmingState.TRIGGERED:
self._state = STATE_ALARM_TRIGGERED
else:
_LOGGER.warning("Unhandled arming state: %s", arming_state)
self.async_schedule_update_ha_state()

View File

@@ -1,124 +0,0 @@
"""
Support for NX584 alarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.nx584/
"""
import logging
import requests
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_HOST, CONF_NAME, CONF_PORT, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pynx584==0.4']
_LOGGER = logging.getLogger(__name__)
DEFAULT_HOST = 'localhost'
DEFAULT_NAME = 'NX584'
DEFAULT_PORT = 5007
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the NX584 platform."""
name = config.get(CONF_NAME)
host = config.get(CONF_HOST)
port = config.get(CONF_PORT)
url = 'http://{}:{}'.format(host, port)
try:
add_entities([NX584Alarm(hass, url, name)])
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to NX584: %s", str(ex))
return
class NX584Alarm(alarm.AlarmControlPanel):
"""Representation of a NX584-based alarm panel."""
def __init__(self, hass, url, name):
"""Init the nx584 alarm panel."""
from nx584 import client
self._hass = hass
self._name = name
self._url = url
self._alarm = client.Client(self._url)
# Do an initial list operation so that we will try to actually
# talk to the API and trigger a requests exception for setup_platform()
# to catch
self._alarm.list_zones()
self._state = None
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def code_format(self):
"""Return one or more digits/characters."""
return alarm.FORMAT_NUMBER
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Process new events from panel."""
try:
part = self._alarm.list_partitions()[0]
zones = self._alarm.list_zones()
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to %(host)s: %(reason)s",
dict(host=self._url, reason=ex))
self._state = None
zones = []
except IndexError:
_LOGGER.error("NX584 reports no partitions")
self._state = None
zones = []
bypassed = False
for zone in zones:
if zone['bypassed']:
_LOGGER.debug("Zone %(zone)s is bypassed, assuming HOME",
dict(zone=zone['number']))
bypassed = True
break
if not part['armed']:
self._state = STATE_ALARM_DISARMED
elif bypassed:
self._state = STATE_ALARM_ARMED_HOME
else:
self._state = STATE_ALARM_ARMED_AWAY
for flag in part['condition_flags']:
if flag == "Siren on":
self._state = STATE_ALARM_TRIGGERED
def alarm_disarm(self, code=None):
"""Send disarm command."""
self._alarm.disarm(code)
def alarm_arm_home(self, code=None):
"""Send arm home command."""
self._alarm.arm('stay')
def alarm_arm_away(self, code=None):
"""Send arm away command."""
self._alarm.arm('exit')

View File

@@ -1,107 +0,0 @@
"""
Support for Vanderbilt (formerly Siemens) SPC alarm systems.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.spc/
"""
import logging
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.core import callback
from homeassistant.components.spc import (DATA_API, SIGNAL_UPDATE_ALARM)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED)
_LOGGER = logging.getLogger(__name__)
def _get_alarm_state(area):
"""Get the alarm state."""
from pyspcwebgw.const import AreaMode
if area.verified_alarm:
return STATE_ALARM_TRIGGERED
mode_to_state = {
AreaMode.UNSET: STATE_ALARM_DISARMED,
AreaMode.PART_SET_A: STATE_ALARM_ARMED_HOME,
AreaMode.PART_SET_B: STATE_ALARM_ARMED_NIGHT,
AreaMode.FULL_SET: STATE_ALARM_ARMED_AWAY,
}
return mode_to_state.get(area.mode)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the SPC alarm control panel platform."""
if discovery_info is None:
return
api = hass.data[DATA_API]
async_add_entities([SpcAlarm(area=area, api=api)
for area in api.areas.values()])
class SpcAlarm(alarm.AlarmControlPanel):
"""Representation of the SPC alarm panel."""
def __init__(self, area, api):
"""Initialize the SPC alarm panel."""
self._area = area
self._api = api
async def async_added_to_hass(self):
"""Call for adding new entities."""
async_dispatcher_connect(self.hass,
SIGNAL_UPDATE_ALARM.format(self._area.id),
self._update_callback)
@callback
def _update_callback(self):
"""Call update method."""
self.async_schedule_update_ha_state(True)
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def name(self):
"""Return the name of the device."""
return self._area.name
@property
def changed_by(self):
"""Return the user the last change was triggered by."""
return self._area.last_changed_by
@property
def state(self):
"""Return the state of the device."""
return _get_alarm_state(self._area)
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
from pyspcwebgw.const import AreaMode
await self._api.change_mode(area=self._area,
new_mode=AreaMode.UNSET)
async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
from pyspcwebgw.const import AreaMode
await self._api.change_mode(area=self._area,
new_mode=AreaMode.PART_SET_A)
async def async_alarm_arm_night(self, code=None):
"""Send arm home command."""
from pyspcwebgw.const import AreaMode
await self._api.change_mode(area=self._area,
new_mode=AreaMode.PART_SET_B)
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
from pyspcwebgw.const import AreaMode
await self._api.change_mode(area=self._area,
new_mode=AreaMode.FULL_SET)

View File

@@ -1,106 +0,0 @@
"""
Interfaces with TotalConnect alarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.totalconnect/
"""
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED,
STATE_ALARM_ARMING, STATE_ALARM_DISARMING, CONF_NAME,
STATE_ALARM_ARMED_CUSTOM_BYPASS)
REQUIREMENTS = ['total_connect_client==0.25']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Total Connect'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a TotalConnect control panel."""
name = config.get(CONF_NAME)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
total_connect = TotalConnect(name, username, password)
add_entities([total_connect], True)
class TotalConnect(alarm.AlarmControlPanel):
"""Represent an TotalConnect status."""
def __init__(self, name, username, password):
"""Initialize the TotalConnect status."""
from total_connect_client import TotalConnectClient
_LOGGER.debug("Setting up TotalConnect...")
self._name = name
self._username = username
self._password = password
self._state = None
self._client = TotalConnectClient.TotalConnectClient(
username, password)
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Return the state of the device."""
status = self._client.get_armed_status()
if status == self._client.DISARMED:
state = STATE_ALARM_DISARMED
elif status == self._client.ARMED_STAY:
state = STATE_ALARM_ARMED_HOME
elif status == self._client.ARMED_AWAY:
state = STATE_ALARM_ARMED_AWAY
elif status == self._client.ARMED_STAY_NIGHT:
state = STATE_ALARM_ARMED_NIGHT
elif status == self._client.ARMED_CUSTOM_BYPASS:
state = STATE_ALARM_ARMED_CUSTOM_BYPASS
elif status == self._client.ARMING:
state = STATE_ALARM_ARMING
elif status == self._client.DISARMING:
state = STATE_ALARM_DISARMING
else:
state = None
self._state = state
def alarm_disarm(self, code=None):
"""Send disarm command."""
self._client.disarm()
def alarm_arm_home(self, code=None):
"""Send arm home command."""
self._client.arm_stay()
def alarm_arm_away(self, code=None):
"""Send arm away command."""
self._client.arm_away()
def alarm_arm_night(self, code=None):
"""Send arm night command."""
self._client.arm_stay_night()

View File

@@ -1,98 +0,0 @@
"""
Yale Smart Alarm client for interacting with the Yale Smart Alarm System API.
For more details about this platform, please refer to the documentation at
https://www.home-assistant.io/components/alarm_control_panel.yale_smart_alarm
"""
import logging
import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
AlarmControlPanel, PLATFORM_SCHEMA)
from homeassistant.const import (
CONF_PASSWORD, CONF_USERNAME, CONF_NAME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['yalesmartalarmclient==0.1.6']
CONF_AREA_ID = 'area_id'
DEFAULT_NAME = 'Yale Smart Alarm'
DEFAULT_AREA_ID = '1'
_LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_AREA_ID, default=DEFAULT_AREA_ID): cv.string,
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the alarm platform."""
name = config[CONF_NAME]
username = config[CONF_USERNAME]
password = config[CONF_PASSWORD]
area_id = config[CONF_AREA_ID]
from yalesmartalarmclient.client import (
YaleSmartAlarmClient, AuthenticationError)
try:
client = YaleSmartAlarmClient(username, password, area_id)
except AuthenticationError:
_LOGGER.error("Authentication failed. Check credentials")
return
add_entities([YaleAlarmDevice(name, client)], True)
class YaleAlarmDevice(AlarmControlPanel):
"""Represent a Yale Smart Alarm."""
def __init__(self, name, client):
"""Initialize the Yale Alarm Device."""
self._name = name
self._client = client
self._state = None
from yalesmartalarmclient.client import (YALE_STATE_DISARM,
YALE_STATE_ARM_PARTIAL,
YALE_STATE_ARM_FULL)
self._state_map = {
YALE_STATE_DISARM: STATE_ALARM_DISARMED,
YALE_STATE_ARM_PARTIAL: STATE_ALARM_ARMED_HOME,
YALE_STATE_ARM_FULL: STATE_ALARM_ARMED_AWAY
}
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Return the state of the device."""
armed_status = self._client.get_armed_status()
self._state = self._state_map.get(armed_status)
def alarm_disarm(self, code=None):
"""Send disarm command."""
self._client.disarm()
def alarm_arm_home(self, code=None):
"""Send arm home command."""
self._client.arm_partial()
def alarm_arm_away(self, code=None):
"""Send arm away command."""
self._client.arm_full()

View File

@@ -5,13 +5,11 @@ from datetime import timedelta
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, CONF_HOST
from homeassistant.helpers.discovery import load_platform
from homeassistant.util import dt as dt_util
from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA
REQUIREMENTS = ['alarmdecoder==1.13.2']
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'alarmdecoder'
@@ -20,7 +18,6 @@ DATA_AD = 'alarmdecoder'
CONF_DEVICE = 'device'
CONF_DEVICE_BAUD = 'baudrate'
CONF_DEVICE_HOST = 'host'
CONF_DEVICE_PATH = 'path'
CONF_DEVICE_PORT = 'port'
CONF_DEVICE_TYPE = 'type'
@@ -55,7 +52,7 @@ SIGNAL_REL_MESSAGE = 'alarmdecoder.rel_message'
DEVICE_SOCKET_SCHEMA = vol.Schema({
vol.Required(CONF_DEVICE_TYPE): 'socket',
vol.Optional(CONF_DEVICE_HOST, default=DEFAULT_DEVICE_HOST): cv.string,
vol.Optional(CONF_HOST, default=DEFAULT_DEVICE_HOST): cv.string,
vol.Optional(CONF_DEVICE_PORT, default=DEFAULT_DEVICE_PORT): cv.port})
DEVICE_SERIAL_SCHEMA = vol.Schema({
@@ -165,7 +162,7 @@ def setup(hass, config):
controller = False
if device_type == 'socket':
host = device.get(CONF_DEVICE_HOST)
host = device.get(CONF_HOST)
port = device.get(CONF_DEVICE_PORT)
controller = AlarmDecoder(SocketDevice(interface=(host, port)))
elif device_type == 'serial':

View File

@@ -4,15 +4,14 @@ import logging
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarmdecoder import DATA_AD, SIGNAL_PANEL_MESSAGE
from homeassistant.const import (
ATTR_CODE, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
from . import DATA_AD, SIGNAL_PANEL_MESSAGE
DEPENDENCIES = ['alarmdecoder']
_LOGGER = logging.getLogger(__name__)
SERVICE_ALARM_TOGGLE_CHIME = 'alarmdecoder_alarm_toggle_chime'
ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({

View File

@@ -2,13 +2,11 @@
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.alarmdecoder import (
ZONE_SCHEMA, CONF_ZONES, CONF_ZONE_NAME, CONF_ZONE_TYPE,
CONF_ZONE_RFID, CONF_ZONE_LOOP, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE,
SIGNAL_RFX_MESSAGE, SIGNAL_REL_MESSAGE, CONF_RELAY_ADDR,
CONF_RELAY_CHAN)
DEPENDENCIES = ['alarmdecoder']
from . import (
CONF_RELAY_ADDR, CONF_RELAY_CHAN, CONF_ZONE_LOOP, CONF_ZONE_NAME,
CONF_ZONE_RFID, CONF_ZONE_TYPE, CONF_ZONES, SIGNAL_REL_MESSAGE,
SIGNAL_RFX_MESSAGE, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE, ZONE_SCHEMA)
_LOGGER = logging.getLogger(__name__)

View File

@@ -0,0 +1,10 @@
{
"domain": "alarmdecoder",
"name": "Alarmdecoder",
"documentation": "https://www.home-assistant.io/components/alarmdecoder",
"requirements": [
"alarmdecoder==1.13.2"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -2,12 +2,11 @@
import logging
from homeassistant.helpers.entity import Entity
from homeassistant.components.alarmdecoder import (SIGNAL_PANEL_MESSAGE)
from . import SIGNAL_PANEL_MESSAGE
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['alarmdecoder']
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up for AlarmDecoder sensor devices."""

View File

@@ -0,0 +1 @@
"""The alarmdotcom component."""

View File

@@ -0,0 +1,118 @@
"""Interfaces with Alarm.com alarm control panels."""
import logging
import re
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_CODE, CONF_NAME, CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Alarm.com'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_CODE): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a Alarm.com control panel."""
name = config.get(CONF_NAME)
code = config.get(CONF_CODE)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
alarmdotcom = AlarmDotCom(hass, name, code, username, password)
await alarmdotcom.async_login()
async_add_entities([alarmdotcom])
class AlarmDotCom(alarm.AlarmControlPanel):
"""Representation of an Alarm.com status."""
def __init__(self, hass, name, code, username, password):
"""Initialize the Alarm.com status."""
from pyalarmdotcom import Alarmdotcom
_LOGGER.debug('Setting up Alarm.com...')
self._hass = hass
self._name = name
self._code = str(code) if code else None
self._username = username
self._password = password
self._websession = async_get_clientsession(self._hass)
self._state = None
self._alarm = Alarmdotcom(
username, password, self._websession, hass.loop)
async def async_login(self):
"""Login to Alarm.com."""
await self._alarm.async_login()
async def async_update(self):
"""Fetch the latest state."""
await self._alarm.async_update()
return self._alarm.state
@property
def name(self):
"""Return the name of the alarm."""
return self._name
@property
def code_format(self):
"""Return one or more digits/characters."""
if self._code is None:
return None
if isinstance(self._code, str) and re.search('^\\d+$', self._code):
return alarm.FORMAT_NUMBER
return alarm.FORMAT_TEXT
@property
def state(self):
"""Return the state of the device."""
if self._alarm.state.lower() == 'disarmed':
return STATE_ALARM_DISARMED
if self._alarm.state.lower() == 'armed stay':
return STATE_ALARM_ARMED_HOME
if self._alarm.state.lower() == 'armed away':
return STATE_ALARM_ARMED_AWAY
return None
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
'sensor_status': self._alarm.sensor_status
}
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
if self._validate_code(code):
await self._alarm.async_alarm_disarm()
async def async_alarm_arm_home(self, code=None):
"""Send arm hom command."""
if self._validate_code(code):
await self._alarm.async_alarm_arm_home()
async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
if self._validate_code(code):
await self._alarm.async_alarm_arm_away()
def _validate_code(self, code):
"""Validate given code."""
check = self._code is None or code == self._code
if not check:
_LOGGER.warning("Wrong code entered")
return check

View File

@@ -0,0 +1,10 @@
{
"domain": "alarmdotcom",
"name": "Alarmdotcom",
"documentation": "https://www.home-assistant.io/components/alarmdotcom",
"requirements": [
"pyalarmdotcom==0.3.2"
],
"dependencies": [],
"codeowners": []
}

View File

@@ -0,0 +1,8 @@
{
"domain": "alert",
"name": "Alert",
"documentation": "https://www.home-assistant.io/components/alert",
"requirements": [],
"dependencies": [],
"codeowners": []
}

View File

@@ -17,8 +17,6 @@ _LOGGER = logging.getLogger(__name__)
CONF_FLASH_BRIEFINGS = 'flash_briefings'
CONF_SMART_HOME = 'smart_home'
DEPENDENCIES = ['http']
ALEXA_ENTITY_SCHEMA = vol.Schema({
vol.Optional(smart_home.CONF_DESCRIPTION): cv.string,
vol.Optional(smart_home.CONF_DISPLAY_CATEGORIES): cv.string,

View File

@@ -0,0 +1,10 @@
{
"domain": "alexa",
"name": "Alexa",
"documentation": "https://www.home-assistant.io/components/alexa",
"requirements": [],
"dependencies": [
"http"
],
"codeowners": []
}

View File

@@ -65,6 +65,12 @@ API_THERMOSTAT_MODES = OrderedDict([
(climate.STATE_DRY, 'OFF'),
])
PERCENTAGE_FAN_MAP = {
fan.SPEED_LOW: 33,
fan.SPEED_MEDIUM: 66,
fan.SPEED_HIGH: 100,
}
SMART_HOME_HTTP_ENDPOINT = '/api/alexa/smart_home'
CONF_DESCRIPTION = 'description'
@@ -580,6 +586,26 @@ class _AlexaPercentageController(_AlexaInterface):
def name(self):
return 'Alexa.PercentageController'
def properties_supported(self):
return [{'name': 'percentage'}]
def properties_retrievable(self):
return True
def get_property(self, name):
if name != 'percentage':
raise _UnsupportedProperty(name)
if self.entity.domain == fan.DOMAIN:
speed = self.entity.attributes.get(fan.ATTR_SPEED)
return PERCENTAGE_FAN_MAP.get(speed, 0)
if self.entity.domain == cover.DOMAIN:
return self.entity.attributes.get(cover.ATTR_CURRENT_POSITION, 0)
return 0
class _AlexaSpeaker(_AlexaInterface):
"""Implements Alexa.Speaker.
@@ -885,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:

View File

@@ -0,0 +1 @@
"""The alpha_vantage component."""

View File

@@ -0,0 +1,12 @@
{
"domain": "alpha_vantage",
"name": "Alpha vantage",
"documentation": "https://www.home-assistant.io/components/alpha_vantage",
"requirements": [
"alpha_vantage==2.1.0"
],
"dependencies": [],
"codeowners": [
"@fabaff"
]
}

View File

@@ -0,0 +1,212 @@
"""Stock market information from Alpha Vantage."""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_API_KEY, CONF_CURRENCY, CONF_NAME)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
ATTR_CLOSE = 'close'
ATTR_HIGH = 'high'
ATTR_LOW = 'low'
ATTRIBUTION = "Stock market information provided by Alpha Vantage"
CONF_FOREIGN_EXCHANGE = 'foreign_exchange'
CONF_FROM = 'from'
CONF_SYMBOL = 'symbol'
CONF_SYMBOLS = 'symbols'
CONF_TO = 'to'
ICONS = {
'BTC': 'mdi:currency-btc',
'EUR': 'mdi:currency-eur',
'GBP': 'mdi:currency-gbp',
'INR': 'mdi:currency-inr',
'RUB': 'mdi:currency-rub',
'TRY': 'mdi:currency-try',
'USD': 'mdi:currency-usd',
}
SCAN_INTERVAL = timedelta(minutes=5)
SYMBOL_SCHEMA = vol.Schema({
vol.Required(CONF_SYMBOL): cv.string,
vol.Optional(CONF_CURRENCY): cv.string,
vol.Optional(CONF_NAME): cv.string,
})
CURRENCY_SCHEMA = vol.Schema({
vol.Required(CONF_FROM): cv.string,
vol.Required(CONF_TO): cv.string,
vol.Optional(CONF_NAME): cv.string,
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_FOREIGN_EXCHANGE):
vol.All(cv.ensure_list, [CURRENCY_SCHEMA]),
vol.Optional(CONF_SYMBOLS):
vol.All(cv.ensure_list, [SYMBOL_SCHEMA]),
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Alpha Vantage sensor."""
from alpha_vantage.timeseries import TimeSeries
from alpha_vantage.foreignexchange import ForeignExchange
api_key = config.get(CONF_API_KEY)
symbols = config.get(CONF_SYMBOLS, [])
conversions = config.get(CONF_FOREIGN_EXCHANGE, [])
if not symbols and not conversions:
msg = 'Warning: No symbols or currencies configured.'
hass.components.persistent_notification.create(
msg, 'Sensor alpha_vantage')
_LOGGER.warning(msg)
return
timeseries = TimeSeries(key=api_key)
dev = []
for symbol in symbols:
try:
_LOGGER.debug("Configuring timeseries for symbols: %s",
symbol[CONF_SYMBOL])
timeseries.get_intraday(symbol[CONF_SYMBOL])
except ValueError:
_LOGGER.error(
"API Key is not valid or symbol '%s' not known", symbol)
dev.append(AlphaVantageSensor(timeseries, symbol))
forex = ForeignExchange(key=api_key)
for conversion in conversions:
from_cur = conversion.get(CONF_FROM)
to_cur = conversion.get(CONF_TO)
try:
_LOGGER.debug("Configuring forex %s - %s", from_cur, to_cur)
forex.get_currency_exchange_rate(
from_currency=from_cur, to_currency=to_cur)
except ValueError as error:
_LOGGER.error(
"API Key is not valid or currencies '%s'/'%s' not known",
from_cur, to_cur)
_LOGGER.debug(str(error))
dev.append(AlphaVantageForeignExchange(forex, conversion))
add_entities(dev, True)
_LOGGER.debug("Setup completed")
class AlphaVantageSensor(Entity):
"""Representation of a Alpha Vantage sensor."""
def __init__(self, timeseries, symbol):
"""Initialize the sensor."""
self._symbol = symbol[CONF_SYMBOL]
self._name = symbol.get(CONF_NAME, self._symbol)
self._timeseries = timeseries
self.values = None
self._unit_of_measurement = symbol.get(CONF_CURRENCY, self._symbol)
self._icon = ICONS.get(symbol.get(CONF_CURRENCY, 'USD'))
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement
@property
def state(self):
"""Return the state of the sensor."""
return self.values['1. open']
@property
def device_state_attributes(self):
"""Return the state attributes."""
if self.values is not None:
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
ATTR_CLOSE: self.values['4. close'],
ATTR_HIGH: self.values['2. high'],
ATTR_LOW: self.values['3. low'],
}
@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return self._icon
def update(self):
"""Get the latest data and updates the states."""
_LOGGER.debug("Requesting new data for symbol %s", self._symbol)
all_values, _ = self._timeseries.get_intraday(self._symbol)
self.values = next(iter(all_values.values()))
_LOGGER.debug("Received new values for symbol %s", self._symbol)
class AlphaVantageForeignExchange(Entity):
"""Sensor for foreign exchange rates."""
def __init__(self, foreign_exchange, config):
"""Initialize the sensor."""
self._foreign_exchange = foreign_exchange
self._from_currency = config.get(CONF_FROM)
self._to_currency = config.get(CONF_TO)
if CONF_NAME in config:
self._name = config.get(CONF_NAME)
else:
self._name = '{}/{}'.format(self._to_currency, self._from_currency)
self._unit_of_measurement = self._to_currency
self._icon = ICONS.get(self._from_currency, 'USD')
self.values = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement
@property
def state(self):
"""Return the state of the sensor."""
return round(float(self.values['5. Exchange Rate']), 4)
@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return self._icon
@property
def device_state_attributes(self):
"""Return the state attributes."""
if self.values is not None:
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
CONF_FROM: self._from_currency,
CONF_TO: self._to_currency,
}
def update(self):
"""Get the latest data and updates the states."""
_LOGGER.debug("Requesting new data for forex %s - %s",
self._from_currency, self._to_currency)
self.values, _ = self._foreign_exchange.get_currency_exchange_rate(
from_currency=self._from_currency, to_currency=self._to_currency)
_LOGGER.debug("Received new data for forex %s - %s",
self._from_currency, self._to_currency)

View File

@@ -0,0 +1 @@
"""Support for Amazon Polly integration."""

View File

@@ -0,0 +1,12 @@
{
"domain": "amazon_polly",
"name": "Amazon polly",
"documentation": "https://www.home-assistant.io/components/amazon_polly",
"requirements": [
"boto3==1.9.16"
],
"dependencies": [],
"codeowners": [
"@robbiet480"
]
}

View File

@@ -0,0 +1,202 @@
"""Support for the Amazon Polly text to speech service."""
import logging
import voluptuous as vol
from homeassistant.components.tts import PLATFORM_SCHEMA, Provider
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
CONF_REGION = 'region_name'
CONF_ACCESS_KEY_ID = 'aws_access_key_id'
CONF_SECRET_ACCESS_KEY = 'aws_secret_access_key'
CONF_PROFILE_NAME = 'profile_name'
ATTR_CREDENTIALS = 'credentials'
DEFAULT_REGION = 'us-east-1'
SUPPORTED_REGIONS = ['us-east-1', 'us-east-2', 'us-west-1', 'us-west-2',
'ca-central-1', 'eu-west-1', 'eu-central-1', 'eu-west-2',
'eu-west-3', 'ap-southeast-1', 'ap-southeast-2',
'ap-northeast-2', 'ap-northeast-1', 'ap-south-1',
'sa-east-1']
CONF_VOICE = 'voice'
CONF_OUTPUT_FORMAT = 'output_format'
CONF_SAMPLE_RATE = 'sample_rate'
CONF_TEXT_TYPE = 'text_type'
SUPPORTED_VOICES = [
'Zhiyu', # Chinese
'Mads', 'Naja', # Danish
'Ruben', 'Lotte', # Dutch
'Russell', 'Nicole', # English Austrailian
'Brian', 'Amy', 'Emma', # English
'Aditi', 'Raveena', # English, Indian
'Joey', 'Justin', 'Matthew', 'Ivy', 'Joanna', 'Kendra', 'Kimberly',
'Salli', # English
'Geraint', # English Welsh
'Mathieu', 'Celine', 'Lea', # French
'Chantal', # French Canadian
'Hans', 'Marlene', 'Vicki', # German
'Aditi', # Hindi
'Karl', 'Dora', # Icelandic
'Giorgio', 'Carla', 'Bianca', # Italian
'Takumi', 'Mizuki', # Japanese
'Seoyeon', # Korean
'Liv', # Norwegian
'Jacek', 'Jan', 'Ewa', 'Maja', # Polish
'Ricardo', 'Vitoria', # Portuguese, Brazilian
'Cristiano', 'Ines', # Portuguese, European
'Carmen', # Romanian
'Maxim', 'Tatyana', # Russian
'Enrique', 'Conchita', 'Lucia', # Spanish European
'Mia', # Spanish Mexican
'Miguel', 'Penelope', # Spanish US
'Astrid', # Swedish
'Filiz', # Turkish
'Gwyneth', # Welsh
]
SUPPORTED_OUTPUT_FORMATS = ['mp3', 'ogg_vorbis', 'pcm']
SUPPORTED_SAMPLE_RATES = ['8000', '16000', '22050']
SUPPORTED_SAMPLE_RATES_MAP = {
'mp3': ['8000', '16000', '22050'],
'ogg_vorbis': ['8000', '16000', '22050'],
'pcm': ['8000', '16000'],
}
SUPPORTED_TEXT_TYPES = ['text', 'ssml']
CONTENT_TYPE_EXTENSIONS = {
'audio/mpeg': 'mp3',
'audio/ogg': 'ogg',
'audio/pcm': 'pcm',
}
DEFAULT_VOICE = 'Joanna'
DEFAULT_OUTPUT_FORMAT = 'mp3'
DEFAULT_TEXT_TYPE = 'text'
DEFAULT_SAMPLE_RATES = {
'mp3': '22050',
'ogg_vorbis': '22050',
'pcm': '16000',
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_REGION, default=DEFAULT_REGION):
vol.In(SUPPORTED_REGIONS),
vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): vol.In(SUPPORTED_VOICES),
vol.Optional(CONF_OUTPUT_FORMAT, default=DEFAULT_OUTPUT_FORMAT):
vol.In(SUPPORTED_OUTPUT_FORMATS),
vol.Optional(CONF_SAMPLE_RATE):
vol.All(cv.string, vol.In(SUPPORTED_SAMPLE_RATES)),
vol.Optional(CONF_TEXT_TYPE, default=DEFAULT_TEXT_TYPE):
vol.In(SUPPORTED_TEXT_TYPES),
})
def get_engine(hass, config):
"""Set up Amazon Polly speech component."""
output_format = config.get(CONF_OUTPUT_FORMAT)
sample_rate = config.get(
CONF_SAMPLE_RATE, DEFAULT_SAMPLE_RATES[output_format])
if sample_rate not in SUPPORTED_SAMPLE_RATES_MAP.get(output_format):
_LOGGER.error("%s is not a valid sample rate for %s",
sample_rate, output_format)
return None
config[CONF_SAMPLE_RATE] = sample_rate
import boto3
profile = config.get(CONF_PROFILE_NAME)
if profile is not None:
boto3.setup_default_session(profile_name=profile)
aws_config = {
CONF_REGION: config.get(CONF_REGION),
CONF_ACCESS_KEY_ID: config.get(CONF_ACCESS_KEY_ID),
CONF_SECRET_ACCESS_KEY: config.get(CONF_SECRET_ACCESS_KEY),
}
del config[CONF_REGION]
del config[CONF_ACCESS_KEY_ID]
del config[CONF_SECRET_ACCESS_KEY]
polly_client = boto3.client('polly', **aws_config)
supported_languages = []
all_voices = {}
all_voices_req = polly_client.describe_voices()
for voice in all_voices_req.get('Voices'):
all_voices[voice.get('Id')] = voice
if voice.get('LanguageCode') not in supported_languages:
supported_languages.append(voice.get('LanguageCode'))
return AmazonPollyProvider(
polly_client, config, supported_languages, all_voices)
class AmazonPollyProvider(Provider):
"""Amazon Polly speech api provider."""
def __init__(self, polly_client, config, supported_languages,
all_voices):
"""Initialize Amazon Polly provider for TTS."""
self.client = polly_client
self.config = config
self.supported_langs = supported_languages
self.all_voices = all_voices
self.default_voice = self.config.get(CONF_VOICE)
self.name = 'Amazon Polly'
@property
def supported_languages(self):
"""Return a list of supported languages."""
return self.supported_langs
@property
def default_language(self):
"""Return the default language."""
return self.all_voices.get(self.default_voice).get('LanguageCode')
@property
def default_options(self):
"""Return dict include default options."""
return {CONF_VOICE: self.default_voice}
@property
def supported_options(self):
"""Return a list of supported options."""
return [CONF_VOICE]
def get_tts_audio(self, message, language=None, options=None):
"""Request TTS file from Polly."""
voice_id = options.get(CONF_VOICE, self.default_voice)
voice_in_dict = self.all_voices.get(voice_id)
if language != voice_in_dict.get('LanguageCode'):
_LOGGER.error("%s does not support the %s language",
voice_id, language)
return None, None
resp = self.client.synthesize_speech(
OutputFormat=self.config[CONF_OUTPUT_FORMAT],
SampleRate=self.config[CONF_SAMPLE_RATE],
Text=message,
TextType=self.config[CONF_TEXT_TYPE],
VoiceId=voice_id
)
return (CONTENT_TYPE_EXTENSIONS[resp.get('ContentType')],
resp.get('AudioStream').read())

View File

@@ -0,0 +1,19 @@
{
"config": {
"error": {
"identifier_exists": "Application \u0438/\u0438\u043b\u0438 API \u043a\u043b\u044e\u0447\u044a\u0442 \u0432\u0435\u0447\u0435 \u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d\u0438",
"invalid_key": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d API \u043a\u043b\u044e\u0447 \u0438/\u0438\u043b\u0438 Application \u043a\u043b\u044e\u0447",
"no_devices": "\u041d\u0435 \u0441\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0430"
},
"step": {
"user": {
"data": {
"api_key": "API \u043a\u043b\u044e\u0447",
"app_key": "Application \u043a\u043b\u044e\u0447"
},
"title": "\u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f\u0442\u0430 \u0441\u0438"
}
},
"title": "\u0410\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u043d\u0430 PWS"
}
}

View File

@@ -1,9 +1,19 @@
{
"config": {
"error": {
"identifier_exists": "La clave API y/o la clave de aplicaci\u00f3n ya est\u00e1 registrada",
"invalid_key": "Clave API y/o clave de aplicaci\u00f3n no v\u00e1lida",
"no_devices": "No se han encontrado dispositivos en la cuenta"
},
"step": {
"user": {
"data": {
"api_key": "Clave API",
"app_key": "Clave de aplicaci\u00f3n"
},
"title": "Completa tu informaci\u00f3n"
}
}
},
"title": "Ambient PWS"
}
}

View File

@@ -13,6 +13,7 @@
},
"title": "Veuillez saisir vos informations"
}
}
},
"title": "Ambient PWS"
}
}

View File

@@ -11,7 +11,7 @@
"api_key": "API \ud0a4",
"app_key": "Application \ud0a4"
},
"title": "\uc0ac\uc6a9\uc790 \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694"
"title": "\uc0ac\uc6a9\uc790 \uc815\ubcf4 \uc785\ub825"
}
},
"title": "Ambient PWS"

View File

@@ -1,5 +1,8 @@
{
"config": {
"error": {
"no_devices": "\u0e44\u0e21\u0e48\u0e1e\u0e1a\u0e2d\u0e38\u0e1b\u0e01\u0e23\u0e13\u0e4c\u0e43\u0e14\u0e46 \u0e43\u0e19\u0e1a\u0e31\u0e0d\u0e0a\u0e35\u0e40\u0e25\u0e22"
},
"step": {
"user": {
"data": {

View File

@@ -0,0 +1,19 @@
{
"config": {
"error": {
"identifier_exists": "Application Key \u548c/\u6216 API Key \u5df2\u6ce8\u518c",
"invalid_key": "\u65e0\u6548\u7684 API \u5bc6\u94a5\u548c/\u6216 Application Key",
"no_devices": "\u6ca1\u6709\u5728\u5e10\u6237\u4e2d\u627e\u5230\u8bbe\u5907"
},
"step": {
"user": {
"data": {
"api_key": "API Key",
"app_key": "Application Key"
},
"title": "\u586b\u5199\u60a8\u7684\u4fe1\u606f"
}
},
"title": "Ambient PWS"
}
}

View File

@@ -20,8 +20,6 @@ from .const import (
ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE,
TYPE_BINARY_SENSOR, TYPE_SENSOR)
REQUIREMENTS = ['aioambient==0.1.3']
_LOGGER = logging.getLogger(__name__)
DATA_CONFIG = 'config'
@@ -304,20 +302,33 @@ class AmbientStation:
self.monitored_conditions = monitored_conditions
self.stations = {}
async def ws_connect(self):
"""Register handlers and connect to the websocket."""
async def _attempt_connect(self):
"""Attempt to connect to the socket (retrying later on fail)."""
from aioambient.errors import WebsocketError
try:
await self.client.websocket.connect()
except WebsocketError as err:
_LOGGER.error("Error with the websocket connection: %s", err)
self._ws_reconnect_delay = min(
2 * self._ws_reconnect_delay, 480)
async_call_later(
self._hass, self._ws_reconnect_delay, self.ws_connect)
async def ws_connect(self):
"""Register handlers and connect to the websocket."""
async def _ws_reconnect(event_time):
"""Forcibly disconnect from and reconnect to the websocket."""
_LOGGER.debug('Watchdog expired; forcing socket reconnection')
await self.client.websocket.disconnect()
await self.client.websocket.connect()
await self._attempt_connect()
def on_connect():
"""Define a handler to fire when the websocket is connected."""
_LOGGER.info('Connected to websocket')
_LOGGER.debug('Watchdog starting')
if self._watchdog_listener:
self._watchdog_listener()
self._watchdog_listener = async_call_later(
self._hass, DEFAULT_WATCHDOG_SECONDS, _ws_reconnect)
@@ -381,15 +392,7 @@ class AmbientStation:
self.client.websocket.on_disconnect(on_disconnect)
self.client.websocket.on_subscribed(on_subscribed)
try:
await self.client.websocket.connect()
except WebsocketError as err:
_LOGGER.error("Error with the websocket connection: %s", err)
self._ws_reconnect_delay = min(2 * self._ws_reconnect_delay, 480)
async_call_later(
self._hass, self._ws_reconnect_delay, self.ws_connect)
await self._attempt_connect()
async def ws_disconnect(self):
"""Disconnect from the websocket."""
@@ -411,6 +414,12 @@ class AmbientWeatherEntity(Entity):
self._state = None
self._station_name = station_name
@property
def available(self):
"""Return True if entity is available."""
return self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get(
self._sensor_type) is not None
@property
def device_info(self):
"""Return device registry information for this entity."""

View File

@@ -1,19 +1,17 @@
"""Support for Ambient Weather Station binary sensors."""
import logging
from homeassistant.components.ambient_station import (
SENSOR_TYPES, TYPE_BATT1, TYPE_BATT10, TYPE_BATT2, TYPE_BATT3, TYPE_BATT4,
TYPE_BATT5, TYPE_BATT6, TYPE_BATT7, TYPE_BATT8, TYPE_BATT9, TYPE_BATTOUT,
AmbientWeatherEntity)
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.const import ATTR_NAME
from . import (
SENSOR_TYPES, TYPE_BATT1, TYPE_BATT2, TYPE_BATT3, TYPE_BATT4, TYPE_BATT5,
TYPE_BATT6, TYPE_BATT7, TYPE_BATT8, TYPE_BATT9, TYPE_BATT10, TYPE_BATTOUT,
AmbientWeatherEntity)
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_BINARY_SENSOR
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ambient_station']
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):

View File

@@ -0,0 +1,12 @@
{
"domain": "ambient_station",
"name": "Ambient station",
"documentation": "https://www.home-assistant.io/components/ambient_station",
"requirements": [
"aioambient==0.3.0"
],
"dependencies": [],
"codeowners": [
"@bachya"
]
}

View File

@@ -1,16 +1,13 @@
"""Support for Ambient Weather Station sensors."""
import logging
from homeassistant.components.ambient_station import (
SENSOR_TYPES, AmbientWeatherEntity)
from homeassistant.const import ATTR_NAME
from . import SENSOR_TYPES, AmbientWeatherEntity
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_SENSOR
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ambient_station']
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):

View File

@@ -4,18 +4,14 @@ from datetime import timedelta
import aiohttp
import voluptuous as vol
from requests.exceptions import HTTPError, ConnectTimeout
from requests.exceptions import ConnectionError as ConnectError
from homeassistant.const import (
CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD,
CONF_SENSORS, CONF_SWITCHES, CONF_SCAN_INTERVAL, HTTP_BASIC_AUTHENTICATION)
CONF_BINARY_SENSORS, CONF_SENSORS, CONF_SWITCHES, CONF_SCAN_INTERVAL,
HTTP_BASIC_AUTHENTICATION)
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['amcrest==1.2.5']
DEPENDENCIES = ['ffmpeg']
_LOGGER = logging.getLogger(__name__)
CONF_AUTHENTICATION = 'authentication'
@@ -27,6 +23,7 @@ DEFAULT_NAME = 'Amcrest Camera'
DEFAULT_PORT = 80
DEFAULT_RESOLUTION = 'high'
DEFAULT_STREAM_SOURCE = 'snapshot'
DEFAULT_ARGUMENTS = '-pred 1'
TIMEOUT = 10
DATA_AMCREST = 'amcrest'
@@ -52,9 +49,14 @@ STREAM_SOURCE_LIST = {
'rtsp': 2,
}
BINARY_SENSORS = {
'motion_detected': 'Motion Detected'
}
# Sensor types are defined like: Name, units, icon
SENSOR_MOTION_DETECTOR = 'motion_detector'
SENSORS = {
'motion_detector': ['Motion Detected', None, 'mdi:run'],
SENSOR_MOTION_DETECTOR: ['Motion Detected', None, 'mdi:run'],
'sdcard': ['SD Used', '%', 'mdi:sd'],
'ptz_preset': ['PTZ Preset', None, 'mdi:camera-iris'],
}
@@ -65,48 +67,74 @@ SWITCHES = {
'motion_recording': ['Motion Recording', 'mdi:record-rec']
}
def _deprecated_sensors(value):
if SENSOR_MOTION_DETECTOR in value:
_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
def _has_unique_names(value):
names = [camera[CONF_NAME] for camera in value]
vol.Schema(vol.Unique())(names)
return value
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)]),
})
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.All(cv.ensure_list, [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): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
cv.time_period,
vol.Optional(CONF_SENSORS):
vol.All(cv.ensure_list, [vol.In(SENSORS)]),
vol.Optional(CONF_SWITCHES):
vol.All(cv.ensure_list, [vol.In(SWITCHES)]),
})])
DOMAIN: vol.All(cv.ensure_list, [AMCREST_SCHEMA], _has_unique_names)
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Set up the Amcrest IP Camera component."""
from amcrest import AmcrestCamera
from amcrest import AmcrestCamera, AmcrestError
hass.data[DATA_AMCREST] = {}
hass.data.setdefault(DATA_AMCREST, {})
amcrest_cams = config[DOMAIN]
for device in amcrest_cams:
name = device[CONF_NAME]
username = device[CONF_USERNAME]
password = device[CONF_PASSWORD]
try:
camera = AmcrestCamera(device.get(CONF_HOST),
device.get(CONF_PORT),
device.get(CONF_USERNAME),
device.get(CONF_PASSWORD)).camera
camera = AmcrestCamera(device[CONF_HOST],
device[CONF_PORT],
username,
password).camera
# pylint: disable=pointless-statement
camera.current_time
except (ConnectError, ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Amcrest camera: %s", str(ex))
except AmcrestError as ex:
_LOGGER.error("Unable to connect to %s camera: %s", name, str(ex))
hass.components.persistent_notification.create(
'Error: {}<br />'
'You will need to restart hass after fixing.'
@@ -115,23 +143,19 @@ def setup(hass, config):
notification_id=NOTIFICATION_ID)
continue
ffmpeg_arguments = device.get(CONF_FFMPEG_ARGUMENTS)
name = device.get(CONF_NAME)
resolution = RESOLUTION_LIST[device.get(CONF_RESOLUTION)]
ffmpeg_arguments = device[CONF_FFMPEG_ARGUMENTS]
resolution = RESOLUTION_LIST[device[CONF_RESOLUTION]]
binary_sensors = device.get(CONF_BINARY_SENSORS)
sensors = device.get(CONF_SENSORS)
switches = device.get(CONF_SWITCHES)
stream_source = STREAM_SOURCE_LIST[device.get(CONF_STREAM_SOURCE)]
username = device.get(CONF_USERNAME)
password = device.get(CONF_PASSWORD)
stream_source = STREAM_SOURCE_LIST[device[CONF_STREAM_SOURCE]]
# currently aiohttp only works with basic authentication
# only valid for mjpeg streaming
if username is not None and password is not None:
if device.get(CONF_AUTHENTICATION) == HTTP_BASIC_AUTHENTICATION:
authentication = aiohttp.BasicAuth(username, password)
else:
authentication = None
if device[CONF_AUTHENTICATION] == HTTP_BASIC_AUTHENTICATION:
authentication = aiohttp.BasicAuth(username, password)
else:
authentication = None
hass.data[DATA_AMCREST][name] = AmcrestDevice(
camera, name, authentication, ffmpeg_arguments, stream_source,
@@ -142,6 +166,13 @@ def setup(hass, config):
CONF_NAME: name,
}, config)
if binary_sensors:
discovery.load_platform(
hass, 'binary_sensor', DOMAIN, {
CONF_NAME: name,
CONF_BINARY_SENSORS: binary_sensors
}, config)
if sensors:
discovery.load_platform(
hass, 'sensor', DOMAIN, {
@@ -156,7 +187,7 @@ def setup(hass, config):
CONF_SWITCHES: switches
}, config)
return True
return len(hass.data[DATA_AMCREST]) >= 1
class AmcrestDevice:

View File

@@ -0,0 +1,69 @@
"""Suppoort for Amcrest IP camera binary sensors."""
from datetime import timedelta
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
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=5)
async def async_setup_platform(hass, config, async_add_devices,
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)
class AmcrestBinarySensor(BinarySensorDevice):
"""Binary sensor for Amcrest camera."""
def __init__(self, name, camera, sensor_type):
"""Initialize entity."""
self._name = '{} {}'.format(name, BINARY_SENSORS[sensor_type])
self._camera = camera
self._sensor_type = sensor_type
self._state = None
@property
def name(self):
"""Return entity name."""
return self._name
@property
def is_on(self):
"""Return if entity is on."""
return self._state
@property
def device_class(self):
"""Return device class."""
return DEVICE_CLASS_MOTION
def update(self):
"""Update entity."""
from amcrest import AmcrestError
_LOGGER.debug('Pulling data from %s binary sensor', self._name)
try:
self._state = self._camera.is_motion_detected
except AmcrestError as error:
_LOGGER.error(
'Could not update %s binary sensor due to error: %s',
self.name, error)

View File

@@ -2,19 +2,15 @@
import asyncio
import logging
from requests import RequestException
from urllib3.exceptions import ReadTimeoutError
from homeassistant.components.amcrest import (
DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT)
from homeassistant.components.camera import Camera
from homeassistant.components.camera import (
Camera, SUPPORT_ON_OFF, SUPPORT_STREAM)
from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import CONF_NAME
from homeassistant.helpers.aiohttp_client import (
async_get_clientsession, async_aiohttp_proxy_web,
async_aiohttp_proxy_stream)
async_aiohttp_proxy_stream, async_aiohttp_proxy_web,
async_get_clientsession)
DEPENDENCIES = ['amcrest', 'ffmpeg']
from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT
_LOGGER = logging.getLogger(__name__)
@@ -30,8 +26,6 @@ async def async_setup_platform(hass, config, async_add_entities,
async_add_entities([AmcrestCam(hass, amcrest)], True)
return True
class AmcrestCam(Camera):
"""An implementation of an Amcrest IP camera."""
@@ -41,25 +35,33 @@ class AmcrestCam(Camera):
super(AmcrestCam, self).__init__()
self._name = amcrest.name
self._camera = amcrest.device
self._base_url = self._camera.get_base_url()
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
self._is_recording = False
self._model = None
self._snapshot_lock = asyncio.Lock()
async def async_camera_image(self):
"""Return a still image response from the camera."""
from amcrest import AmcrestError
if not self.is_on:
_LOGGER.error(
'Attempt to take snaphot when %s camera is off', self.name)
return None
async with self._snapshot_lock:
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)
return response.data
except (RequestException, ReadTimeoutError, ValueError) as error:
except AmcrestError as error:
_LOGGER.error(
'Could not get camera image due to error %s', error)
'Could not get image from %s camera due to error: %s',
self.name, error)
return None
async def handle_async_mjpeg_stream(self, request):
@@ -79,7 +81,7 @@ class AmcrestCam(Camera):
self.hass, request, stream_coro)
# streaming via ffmpeg
from haffmpeg import CameraMjpeg
from haffmpeg.camera import CameraMjpeg
streaming_url = self._camera.rtsp_url(typeno=self._resolution)
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
@@ -87,18 +89,97 @@ class AmcrestCam(Camera):
streaming_url, extra_cmd=self._ffmpeg_arguments)
try:
stream_reader = await stream.get_reader()
return await async_aiohttp_proxy_stream(
self.hass, request, stream,
self.hass, request, stream_reader,
self._ffmpeg.ffmpeg_stream_content_type)
finally:
await stream.close()
# Entity property overrides
@property
def name(self):
"""Return the name of this camera."""
return self._name
@property
def supported_features(self):
"""Return supported features."""
return SUPPORT_ON_OFF | SUPPORT_STREAM
# Camera property overrides
@property
def is_recording(self):
"""Return true if the device is recording."""
return self._is_recording
@property
def brand(self):
"""Return the camera brand."""
return 'Amcrest'
@property
def model(self):
"""Return the camera model."""
return self._model
@property
def stream_source(self):
"""Return the source of the stream."""
return self._camera.rtsp_url(typeno=self._resolution)
@property
def is_on(self):
"""Return true if on."""
return self.is_streaming
# Other Entity method overrides
def update(self):
"""Update entity status."""
from amcrest import AmcrestError
_LOGGER.debug('Pulling data from %s camera', self.name)
if self._model is None:
try:
self._model = self._camera.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'
except AmcrestError as error:
_LOGGER.error(
'Could not get %s camera attributes due to error: %s',
self.name, error)
# Other Camera method overrides
def turn_off(self):
"""Turn off camera."""
self._enable_video_stream(False)
def turn_on(self):
"""Turn on camera."""
self._enable_video_stream(True)
# Utility methods
def _enable_video_stream(self, enable):
"""Enable or disable camera video stream."""
from amcrest import AmcrestError
try:
self._camera.video_enabled = enable
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera video stream due to error: %s',
'enable' if enable else 'disable', self.name, error)
else:
self.is_streaming = enable
self.schedule_update_ha_state()

View File

@@ -0,0 +1,12 @@
{
"domain": "amcrest",
"name": "Amcrest",
"documentation": "https://www.home-assistant.io/components/amcrest",
"requirements": [
"amcrest==1.3.0"
],
"dependencies": [
"ffmpeg"
],
"codeowners": []
}

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