Merge pull request #23353 from home-assistant/rc

0.92.0
This commit is contained in:
Paulus Schoutsen 2019-04-24 13:37:44 -07:00 committed by GitHub
commit 8ae2ce2299
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2713 changed files with 32282 additions and 13299 deletions

View File

@ -57,6 +57,7 @@ commands:
<<# parameters.all >>pip install -q --progress-bar off -r requirements_all.txt -c homeassistant/package_constraints.txt<</ parameters.all>> <<# 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 >>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>> <<# 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: - save_cache:
paths: paths:
- ./venv - ./venv
@ -99,6 +100,13 @@ jobs:
mypy $TYPING_FILES mypy $TYPING_FILES
- install - install
- run:
name: validate manifests
command: |
. venv/bin/activate
python -m script.hassfest validate
- run: - run:
name: run gen_requirements_all name: run gen_requirements_all
command: | command: |
@ -139,6 +147,7 @@ jobs:
. venv/bin/activate . venv/bin/activate
PYFILES=$(circleci tests glob "homeassistant/**/*.py" | circleci tests split) PYFILES=$(circleci tests glob "homeassistant/**/*.py" | circleci tests split)
pylint ${PYFILES} pylint ${PYFILES}
no_output_timeout: 15m
pre-test: pre-test:
parameters: parameters:
@ -173,13 +182,14 @@ jobs:
- install - install
- run: - run:
name: run tests name: run tests with code coverage
command: | command: |
. venv/bin/activate . venv/bin/activate
CC_SWITCH="--cov --cov-report="
TESTFILES=$(circleci tests glob "tests/**/test_*.py" | circleci tests split --split-by=timings) TESTFILES=$(circleci tests glob "tests/**/test_*.py" | circleci tests split --split-by=timings)
if [ -z "$CODE_COVERAGE" ]; then CC_SWITCH=""; else CC_SWITCH="--cov --cov-report html:htmlcov"; fi 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}
pytest --timeout=9 --duration=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 script/check_dirty
codecov
- store_test_results: - store_test_results:
path: test-reports path: test-reports

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

View File

@ -21,14 +21,15 @@ omit =
homeassistant/components/alarmdecoder/* homeassistant/components/alarmdecoder/*
homeassistant/components/alarmdotcom/alarm_control_panel.py homeassistant/components/alarmdotcom/alarm_control_panel.py
homeassistant/components/alpha_vantage/sensor.py homeassistant/components/alpha_vantage/sensor.py
homeassistant/components/amazon_polly/tts.py
homeassistant/components/ambient_station/* homeassistant/components/ambient_station/*
homeassistant/components/amcrest/* homeassistant/components/amcrest/*
homeassistant/components/ampio/*
homeassistant/components/android_ip_webcam/* homeassistant/components/android_ip_webcam/*
homeassistant/components/androidtv/* homeassistant/components/androidtv/*
homeassistant/components/anel_pwrctrl/switch.py homeassistant/components/anel_pwrctrl/switch.py
homeassistant/components/anthemav/media_player.py homeassistant/components/anthemav/media_player.py
homeassistant/components/apcupsd/* homeassistant/components/apcupsd/*
homeassistant/components/apiai/*
homeassistant/components/apple_tv/* homeassistant/components/apple_tv/*
homeassistant/components/aqualogic/* homeassistant/components/aqualogic/*
homeassistant/components/aquostv/media_player.py homeassistant/components/aquostv/media_player.py
@ -45,9 +46,7 @@ omit =
homeassistant/components/august/* homeassistant/components/august/*
homeassistant/components/automatic/device_tracker.py homeassistant/components/automatic/device_tracker.py
homeassistant/components/avion/light.py homeassistant/components/avion/light.py
homeassistant/components/aws_lambda/notify.py homeassistant/components/baidu/tts.py
homeassistant/components/aws_sns/notify.py
homeassistant/components/aws_sqs/notify.py
homeassistant/components/bbb_gpio/* homeassistant/components/bbb_gpio/*
homeassistant/components/bbox/device_tracker.py homeassistant/components/bbox/device_tracker.py
homeassistant/components/bbox/sensor.py homeassistant/components/bbox/sensor.py
@ -64,6 +63,7 @@ omit =
homeassistant/components/bme280/sensor.py homeassistant/components/bme280/sensor.py
homeassistant/components/bme680/sensor.py homeassistant/components/bme680/sensor.py
homeassistant/components/bmw_connected_drive/* homeassistant/components/bmw_connected_drive/*
homeassistant/components/bom/camera.py
homeassistant/components/bom/sensor.py homeassistant/components/bom/sensor.py
homeassistant/components/bom/weather.py homeassistant/components/bom/weather.py
homeassistant/components/braviatv/media_player.py homeassistant/components/braviatv/media_player.py
@ -84,6 +84,7 @@ omit =
homeassistant/components/channels/media_player.py homeassistant/components/channels/media_player.py
homeassistant/components/cisco_ios/device_tracker.py homeassistant/components/cisco_ios/device_tracker.py
homeassistant/components/cisco_mobility_express/device_tracker.py homeassistant/components/cisco_mobility_express/device_tracker.py
homeassistant/components/cisco_webex_teams/notify.py
homeassistant/components/ciscospark/notify.py homeassistant/components/ciscospark/notify.py
homeassistant/components/citybikes/sensor.py homeassistant/components/citybikes/sensor.py
homeassistant/components/clementine/media_player.py homeassistant/components/clementine/media_player.py
@ -92,6 +93,7 @@ omit =
homeassistant/components/clicksend_tts/notify.py homeassistant/components/clicksend_tts/notify.py
homeassistant/components/cloudflare/* homeassistant/components/cloudflare/*
homeassistant/components/cmus/media_player.py homeassistant/components/cmus/media_player.py
homeassistant/components/co2signal/*
homeassistant/components/coinbase/* homeassistant/components/coinbase/*
homeassistant/components/comed_hourly_pricing/sensor.py homeassistant/components/comed_hourly_pricing/sensor.py
homeassistant/components/comfoconnect/* homeassistant/components/comfoconnect/*
@ -125,7 +127,6 @@ omit =
homeassistant/components/dlink/switch.py homeassistant/components/dlink/switch.py
homeassistant/components/dlna_dmr/media_player.py homeassistant/components/dlna_dmr/media_player.py
homeassistant/components/dnsip/sensor.py homeassistant/components/dnsip/sensor.py
homeassistant/components/domain_expiry/sensor.py
homeassistant/components/dominos/* homeassistant/components/dominos/*
homeassistant/components/doorbird/* homeassistant/components/doorbird/*
homeassistant/components/dovado/* homeassistant/components/dovado/*
@ -161,9 +162,12 @@ omit =
homeassistant/components/envisalink/* homeassistant/components/envisalink/*
homeassistant/components/ephember/climate.py homeassistant/components/ephember/climate.py
homeassistant/components/epson/media_player.py homeassistant/components/epson/media_player.py
homeassistant/components/epsonworkforce/sensor.py
homeassistant/components/eq3btsmart/climate.py homeassistant/components/eq3btsmart/climate.py
homeassistant/components/esphome/__init__.py homeassistant/components/esphome/__init__.py
homeassistant/components/esphome/binary_sensor.py homeassistant/components/esphome/binary_sensor.py
homeassistant/components/esphome/camera.py
homeassistant/components/esphome/climate.py
homeassistant/components/esphome/cover.py homeassistant/components/esphome/cover.py
homeassistant/components/esphome/fan.py homeassistant/components/esphome/fan.py
homeassistant/components/esphome/light.py homeassistant/components/esphome/light.py
@ -203,6 +207,7 @@ omit =
homeassistant/components/futurenow/light.py homeassistant/components/futurenow/light.py
homeassistant/components/garadget/cover.py homeassistant/components/garadget/cover.py
homeassistant/components/gc100/* homeassistant/components/gc100/*
homeassistant/components/geniushub/*
homeassistant/components/gearbest/sensor.py homeassistant/components/gearbest/sensor.py
homeassistant/components/geizhals/sensor.py homeassistant/components/geizhals/sensor.py
homeassistant/components/github/sensor.py homeassistant/components/github/sensor.py
@ -266,13 +271,10 @@ omit =
homeassistant/components/ifttt/* homeassistant/components/ifttt/*
homeassistant/components/iglo/light.py homeassistant/components/iglo/light.py
homeassistant/components/ihc/* homeassistant/components/ihc/*
homeassistant/components/iliad_italy/sensor.py
homeassistant/components/imap/sensor.py homeassistant/components/imap/sensor.py
homeassistant/components/imap_email_content/sensor.py homeassistant/components/imap_email_content/sensor.py
homeassistant/components/influxdb/sensor.py homeassistant/components/influxdb/sensor.py
homeassistant/components/insteon/* homeassistant/components/insteon/*
homeassistant/components/insteon_local/*
homeassistant/components/insteon_plm/*
homeassistant/components/ios/* homeassistant/components/ios/*
homeassistant/components/iota/* homeassistant/components/iota/*
homeassistant/components/iperf3/* homeassistant/components/iperf3/*
@ -318,7 +320,10 @@ omit =
homeassistant/components/liveboxplaytv/media_player.py homeassistant/components/liveboxplaytv/media_player.py
homeassistant/components/llamalab_automate/notify.py homeassistant/components/llamalab_automate/notify.py
homeassistant/components/lockitron/lock.py homeassistant/components/lockitron/lock.py
homeassistant/components/logi_circle/* homeassistant/components/logi_circle/__init__.py
homeassistant/components/logi_circle/camera.py
homeassistant/components/logi_circle/const.py
homeassistant/components/logi_circle/sensor.py
homeassistant/components/london_underground/sensor.py homeassistant/components/london_underground/sensor.py
homeassistant/components/loopenergy/sensor.py homeassistant/components/loopenergy/sensor.py
homeassistant/components/luci/device_tracker.py homeassistant/components/luci/device_tracker.py
@ -341,6 +346,7 @@ omit =
homeassistant/components/meteo_france/* homeassistant/components/meteo_france/*
homeassistant/components/metoffice/sensor.py homeassistant/components/metoffice/sensor.py
homeassistant/components/metoffice/weather.py homeassistant/components/metoffice/weather.py
homeassistant/components/microsoft/tts.py
homeassistant/components/miflora/sensor.py homeassistant/components/miflora/sensor.py
homeassistant/components/mikrotik/device_tracker.py homeassistant/components/mikrotik/device_tracker.py
homeassistant/components/mill/climate.py homeassistant/components/mill/climate.py
@ -363,8 +369,8 @@ omit =
homeassistant/components/mystrom/binary_sensor.py homeassistant/components/mystrom/binary_sensor.py
homeassistant/components/mystrom/light.py homeassistant/components/mystrom/light.py
homeassistant/components/mystrom/switch.py homeassistant/components/mystrom/switch.py
homeassistant/components/n26/*
homeassistant/components/nad/media_player.py homeassistant/components/nad/media_player.py
homeassistant/components/nadtcp/media_player.py
homeassistant/components/nanoleaf/light.py homeassistant/components/nanoleaf/light.py
homeassistant/components/neato/* homeassistant/components/neato/*
homeassistant/components/nederlandse_spoorwegen/sensor.py homeassistant/components/nederlandse_spoorwegen/sensor.py
@ -373,7 +379,6 @@ omit =
homeassistant/components/netatmo/* homeassistant/components/netatmo/*
homeassistant/components/netatmo_public/sensor.py homeassistant/components/netatmo_public/sensor.py
homeassistant/components/netdata/sensor.py homeassistant/components/netdata/sensor.py
homeassistant/components/netdata_public/sensor.py
homeassistant/components/netgear/device_tracker.py homeassistant/components/netgear/device_tracker.py
homeassistant/components/netgear_lte/* homeassistant/components/netgear_lte/*
homeassistant/components/netio/switch.py homeassistant/components/netio/switch.py
@ -394,6 +399,7 @@ omit =
homeassistant/components/nzbget/sensor.py homeassistant/components/nzbget/sensor.py
homeassistant/components/octoprint/* homeassistant/components/octoprint/*
homeassistant/components/oem/climate.py homeassistant/components/oem/climate.py
homeassistant/components/oasa_telematics/sensor.py
homeassistant/components/ohmconnect/sensor.py homeassistant/components/ohmconnect/sensor.py
homeassistant/components/onewire/sensor.py homeassistant/components/onewire/sensor.py
homeassistant/components/onkyo/media_player.py homeassistant/components/onkyo/media_player.py
@ -422,6 +428,7 @@ omit =
homeassistant/components/pencom/switch.py homeassistant/components/pencom/switch.py
homeassistant/components/philips_js/media_player.py homeassistant/components/philips_js/media_player.py
homeassistant/components/pi_hole/sensor.py homeassistant/components/pi_hole/sensor.py
homeassistant/components/picotts/tts.py
homeassistant/components/piglow/light.py homeassistant/components/piglow/light.py
homeassistant/components/pilight/* homeassistant/components/pilight/*
homeassistant/components/ping/binary_sensor.py homeassistant/components/ping/binary_sensor.py
@ -533,6 +540,7 @@ omit =
homeassistant/components/sochain/sensor.py homeassistant/components/sochain/sensor.py
homeassistant/components/socialblade/sensor.py homeassistant/components/socialblade/sensor.py
homeassistant/components/solaredge/sensor.py homeassistant/components/solaredge/sensor.py
homeassistant/components/somfy_mylink/*
homeassistant/components/sonarr/sensor.py homeassistant/components/sonarr/sensor.py
homeassistant/components/songpal/media_player.py homeassistant/components/songpal/media_player.py
homeassistant/components/sonos/* homeassistant/components/sonos/*
@ -546,6 +554,7 @@ omit =
homeassistant/components/srp_energy/sensor.py homeassistant/components/srp_energy/sensor.py
homeassistant/components/starlingbank/sensor.py homeassistant/components/starlingbank/sensor.py
homeassistant/components/steam_online/sensor.py homeassistant/components/steam_online/sensor.py
homeassistant/components/stiebel_eltron/*
homeassistant/components/stride/notify.py homeassistant/components/stride/notify.py
homeassistant/components/supervisord/sensor.py homeassistant/components/supervisord/sensor.py
homeassistant/components/swiss_hydrological_data/sensor.py homeassistant/components/swiss_hydrological_data/sensor.py
@ -573,7 +582,6 @@ omit =
homeassistant/components/tellduslive/* homeassistant/components/tellduslive/*
homeassistant/components/tellstick/* homeassistant/components/tellstick/*
homeassistant/components/telnet/switch.py homeassistant/components/telnet/switch.py
homeassistant/components/telstra/notify.py
homeassistant/components/temper/sensor.py homeassistant/components/temper/sensor.py
homeassistant/components/tensorflow/image_processing.py homeassistant/components/tensorflow/image_processing.py
homeassistant/components/tesla/* homeassistant/components/tesla/*
@ -605,10 +613,6 @@ omit =
homeassistant/components/trafikverket_weatherstation/sensor.py homeassistant/components/trafikverket_weatherstation/sensor.py
homeassistant/components/transmission/* homeassistant/components/transmission/*
homeassistant/components/travisci/sensor.py homeassistant/components/travisci/sensor.py
homeassistant/components/tts/amazon_polly.py
homeassistant/components/tts/baidu.py
homeassistant/components/tts/microsoft.py
homeassistant/components/tts/picotts.py
homeassistant/components/tuya/* homeassistant/components/tuya/*
homeassistant/components/twilio_call/notify.py homeassistant/components/twilio_call/notify.py
homeassistant/components/twilio_sms/notify.py homeassistant/components/twilio_sms/notify.py
@ -650,6 +654,7 @@ omit =
homeassistant/components/wirelesstag/* homeassistant/components/wirelesstag/*
homeassistant/components/worldtidesinfo/sensor.py homeassistant/components/worldtidesinfo/sensor.py
homeassistant/components/worxlandroid/sensor.py homeassistant/components/worxlandroid/sensor.py
homeassistant/components/wunderlist/*
homeassistant/components/x10/light.py homeassistant/components/x10/light.py
homeassistant/components/xbox_live/sensor.py homeassistant/components/xbox_live/sensor.py
homeassistant/components/xeoma/camera.py homeassistant/components/xeoma/camera.py
@ -663,7 +668,7 @@ omit =
homeassistant/components/yale_smart_alarm/alarm_control_panel.py homeassistant/components/yale_smart_alarm/alarm_control_panel.py
homeassistant/components/yamaha/media_player.py homeassistant/components/yamaha/media_player.py
homeassistant/components/yamaha_musiccast/media_player.py homeassistant/components/yamaha_musiccast/media_player.py
homeassistant/components/yeelight/light.py homeassistant/components/yeelight/*
homeassistant/components/yeelightsunflower/light.py homeassistant/components/yeelightsunflower/light.py
homeassistant/components/yi/camera.py homeassistant/components/yi/camera.py
homeassistant/components/zabbix/* homeassistant/components/zabbix/*
@ -688,6 +693,7 @@ omit =
homeassistant/components/zigbee/* homeassistant/components/zigbee/*
homeassistant/components/ziggo_mediabox_xl/media_player.py homeassistant/components/ziggo_mediabox_xl/media_player.py
homeassistant/components/zoneminder/* homeassistant/components/zoneminder/*
homeassistant/components/supla/*
homeassistant/components/zwave/util.py homeassistant/components/zwave/util.py
[report] [report]

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) - [ ] 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: 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 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 or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
- [ ] New files were added to `.coveragerc`. - [ ] 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: If the code does not interact with devices:
- [ ] Tests have been added to verify that the new code works. - [ ] 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 [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" { workflow "Mention CODEOWNERS of integrations when integration label is added to an issue" {
resolves = ["Python 3.7 - tests"] on = "issues"
on = "push" resolves = "codeowners-mention"
} }
action "Python 3.7 - tests" { workflow "Mention CODEOWNERS of integrations when integration label is added to an PRs" {
uses = "home-assistant/actions/py37-tox@master" on = "pull_request"
args = "-e py37" resolves = "codeowners-mention"
} }
workflow "Python 3.6 - tox" { action "codeowners-mention" {
resolves = ["Python 3.6 - tests"] uses = "home-assistant/codeowners-mention@master"
on = "push" secrets = ["GITHUB_TOKEN"]
}
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"]
} }

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

View File

@ -11,9 +11,6 @@ from typing import Any, Optional, Dict, Set
import voluptuous as vol import voluptuous as vol
from homeassistant import core, config as conf_util, config_entries, loader from homeassistant import core, config as conf_util, config_entries, loader
from homeassistant.components import (
persistent_notification, homeassistant as core_component
)
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.logging import AsyncHandler from homeassistant.util.logging import AsyncHandler
@ -29,50 +26,16 @@ ERROR_LOG_FILENAME = 'home-assistant.log'
# hass.data key for logging information. # hass.data key for logging information.
DATA_LOGGING = 'logging' DATA_LOGGING = 'logging'
LOGGING_COMPONENT = {'logger', 'system_log'} CORE_INTEGRATIONS = ('homeassistant', 'persistent_notification')
LOGGING_INTEGRATIONS = {'logger', 'system_log'}
FIRST_INIT_COMPONENT = { STAGE_1_INTEGRATIONS = {
# To record data
'recorder', 'recorder',
'mqtt', # To make sure we forward data to other instances
'mqtt_eventstream', '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], async def async_from_config_dict(config: Dict[str, Any],
hass: core.HomeAssistant, hass: core.HomeAssistant,
config_dir: Optional[str] = None, config_dir: Optional[str] = None,
@ -115,70 +78,17 @@ async def async_from_config_dict(config: Dict[str, Any],
"Further initialization aborted") "Further initialization aborted")
return None return None
await hass.async_add_executor_job(
conf_util.process_ha_config_upgrade, hass)
# Make a copy because we are mutating it. # Make a copy because we are mutating it.
config = OrderedDict(config) config = OrderedDict(config)
# Merge packages # Merge packages
conf_util.merge_packages_config( await conf_util.merge_packages_config(
hass, config, core_config.get(conf_util.CONF_PACKAGES, {})) hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))
hass.config_entries = config_entries.ConfigEntries(hass, config) hass.config_entries = config_entries.ConfigEntries(hass, config)
await hass.config_entries.async_initialize() await hass.config_entries.async_initialize()
components = _get_components(hass, config) await _async_set_up_integrations(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_component.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()
# 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())
# 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()
stop = time() stop = time()
_LOGGER.info("Home Assistant initialized in %.2fs", stop-start) _LOGGER.info("Home Assistant initialized in %.2fs", stop-start)
@ -231,32 +141,6 @@ async def async_from_config_dict(config: Dict[str, Any],
return hass 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, async def async_from_config_file(config_path: str,
hass: core.HomeAssistant, hass: core.HomeAssistant,
verbose: bool = False, verbose: bool = False,
@ -280,6 +164,9 @@ async def async_from_config_file(config_path: str,
async_enable_logging(hass, verbose, log_rotate_days, log_file, async_enable_logging(hass, verbose, log_rotate_days, log_file,
log_no_color) log_no_color)
await hass.async_add_executor_job(
conf_util.process_ha_config_upgrade, hass)
try: try:
config_dict = await hass.async_add_executor_job( config_dict = await hass.async_add_executor_job(
conf_util.load_yaml_config_file, config_path) conf_util.load_yaml_config_file, config_path)
@ -398,18 +285,127 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
@core.callback @core.callback
def _get_components(hass: core.HomeAssistant, def _get_domains(hass: core.HomeAssistant, config: Dict[str, Any]) -> Set[str]:
config: Dict[str, Any]) -> Set[str]: """Get domains of components to set up."""
"""Get components to set up."""
# Filter out the repeating and common config section [homeassistant] # Filter out the repeating and common config section [homeassistant]
components = set(key.split(' ')[0] for key in config.keys() domains = set(key.split(' ')[0] for key in config.keys()
if key != core.DOMAIN) if key != core.DOMAIN)
# Add config entry domains # 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 # Make sure the Hass.io component is loaded
if 'HASSIO' in os.environ: 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 logging_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

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

View File

@ -8,8 +8,6 @@ from homeassistant.const import (
from . import ATTRIBUTION, DOMAIN as ABODE_DOMAIN, AbodeDevice from . import ATTRIBUTION, DOMAIN as ABODE_DOMAIN, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ICON = 'mdi:security' ICON = 'mdi:security'

View File

@ -7,8 +7,6 @@ from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['abode']
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a sensor for an Abode device.""" """Set up a sensor for an Abode device."""

View File

@ -9,8 +9,6 @@ from homeassistant.util import Throttle
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
DEPENDENCIES = ['abode']
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90) MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -5,8 +5,6 @@ from homeassistant.components.cover import CoverDevice
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -10,8 +10,6 @@ from homeassistant.util.color import (
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -5,8 +5,6 @@ from homeassistant.components.lock import LockDevice
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__) _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

@ -8,8 +8,6 @@ from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['abode']
# Sensor types: Name, icon # Sensor types: Name, icon
SENSOR_TYPES = { SENSOR_TYPES = {
'temp': ['Temperature', DEVICE_CLASS_TEMPERATURE], 'temp': ['Temperature', DEVICE_CLASS_TEMPERATURE],

View File

@ -7,8 +7,6 @@ from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['abode']
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up Abode switch devices.""" """Set up Abode switch devices."""

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

@ -1,9 +1,4 @@
""" """Use serial protocol of Acer projector to obtain state of the projector."""
Use serial protocol of Acer projector to obtain state of the projector.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/switch.acer_projector/
"""
import logging import logging
import re import re
@ -14,8 +9,6 @@ from homeassistant.const import (
STATE_ON, STATE_OFF, STATE_UNKNOWN, CONF_NAME, CONF_FILENAME) STATE_ON, STATE_OFF, STATE_UNKNOWN, CONF_NAME, CONF_FILENAME)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyserial==3.1.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_TIMEOUT = 'timeout' CONF_TIMEOUT = 'timeout'

View File

@ -1,9 +1,4 @@
""" """Support for Actiontec MI424WR (Verizon FIOS) routers."""
Support for Actiontec MI424WR (Verizon FIOS) routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.actiontec/
"""
import logging import logging
import re import re
import telnetlib import telnetlib

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 logging
import ctypes import ctypes
from collections import namedtuple from collections import namedtuple
import asyncio
import async_timeout
import voluptuous as vol import voluptuous as vol
from homeassistant.const import ( from homeassistant.const import (
CONF_DEVICE, CONF_IP_ADDRESS, CONF_PORT, EVENT_HOMEASSISTANT_STOP) CONF_DEVICE, CONF_IP_ADDRESS, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['pyads==3.0.7']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -31,6 +32,9 @@ CONF_ADS_VALUE = 'value'
CONF_ADS_VAR = 'adsvar' CONF_ADS_VAR = 'adsvar'
CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness' CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness'
STATE_KEY_STATE = 'state'
STATE_KEY_BRIGHTNESS = 'brightness'
DOMAIN = 'ads' DOMAIN = 'ads'
SERVICE_WRITE_DATA_BY_NAME = 'write_data_by_name' SERVICE_WRITE_DATA_BY_NAME = 'write_data_by_name'
@ -154,28 +158,41 @@ class AdsHub:
def write_by_name(self, name, value, plc_datatype): def write_by_name(self, name, value, plc_datatype):
"""Write a value to the device.""" """Write a value to the device."""
import pyads
with self._lock: 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): def read_by_name(self, name, plc_datatype):
"""Read a value from the device.""" """Read a value from the device."""
import pyads
with self._lock: 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): def add_device_notification(self, name, plc_datatype, callback):
"""Add a notification to the ADS devices.""" """Add a notification to the ADS devices."""
from pyads import NotificationAttrib import pyads
attr = NotificationAttrib(ctypes.sizeof(plc_datatype)) attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype))
with self._lock: with self._lock:
hnotify, huser = self._client.add_device_notification( try:
name, attr, self._device_notification_callback) hnotify, huser = self._client.add_device_notification(
hnotify = int(hnotify) name, attr, self._device_notification_callback)
self._notification_items[hnotify] = NotificationItem( except pyads.ADSError as err:
hnotify, huser, name, plc_datatype, callback) _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( _LOGGER.debug(
"Added device notification %d for variable %s", hnotify, name) "Added device notification %d for variable %s",
hnotify, name)
def _device_notification_callback(self, notification, name): def _device_notification_callback(self, notification, name):
"""Handle device notifications.""" """Handle device notifications."""
@ -210,3 +227,68 @@ class AdsHub:
_LOGGER.warning("No callback available for this datatype") _LOGGER.warning("No callback available for this datatype")
notification_item.callback(notification_item.name, value) 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

@ -8,13 +8,11 @@ from homeassistant.components.binary_sensor import (
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, DATA_ADS from . import CONF_ADS_VAR, DATA_ADS, AdsEntity, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'ADS binary sensor' DEFAULT_NAME = 'ADS binary sensor'
DEPENDENCIES = ['ads']
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADS_VAR): cv.string, vol.Required(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
@ -34,51 +32,25 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
add_entities([ads_sensor]) add_entities([ads_sensor])
class AdsBinarySensor(BinarySensorDevice): class AdsBinarySensor(AdsEntity, BinarySensorDevice):
"""Representation of ADS binary sensors.""" """Representation of ADS binary sensors."""
def __init__(self, ads_hub, name, ads_var, device_class): def __init__(self, ads_hub, name, ads_var, device_class):
"""Initialize ADS binary sensor.""" """Initialize ADS binary sensor."""
self._name = name super().__init__(ads_hub, name, ads_var)
self._unique_id = ads_var
self._state = False
self._device_class = device_class or 'moving' self._device_class = device_class or 'moving'
self._ads_hub = ads_hub
self.ads_var = ads_var
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register device notification.""" """Register device notification."""
def update(name, value): await self.async_initialize_device(self._ads_var,
"""Handle device notifications.""" self._ads_hub.PLCTYPE_BOOL)
_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)
@property @property
def name(self): def is_on(self):
"""Return the default name of the binary sensor.""" """Return True if the entity is on."""
return self._name return self._state_dict[STATE_KEY_STATE]
@property
def unique_id(self):
"""Return an unique identifier for this entity."""
return self._unique_id
@property @property
def device_class(self): def device_class(self):
"""Return the device class.""" """Return the device class."""
return self._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

@ -8,12 +8,11 @@ from homeassistant.components.light import (
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS, \
AdsEntity, STATE_KEY_BRIGHTNESS, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ads']
DEFAULT_NAME = 'ADS Light' DEFAULT_NAME = 'ADS Light'
CONF_ADSVAR_BRIGHTNESS = 'adsvar_brightness'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADS_VAR): cv.string, vol.Required(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_ADS_VAR_BRIGHTNESS): cv.string, vol.Optional(CONF_ADS_VAR_BRIGHTNESS): cv.string,
@ -30,91 +29,57 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, 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.""" """Representation of ADS light."""
def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name): def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name):
"""Initialize AdsLight entity.""" """Initialize AdsLight entity."""
self._ads_hub = ads_hub super().__init__(ads_hub, name, ads_var_enable)
self._on_state = False self._state_dict[STATE_KEY_BRIGHTNESS] = None
self._brightness = None self._ads_var_brightness = ads_var_brightness
self._name = name
self._unique_id = ads_var_enable
self.ads_var_enable = ads_var_enable
self.ads_var_brightness = ads_var_brightness
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register device notification.""" """Register device notification."""
def update_on_state(name, value): await self.async_initialize_device(self._ads_var,
"""Handle device notifications for state.""" self._ads_hub.PLCTYPE_BOOL)
_LOGGER.debug('Variable %s changed its value to %d', name, value)
self._on_state = value
self.schedule_update_ha_state()
def update_brightness(name, value): if self._ads_var_brightness is not None:
"""Handle device notification for brightness.""" await self.async_initialize_device(self._ads_var_brightness,
_LOGGER.debug('Variable %s changed its value to %d', name, value) self._ads_hub.PLCTYPE_UINT,
self._brightness = value STATE_KEY_BRIGHTNESS)
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
@property @property
def brightness(self): def brightness(self):
"""Return the brightness of the light (0..255).""" """Return the brightness of the light (0..255)."""
return self._brightness return self._state_dict[STATE_KEY_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
@property @property
def supported_features(self): def supported_features(self):
"""Flag supported features.""" """Flag supported features."""
support = 0 support = 0
if self.ads_var_brightness is not None: if self._ads_var_brightness is not None:
support = SUPPORT_BRIGHTNESS support = SUPPORT_BRIGHTNESS
return support 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): def turn_on(self, **kwargs):
"""Turn the light on or set a specific dimmer value.""" """Turn the light on or set a specific dimmer value."""
brightness = kwargs.get(ATTR_BRIGHTNESS) 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) self._ads_hub.PLCTYPE_BOOL)
if self.ads_var_brightness is not None and brightness is not None: 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.write_by_name(self._ads_var_brightness, brightness,
self._ads_hub.PLCTYPE_UINT) self._ads_hub.PLCTYPE_UINT)
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the light off.""" """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) 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

@ -7,15 +7,13 @@ from homeassistant.components import ads
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR, \
AdsEntity, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "ADS sensor" DEFAULT_NAME = "ADS sensor"
DEPENDENCIES = ['ads']
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADS_VAR): cv.string, vol.Required(CONF_ADS_VAR): cv.string,
vol.Optional(CONF_ADS_FACTOR): cv.positive_int, 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]) add_entities([entity])
class AdsSensor(Entity): class AdsSensor(AdsEntity):
"""Representation of an ADS sensor entity.""" """Representation of an ADS sensor entity."""
def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement, def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement,
factor): factor):
"""Initialize AdsSensor entity.""" """Initialize AdsSensor entity."""
self._ads_hub = ads_hub super().__init__(ads_hub, name, ads_var)
self._name = name
self._unique_id = ads_var
self._value = None
self._unit_of_measurement = unit_of_measurement self._unit_of_measurement = unit_of_measurement
self.ads_var = ads_var self._ads_type = ads_type
self.ads_type = ads_type self._factor = factor
self.factor = factor
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register device notification.""" """Register device notification."""
def update(name, value): await self.async_initialize_device(
"""Handle device notifications.""" self._ads_var,
_LOGGER.debug("Variable %s changed its value to %d", name, value) self._ads_hub.ADS_TYPEMAP[self._ads_type],
STATE_KEY_STATE,
# If factor is set use it otherwise not self._factor)
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
@property @property
def state(self): def state(self):
"""Return the state of the device.""" """Return the state of the device."""
return self._value return self._state_dict[STATE_KEY_STATE]
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement.""" """Return the unit of measurement."""
return self._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,17 +3,14 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.switch import PLATFORM_SCHEMA from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity
from . import CONF_ADS_VAR, DATA_ADS from . import CONF_ADS_VAR, DATA_ADS, AdsEntity, STATE_KEY_STATE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ads']
DEFAULT_NAME = 'ADS Switch' DEFAULT_NAME = 'ADS Switch'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@ -29,58 +26,28 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
ads_var = config.get(CONF_ADS_VAR) 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.""" """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): async def async_added_to_hass(self):
"""Register device notification.""" """Register device notification."""
def update(name, value): await self.async_initialize_device(self._ads_var,
"""Handle device notification.""" self._ads_hub.PLCTYPE_BOOL)
_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)
@property @property
def is_on(self): def is_on(self):
"""Return if the switch is turned on.""" """Return True if the entity is on."""
return self._on_state return self._state_dict[STATE_KEY_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
def turn_on(self, **kwargs): def turn_on(self, **kwargs):
"""Turn the switch on.""" """Turn the switch on."""
self._ads_hub.write_by_name( 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): def turn_off(self, **kwargs):
"""Turn the switch off.""" """Turn the switch off."""
self._ads_hub.write_by_name( 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,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

@ -1,9 +1,4 @@
""" """Support for non-delivered packages recorded in AfterShip."""
Support for non-delivered packages recorded in AfterShip.
For more details about this platform, please refer to the documentation at
https://www.home-assistant.io/components/sensor.aftership/
"""
from datetime import timedelta from datetime import timedelta
import logging import logging
@ -13,24 +8,44 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
from .const import DOMAIN
REQUIREMENTS = ['pyaftership==0.1.2']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTRIBUTION = 'Information provided by AfterShip' ATTRIBUTION = 'Information provided by AfterShip'
ATTR_TRACKINGS = 'trackings'
BASE = 'https://track.aftership.com/'
CONF_SLUG = 'slug' CONF_SLUG = 'slug'
CONF_TITLE = 'title' CONF_TITLE = 'title'
CONF_TRACKING_NUMBER = 'tracking_number' CONF_TRACKING_NUMBER = 'tracking_number'
DEFAULT_NAME = 'aftership' DEFAULT_NAME = 'aftership'
UPDATE_TOPIC = DOMAIN + '_update'
ICON = 'mdi:package-variant-closed' ICON = 'mdi:package-variant-closed'
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30) 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({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_API_KEY): cv.string,
@ -56,7 +71,40 @@ async def async_setup_platform(
aftership.meta) aftership.meta)
return return
async_add_entities([AfterShipSensor(aftership, name)], True) 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): class AfterShipSensor(Entity):
@ -94,8 +142,18 @@ class AfterShipSensor(Entity):
"""Icon to use in the frontend.""" """Icon to use in the frontend."""
return ICON 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) @Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self): async def async_update(self, **kwargs):
"""Get the latest data from the AfterShip API.""" """Get the latest data from the AfterShip API."""
await self.aftership.get_trackings() await self.aftership.get_trackings()
@ -109,12 +167,29 @@ class AfterShipSensor(Entity):
status_to_ignore = {'delivered'} status_to_ignore = {'delivered'}
status_counts = {} status_counts = {}
trackings = []
not_delivered_count = 0 not_delivered_count = 0
for tracking in self.aftership.trackings['trackings']: for track in self.aftership.trackings['trackings']:
status = tracking['tag'].lower() status = track['tag'].lower()
name = tracking['tracking_number'] name = (
status_counts[status] = status_counts.get(status, 0)+1 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: if status not in status_to_ignore:
not_delivered_count += 1 not_delivered_count += 1
else: else:
@ -122,7 +197,8 @@ class AfterShipSensor(Entity):
self._attributes = { self._attributes = {
ATTR_ATTRIBUTION: ATTRIBUTION, ATTR_ATTRIBUTION: ATTRIBUTION,
**status_counts **status_counts,
ATTR_TRACKINGS: trackings,
} }
self._state = not_delivered_count 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."""
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/
"""
from datetime import timedelta from datetime import timedelta
import logging import logging

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

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

@ -1,9 +1,4 @@
""" """Support for AirVisual air quality sensors."""
Support for AirVisual air quality sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.airvisual/
"""
from logging import getLogger from logging import getLogger
from datetime import timedelta from datetime import timedelta
@ -18,7 +13,6 @@ from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
REQUIREMENTS = ['pyairvisual==3.0.1']
_LOGGER = getLogger(__name__) _LOGGER = getLogger(__name__)
ATTR_CITY = 'city' ATTR_CITY = 'city'

View File

@ -1,9 +1,4 @@
""" """Platform for the Aladdin Connect cover component."""
Platform for the Aladdin Connect cover component.
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/cover.aladdin_connect/
"""
import logging import logging
import voluptuous as vol import voluptuous as vol
@ -14,8 +9,6 @@ from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, STATE_CLOSED,
STATE_OPENING, STATE_CLOSING, STATE_OPEN) STATE_OPENING, STATE_CLOSING, STATE_OPEN)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['aladdin_connect==0.3']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
NOTIFICATION_ID = 'aladdin_notification' NOTIFICATION_ID = 'aladdin_notification'

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."""
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/
"""
from datetime import timedelta from datetime import timedelta
import logging import logging

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

@ -10,8 +10,6 @@ from homeassistant.helpers.discovery import load_platform
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA
REQUIREMENTS = ['alarmdecoder==1.13.2']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = 'alarmdecoder' DOMAIN = 'alarmdecoder'

View File

@ -13,8 +13,6 @@ from . import DATA_AD, SIGNAL_PANEL_MESSAGE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['alarmdecoder']
SERVICE_ALARM_TOGGLE_CHIME = 'alarmdecoder_alarm_toggle_chime' SERVICE_ALARM_TOGGLE_CHIME = 'alarmdecoder_alarm_toggle_chime'
ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({ ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({
vol.Required(ATTR_CODE): cv.string, vol.Required(ATTR_CODE): cv.string,

View File

@ -8,8 +8,6 @@ from . import (
CONF_ZONE_RFID, CONF_ZONE_TYPE, CONF_ZONES, SIGNAL_REL_MESSAGE, CONF_ZONE_RFID, CONF_ZONE_TYPE, CONF_ZONES, SIGNAL_REL_MESSAGE,
SIGNAL_RFX_MESSAGE, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE, ZONE_SCHEMA) SIGNAL_RFX_MESSAGE, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE, ZONE_SCHEMA)
DEPENDENCIES = ['alarmdecoder']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_RF_BIT0 = 'rf_bit0' ATTR_RF_BIT0 = 'rf_bit0'

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

@ -7,8 +7,6 @@ from . import SIGNAL_PANEL_MESSAGE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['alarmdecoder']
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up for AlarmDecoder sensor devices.""" """Set up for AlarmDecoder sensor devices."""

View File

@ -1,9 +1,4 @@
""" """Interfaces with Alarm.com alarm control panels."""
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 logging
import re import re
@ -17,8 +12,6 @@ from homeassistant.const import (
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyalarmdotcom==0.3.2']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Alarm.com' DEFAULT_NAME = 'Alarm.com'

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_FLASH_BRIEFINGS = 'flash_briefings'
CONF_SMART_HOME = 'smart_home' CONF_SMART_HOME = 'smart_home'
DEPENDENCIES = ['http']
ALEXA_ENTITY_SCHEMA = vol.Schema({ ALEXA_ENTITY_SCHEMA = vol.Schema({
vol.Optional(smart_home.CONF_DESCRIPTION): cv.string, vol.Optional(smart_home.CONF_DESCRIPTION): cv.string,
vol.Optional(smart_home.CONF_DISPLAY_CATEGORIES): 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

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

@ -1,9 +1,4 @@
""" """Stock market information from Alpha Vantage."""
Stock market information from Alpha Vantage.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.alpha_vantage/
"""
from datetime import timedelta from datetime import timedelta
import logging import logging
@ -15,8 +10,6 @@ from homeassistant.const import (
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['alpha_vantage==2.1.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_CLOSE = 'close' ATTR_CLOSE = 'close'

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

@ -1,9 +1,4 @@
""" """Support for the Amazon Polly text to speech service."""
Support for the Amazon Polly text to speech service.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/tts.amazon_polly/
"""
import logging import logging
import voluptuous as vol import voluptuous as vol
@ -11,8 +6,6 @@ import voluptuous as vol
from homeassistant.components.tts import PLATFORM_SCHEMA, Provider from homeassistant.components.tts import PLATFORM_SCHEMA, Provider
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['boto3==1.9.16']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_REGION = 'region_name' CONF_REGION = 'region_name'

View File

@ -1,9 +1,19 @@
{ {
"config": { "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": { "step": {
"user": { "user": {
"data": {
"api_key": "Clave API",
"app_key": "Clave de aplicaci\u00f3n"
},
"title": "Completa tu informaci\u00f3n" "title": "Completa tu informaci\u00f3n"
} }
} },
"title": "Ambient PWS"
} }
} }

View File

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

View File

@ -11,7 +11,7 @@
"api_key": "API \ud0a4", "api_key": "API \ud0a4",
"app_key": "Application \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" "title": "Ambient PWS"

View File

@ -1,5 +1,8 @@
{ {
"config": { "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": { "step": {
"user": { "user": {
"data": { "data": {

View File

@ -20,8 +20,6 @@ from .const import (
ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE, ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE,
TYPE_BINARY_SENSOR, TYPE_SENSOR) TYPE_BINARY_SENSOR, TYPE_SENSOR)
REQUIREMENTS = ['aioambient==0.2.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DATA_CONFIG = 'config' DATA_CONFIG = 'config'
@ -329,6 +327,8 @@ class AmbientStation:
"""Define a handler to fire when the websocket is connected.""" """Define a handler to fire when the websocket is connected."""
_LOGGER.info('Connected to websocket') _LOGGER.info('Connected to websocket')
_LOGGER.debug('Watchdog starting') _LOGGER.debug('Watchdog starting')
if self._watchdog_listener:
self._watchdog_listener()
self._watchdog_listener = async_call_later( self._watchdog_listener = async_call_later(
self._hass, DEFAULT_WATCHDOG_SECONDS, _ws_reconnect) self._hass, DEFAULT_WATCHDOG_SECONDS, _ws_reconnect)

View File

@ -12,8 +12,6 @@ from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_BINARY_SENSOR
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ambient_station']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): 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

@ -8,8 +8,6 @@ from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_SENSOR
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ambient_station']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):

View File

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

@ -3,7 +3,7 @@ import asyncio
import logging import logging
from homeassistant.components.camera import ( from homeassistant.components.camera import (
Camera, SUPPORT_STREAM) Camera, SUPPORT_ON_OFF, SUPPORT_STREAM)
from homeassistant.components.ffmpeg import DATA_FFMPEG from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
from homeassistant.helpers.aiohttp_client import ( from homeassistant.helpers.aiohttp_client import (
@ -12,8 +12,6 @@ from homeassistant.helpers.aiohttp_client import (
from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT
DEPENDENCIES = ['amcrest', 'ffmpeg']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -28,8 +26,6 @@ async def async_setup_platform(hass, config, async_add_entities,
async_add_entities([AmcrestCam(hass, amcrest)], True) async_add_entities([AmcrestCam(hass, amcrest)], True)
return True
class AmcrestCam(Camera): class AmcrestCam(Camera):
"""An implementation of an Amcrest IP camera.""" """An implementation of an Amcrest IP camera."""
@ -39,18 +35,23 @@ class AmcrestCam(Camera):
super(AmcrestCam, self).__init__() super(AmcrestCam, self).__init__()
self._name = amcrest.name self._name = amcrest.name
self._camera = amcrest.device self._camera = amcrest.device
self._base_url = self._camera.get_base_url()
self._ffmpeg = hass.data[DATA_FFMPEG] self._ffmpeg = hass.data[DATA_FFMPEG]
self._ffmpeg_arguments = amcrest.ffmpeg_arguments self._ffmpeg_arguments = amcrest.ffmpeg_arguments
self._stream_source = amcrest.stream_source self._stream_source = amcrest.stream_source
self._resolution = amcrest.resolution self._resolution = amcrest.resolution
self._token = self._auth = amcrest.authentication self._token = self._auth = amcrest.authentication
self._is_recording = False
self._model = None
self._snapshot_lock = asyncio.Lock() self._snapshot_lock = asyncio.Lock()
async def async_camera_image(self): async def async_camera_image(self):
"""Return a still image response from the camera.""" """Return a still image response from the camera."""
from amcrest import AmcrestError 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: async with self._snapshot_lock:
try: try:
# Send the request to snap a picture and return raw jpg data # Send the request to snap a picture and return raw jpg data
@ -59,7 +60,8 @@ class AmcrestCam(Camera):
return response.data return response.data
except AmcrestError as error: except AmcrestError as error:
_LOGGER.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 return None
async def handle_async_mjpeg_stream(self, request): async def handle_async_mjpeg_stream(self, request):
@ -94,6 +96,8 @@ class AmcrestCam(Camera):
finally: finally:
await stream.close() await stream.close()
# Entity property overrides
@property @property
def name(self): def name(self):
"""Return the name of this camera.""" """Return the name of this camera."""
@ -102,9 +106,80 @@ class AmcrestCam(Camera):
@property @property
def supported_features(self): def supported_features(self):
"""Return supported features.""" """Return supported features."""
return SUPPORT_STREAM 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 @property
def stream_source(self): def stream_source(self):
"""Return the source of the stream.""" """Return the source of the stream."""
return self._camera.rtsp_url(typeno=self._resolution) 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": []
}

View File

@ -7,8 +7,6 @@ from homeassistant.helpers.entity import Entity
from . import DATA_AMCREST, SENSORS from . import DATA_AMCREST, SENSORS
DEPENDENCIES = ['amcrest']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=10) SCAN_INTERVAL = timedelta(seconds=10)
@ -30,7 +28,6 @@ async def async_setup_platform(
AmcrestSensor(amcrest.name, amcrest.device, sensor_type)) AmcrestSensor(amcrest.name, amcrest.device, sensor_type))
async_add_entities(amcrest_sensors, True) async_add_entities(amcrest_sensors, True)
return True
class AmcrestSensor(Entity): class AmcrestSensor(Entity):
@ -75,19 +72,6 @@ class AmcrestSensor(Entity):
"""Get the latest data and updates the state.""" """Get the latest data and updates the state."""
_LOGGER.debug("Pulling data from %s sensor.", self._name) _LOGGER.debug("Pulling data from %s sensor.", self._name)
try:
version, build_date = self._camera.software_information
self._attrs['Build Date'] = build_date.split('=')[-1]
self._attrs['Version'] = version.split('=')[-1]
except ValueError:
self._attrs['Build Date'] = 'Not Available'
self._attrs['Version'] = 'Not Available'
try:
self._attrs['Serial Number'] = self._camera.serial_number
except ValueError:
self._attrs['Serial Number'] = 'Not Available'
if self._sensor_type == 'motion_detector': if self._sensor_type == 'motion_detector':
self._state = self._camera.is_motion_detected self._state = self._camera.is_motion_detected
self._attrs['Record Mode'] = self._camera.record_mode self._attrs['Record Mode'] = self._camera.record_mode

View File

@ -8,8 +8,6 @@ from . import DATA_AMCREST, SWITCHES
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['amcrest']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):

View File

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

View File

@ -0,0 +1,95 @@
"""Support for Ampio 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
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = 'Data provided by Ampio'
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 Ampio Smog air quality platform."""
from asmog import AmpioSmog
name = config.get(CONF_NAME)
station_id = config[CONF_STATION_ID]
session = async_get_clientsession(hass)
api = AmpioSmogMapData(AmpioSmog(station_id, hass.loop, session))
await api.async_update()
if not api.api.data:
_LOGGER.error("Station %s is not available", station_id)
return
async_add_entities([AmpioSmogQuality(api, station_id, name)], True)
class AmpioSmogQuality(AirQualityEntity):
"""Implementation of an Ampio Smog air quality entity."""
def __init__(self, api, station_id, name):
"""Initialize the air quality entity."""
self._ampio = api
self._station_id = station_id
self._name = name or api.api.name
@property
def name(self):
"""Return the name of the air quality entity."""
return self._name
@property
def unique_id(self):
"""Return unique_name."""
return "ampio_smog_{}".format(self._station_id)
@property
def particulate_matter_2_5(self):
"""Return the particulate matter 2.5 level."""
return self._ampio.api.pm2_5
@property
def particulate_matter_10(self):
"""Return the particulate matter 10 level."""
return self._ampio.api.pm10
@property
def attribution(self):
"""Return the attribution."""
return ATTRIBUTION
async def async_update(self):
"""Get the latest data from the AmpioMap API."""
await self._ampio.async_update()
class AmpioSmogMapData:
"""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 AmpioMap."""
await self.api.get_data()

View File

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

View File

@ -21,8 +21,6 @@ from homeassistant.util.dt import utcnow
from homeassistant.components.mjpeg.camera import ( from homeassistant.components.mjpeg.camera import (
CONF_MJPEG_URL, CONF_STILL_IMAGE_URL) CONF_MJPEG_URL, CONF_STILL_IMAGE_URL)
REQUIREMENTS = ['pydroid-ipcam==0.8']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_AUD_CONNS = 'Audio Connections' ATTR_AUD_CONNS = 'Audio Connections'

View File

@ -3,8 +3,6 @@ from homeassistant.components.binary_sensor import BinarySensorDevice
from . import CONF_HOST, CONF_NAME, DATA_IP_WEBCAM, KEY_MAP, AndroidIPCamEntity from . import CONF_HOST, CONF_NAME, DATA_IP_WEBCAM, KEY_MAP, AndroidIPCamEntity
DEPENDENCIES = ['android_ip_webcam']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):

View File

@ -0,0 +1,10 @@
{
"domain": "android_ip_webcam",
"name": "Android ip webcam",
"documentation": "https://www.home-assistant.io/components/android_ip_webcam",
"requirements": [
"pydroid-ipcam==0.8"
],
"dependencies": [],
"codeowners": []
}

View File

@ -5,8 +5,6 @@ from . import (
CONF_HOST, CONF_NAME, CONF_SENSORS, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP, CONF_HOST, CONF_NAME, CONF_SENSORS, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
AndroidIPCamEntity) AndroidIPCamEntity)
DEPENDENCIES = ['android_ip_webcam']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):

View File

@ -5,8 +5,6 @@ from . import (
CONF_HOST, CONF_NAME, CONF_SWITCHES, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP, CONF_HOST, CONF_NAME, CONF_SWITCHES, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
AndroidIPCamEntity) AndroidIPCamEntity)
DEPENDENCIES = ['android_ip_webcam']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):

View File

@ -1,6 +1 @@
""" """Support for functionality to interact with Android TV/Fire TV devices."""
Support for functionality to interact with Android TV and Fire TV devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.androidtv/
"""

View File

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

View File

@ -1,9 +1,4 @@
""" """Support for functionality to interact with Android TV / Fire TV devices."""
Support for functionality to interact with Android TV and Fire TV devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.androidtv/
"""
import functools import functools
import logging import logging
import voluptuous as vol import voluptuous as vol
@ -18,12 +13,11 @@ from homeassistant.const import (
ATTR_COMMAND, ATTR_ENTITY_ID, CONF_DEVICE_CLASS, CONF_HOST, CONF_NAME, ATTR_COMMAND, ATTR_ENTITY_ID, CONF_DEVICE_CLASS, CONF_HOST, CONF_NAME,
CONF_PORT, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING, CONF_PORT, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING,
STATE_STANDBY) STATE_STANDBY)
from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
ANDROIDTV_DOMAIN = 'androidtv' ANDROIDTV_DOMAIN = 'androidtv'
REQUIREMENTS = ['androidtv==0.0.14']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SUPPORT_ANDROIDTV = SUPPORT_PAUSE | SUPPORT_PLAY | \ SUPPORT_ANDROIDTV = SUPPORT_PAUSE | SUPPORT_PLAY | \
@ -125,7 +119,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
_LOGGER.warning("Could not connect to %s at %s%s", _LOGGER.warning("Could not connect to %s at %s%s",
device_name, host, adb_log) device_name, host, adb_log)
return raise PlatformNotReady
if host in hass.data[ANDROIDTV_DOMAIN]: if host in hass.data[ANDROIDTV_DOMAIN]:
_LOGGER.warning("Platform already setup on %s, skipping", host) _LOGGER.warning("Platform already setup on %s, skipping", host)
@ -298,12 +292,12 @@ class ADBDevice(MediaPlayerDevice):
@adb_decorator() @adb_decorator()
def media_previous_track(self): def media_previous_track(self):
"""Send previous track command (results in rewind).""" """Send previous track command (results in rewind)."""
self.aftv.media_previous() self.aftv.media_previous_track()
@adb_decorator() @adb_decorator()
def media_next_track(self): def media_next_track(self):
"""Send next track command (results in fast-forward).""" """Send next track command (results in fast-forward)."""
self.aftv.media_next() self.aftv.media_next_track()
@adb_decorator() @adb_decorator()
def adb_command(self, cmd): def adb_command(self, cmd):
@ -328,11 +322,10 @@ class AndroidTVDevice(ADBDevice):
turn_off_command) turn_off_command)
self._device = None self._device = None
self._muted = None
self._device_properties = self.aftv.device_properties self._device_properties = self.aftv.device_properties
self._unique_id = 'androidtv-{}-{}'.format( self._is_volume_muted = None
name, self._device_properties['serialno']) self._unique_id = self._device_properties.get('serialno')
self._volume = None self._volume_level = None
@adb_decorator(override_available=True) @adb_decorator(override_available=True)
def update(self): def update(self):
@ -349,16 +342,16 @@ class AndroidTVDevice(ADBDevice):
if not self._available: if not self._available:
return return
# Get the `state`, `current_app`, and `running_apps`. # Get the updated state and attributes.
state, self._current_app, self._device, self._muted, self._volume = \ state, self._current_app, self._device, self._is_volume_muted, \
self.aftv.update() self._volume_level = self.aftv.update()
self._state = ANDROIDTV_STATES[state] self._state = ANDROIDTV_STATES[state]
@property @property
def is_volume_muted(self): def is_volume_muted(self):
"""Boolean if volume is currently muted.""" """Boolean if volume is currently muted."""
return self._muted return self._is_volume_muted
@property @property
def source(self): def source(self):
@ -378,7 +371,7 @@ class AndroidTVDevice(ADBDevice):
@property @property
def volume_level(self): def volume_level(self):
"""Return the volume level.""" """Return the volume level."""
return self._volume return self._volume_level
@adb_decorator() @adb_decorator()
def media_stop(self): def media_stop(self):
@ -393,12 +386,12 @@ class AndroidTVDevice(ADBDevice):
@adb_decorator() @adb_decorator()
def volume_down(self): def volume_down(self):
"""Send volume down command.""" """Send volume down command."""
self.aftv.volume_down() self._volume_level = self.aftv.volume_down(self._volume_level)
@adb_decorator() @adb_decorator()
def volume_up(self): def volume_up(self):
"""Send volume up command.""" """Send volume up command."""
self.aftv.volume_up() self._volume_level = self.aftv.volume_up(self._volume_level)
class FireTVDevice(ADBDevice): class FireTVDevice(ADBDevice):

View File

@ -0,0 +1,10 @@
{
"domain": "anel_pwrctrl",
"name": "Anel pwrctrl",
"documentation": "https://www.home-assistant.io/components/anel_pwrctrl",
"requirements": [
"anel_pwrctrl-homeassistant==0.0.1.dev2"
],
"dependencies": [],
"codeowners": []
}

View File

@ -1,9 +1,4 @@
""" """Support for ANEL PwrCtrl switches."""
Support for ANEL PwrCtrl switches.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/switch.pwrctrl/
"""
import logging import logging
import socket import socket
from datetime import timedelta from datetime import timedelta
@ -15,8 +10,6 @@ from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
from homeassistant.const import (CONF_HOST, CONF_PASSWORD, CONF_USERNAME) from homeassistant.const import (CONF_HOST, CONF_PASSWORD, CONF_USERNAME)
from homeassistant.util import Throttle from homeassistant.util import Throttle
REQUIREMENTS = ['anel_pwrctrl-homeassistant==0.0.1.dev2']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_PORT_RECV = 'port_recv' CONF_PORT_RECV = 'port_recv'

View File

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

View File

@ -1,9 +1,4 @@
""" """Support for Anthem Network Receivers and Processors."""
Support for Anthem Network Receivers and Processors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.anthemav/
"""
import logging import logging
import voluptuous as vol import voluptuous as vol
@ -18,8 +13,6 @@ from homeassistant.const import (
STATE_ON) STATE_ON)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['anthemav==1.1.10']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = 'anthemav' DOMAIN = 'anthemav'

View File

@ -8,8 +8,6 @@ from homeassistant.const import (CONF_HOST, CONF_PORT)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle from homeassistant.util import Throttle
REQUIREMENTS = ['apcaccess==0.0.13']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_TYPE = 'type' CONF_TYPE = 'type'

View File

@ -8,8 +8,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.components import apcupsd from homeassistant.components import apcupsd
DEFAULT_NAME = 'UPS Online Status' DEFAULT_NAME = 'UPS Online Status'
DEPENDENCIES = [apcupsd.DOMAIN]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}) })

View File

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

View File

@ -11,8 +11,6 @@ from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = [apcupsd.DOMAIN]
SENSOR_PREFIX = 'UPS ' SENSOR_PREFIX = 'UPS '
SENSOR_TYPES = { SENSOR_TYPES = {
'alarmdel': ['Alarm Delay', '', 'mdi:alarm'], 'alarmdel': ['Alarm Delay', '', 'mdi:alarm'],

View File

@ -33,8 +33,6 @@ ATTR_REQUIRES_API_PASSWORD = 'requires_api_password'
ATTR_VERSION = 'version' ATTR_VERSION = 'version'
DOMAIN = 'api' DOMAIN = 'api'
DEPENDENCIES = ['http']
STREAM_PING_PAYLOAD = 'ping' STREAM_PING_PAYLOAD = 'ping'
STREAM_PING_INTERVAL = 50 # seconds STREAM_PING_INTERVAL = 50 # seconds

View File

@ -0,0 +1,12 @@
{
"domain": "api",
"name": "Home Assistant API",
"documentation": "https://www.home-assistant.io/components/api",
"requirements": [],
"dependencies": [
"http"
],
"codeowners": [
"@home-assistant/core"
]
}

View File

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

View File

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

View File

@ -1,9 +1,4 @@
""" """APNS Notification platform."""
APNS Notification platform.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.apns/
"""
import logging import logging
import os import os
@ -18,8 +13,6 @@ from homeassistant.helpers.event import track_state_change
from homeassistant.components.notify import ( from homeassistant.components.notify import (
ATTR_DATA, ATTR_TARGET, DOMAIN, PLATFORM_SCHEMA, BaseNotificationService) ATTR_DATA, ATTR_TARGET, DOMAIN, PLATFORM_SCHEMA, BaseNotificationService)
REQUIREMENTS = ['apns2==0.3.0']
APNS_DEVICES = 'apns.yaml' APNS_DEVICES = 'apns.yaml'
CONF_CERTFILE = 'cert_file' CONF_CERTFILE = 'cert_file'
CONF_TOPIC = 'topic' CONF_TOPIC = 'topic'

View File

@ -11,8 +11,6 @@ from homeassistant.helpers import discovery
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyatv==0.3.12']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = 'apple_tv' DOMAIN = 'apple_tv'

View File

@ -0,0 +1,10 @@
{
"domain": "apple_tv",
"name": "Apple tv",
"documentation": "https://www.home-assistant.io/components/apple_tv",
"requirements": [
"pyatv==0.3.12"
],
"dependencies": ["configurator"],
"codeowners": []
}

View File

@ -14,8 +14,6 @@ import homeassistant.util.dt as dt_util
from . import ATTR_ATV, ATTR_POWER, DATA_APPLE_TV, DATA_ENTITIES from . import ATTR_ATV, ATTR_POWER, DATA_APPLE_TV, DATA_ENTITIES
DEPENDENCIES = ['apple_tv']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SUPPORT_APPLE_TV = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PLAY_MEDIA | \ SUPPORT_APPLE_TV = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PLAY_MEDIA | \

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