mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
commit
8ae2ce2299
@ -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.test >>pip install -q --progress-bar off -r requirements_test.txt -c homeassistant/package_constraints.txt<</ parameters.test>>
|
||||
<<# parameters.test_all >>pip install -q --progress-bar off -r requirements_test_all.txt -c homeassistant/package_constraints.txt<</ parameters.test_all>>
|
||||
no_output_timeout: 15m
|
||||
- save_cache:
|
||||
paths:
|
||||
- ./venv
|
||||
@ -99,6 +100,13 @@ jobs:
|
||||
mypy $TYPING_FILES
|
||||
|
||||
- install
|
||||
|
||||
- run:
|
||||
name: validate manifests
|
||||
command: |
|
||||
. venv/bin/activate
|
||||
python -m script.hassfest validate
|
||||
|
||||
- run:
|
||||
name: run gen_requirements_all
|
||||
command: |
|
||||
@ -139,6 +147,7 @@ jobs:
|
||||
. venv/bin/activate
|
||||
PYFILES=$(circleci tests glob "homeassistant/**/*.py" | circleci tests split)
|
||||
pylint ${PYFILES}
|
||||
no_output_timeout: 15m
|
||||
|
||||
pre-test:
|
||||
parameters:
|
||||
@ -173,13 +182,14 @@ jobs:
|
||||
- install
|
||||
|
||||
- run:
|
||||
name: run tests
|
||||
name: run tests with code coverage
|
||||
command: |
|
||||
. venv/bin/activate
|
||||
CC_SWITCH="--cov --cov-report="
|
||||
TESTFILES=$(circleci tests glob "tests/**/test_*.py" | circleci tests split --split-by=timings)
|
||||
if [ -z "$CODE_COVERAGE" ]; then CC_SWITCH=""; else CC_SWITCH="--cov --cov-report html:htmlcov"; fi
|
||||
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}
|
||||
pytest --timeout=9 --durations=10 --junitxml=test-reports/homeassistant/results.xml -qq -o junit_family=xunit2 -o junit_suite_name=homeassistant -o console_output_style=count -p no:sugar $CC_SWITCH -- ${TESTFILES}
|
||||
script/check_dirty
|
||||
codecov
|
||||
|
||||
- store_test_results:
|
||||
path: test-reports
|
||||
|
15
.codecov.yml
Normal file
15
.codecov.yml
Normal 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
|
40
.coveragerc
40
.coveragerc
@ -21,14 +21,15 @@ omit =
|
||||
homeassistant/components/alarmdecoder/*
|
||||
homeassistant/components/alarmdotcom/alarm_control_panel.py
|
||||
homeassistant/components/alpha_vantage/sensor.py
|
||||
homeassistant/components/amazon_polly/tts.py
|
||||
homeassistant/components/ambient_station/*
|
||||
homeassistant/components/amcrest/*
|
||||
homeassistant/components/ampio/*
|
||||
homeassistant/components/android_ip_webcam/*
|
||||
homeassistant/components/androidtv/*
|
||||
homeassistant/components/anel_pwrctrl/switch.py
|
||||
homeassistant/components/anthemav/media_player.py
|
||||
homeassistant/components/apcupsd/*
|
||||
homeassistant/components/apiai/*
|
||||
homeassistant/components/apple_tv/*
|
||||
homeassistant/components/aqualogic/*
|
||||
homeassistant/components/aquostv/media_player.py
|
||||
@ -45,9 +46,7 @@ omit =
|
||||
homeassistant/components/august/*
|
||||
homeassistant/components/automatic/device_tracker.py
|
||||
homeassistant/components/avion/light.py
|
||||
homeassistant/components/aws_lambda/notify.py
|
||||
homeassistant/components/aws_sns/notify.py
|
||||
homeassistant/components/aws_sqs/notify.py
|
||||
homeassistant/components/baidu/tts.py
|
||||
homeassistant/components/bbb_gpio/*
|
||||
homeassistant/components/bbox/device_tracker.py
|
||||
homeassistant/components/bbox/sensor.py
|
||||
@ -64,6 +63,7 @@ omit =
|
||||
homeassistant/components/bme280/sensor.py
|
||||
homeassistant/components/bme680/sensor.py
|
||||
homeassistant/components/bmw_connected_drive/*
|
||||
homeassistant/components/bom/camera.py
|
||||
homeassistant/components/bom/sensor.py
|
||||
homeassistant/components/bom/weather.py
|
||||
homeassistant/components/braviatv/media_player.py
|
||||
@ -84,6 +84,7 @@ omit =
|
||||
homeassistant/components/channels/media_player.py
|
||||
homeassistant/components/cisco_ios/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/citybikes/sensor.py
|
||||
homeassistant/components/clementine/media_player.py
|
||||
@ -92,6 +93,7 @@ omit =
|
||||
homeassistant/components/clicksend_tts/notify.py
|
||||
homeassistant/components/cloudflare/*
|
||||
homeassistant/components/cmus/media_player.py
|
||||
homeassistant/components/co2signal/*
|
||||
homeassistant/components/coinbase/*
|
||||
homeassistant/components/comed_hourly_pricing/sensor.py
|
||||
homeassistant/components/comfoconnect/*
|
||||
@ -125,7 +127,6 @@ omit =
|
||||
homeassistant/components/dlink/switch.py
|
||||
homeassistant/components/dlna_dmr/media_player.py
|
||||
homeassistant/components/dnsip/sensor.py
|
||||
homeassistant/components/domain_expiry/sensor.py
|
||||
homeassistant/components/dominos/*
|
||||
homeassistant/components/doorbird/*
|
||||
homeassistant/components/dovado/*
|
||||
@ -161,9 +162,12 @@ omit =
|
||||
homeassistant/components/envisalink/*
|
||||
homeassistant/components/ephember/climate.py
|
||||
homeassistant/components/epson/media_player.py
|
||||
homeassistant/components/epsonworkforce/sensor.py
|
||||
homeassistant/components/eq3btsmart/climate.py
|
||||
homeassistant/components/esphome/__init__.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/fan.py
|
||||
homeassistant/components/esphome/light.py
|
||||
@ -203,6 +207,7 @@ omit =
|
||||
homeassistant/components/futurenow/light.py
|
||||
homeassistant/components/garadget/cover.py
|
||||
homeassistant/components/gc100/*
|
||||
homeassistant/components/geniushub/*
|
||||
homeassistant/components/gearbest/sensor.py
|
||||
homeassistant/components/geizhals/sensor.py
|
||||
homeassistant/components/github/sensor.py
|
||||
@ -266,13 +271,10 @@ omit =
|
||||
homeassistant/components/ifttt/*
|
||||
homeassistant/components/iglo/light.py
|
||||
homeassistant/components/ihc/*
|
||||
homeassistant/components/iliad_italy/sensor.py
|
||||
homeassistant/components/imap/sensor.py
|
||||
homeassistant/components/imap_email_content/sensor.py
|
||||
homeassistant/components/influxdb/sensor.py
|
||||
homeassistant/components/insteon/*
|
||||
homeassistant/components/insteon_local/*
|
||||
homeassistant/components/insteon_plm/*
|
||||
homeassistant/components/ios/*
|
||||
homeassistant/components/iota/*
|
||||
homeassistant/components/iperf3/*
|
||||
@ -318,7 +320,10 @@ omit =
|
||||
homeassistant/components/liveboxplaytv/media_player.py
|
||||
homeassistant/components/llamalab_automate/notify.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/loopenergy/sensor.py
|
||||
homeassistant/components/luci/device_tracker.py
|
||||
@ -341,6 +346,7 @@ omit =
|
||||
homeassistant/components/meteo_france/*
|
||||
homeassistant/components/metoffice/sensor.py
|
||||
homeassistant/components/metoffice/weather.py
|
||||
homeassistant/components/microsoft/tts.py
|
||||
homeassistant/components/miflora/sensor.py
|
||||
homeassistant/components/mikrotik/device_tracker.py
|
||||
homeassistant/components/mill/climate.py
|
||||
@ -363,8 +369,8 @@ omit =
|
||||
homeassistant/components/mystrom/binary_sensor.py
|
||||
homeassistant/components/mystrom/light.py
|
||||
homeassistant/components/mystrom/switch.py
|
||||
homeassistant/components/n26/*
|
||||
homeassistant/components/nad/media_player.py
|
||||
homeassistant/components/nadtcp/media_player.py
|
||||
homeassistant/components/nanoleaf/light.py
|
||||
homeassistant/components/neato/*
|
||||
homeassistant/components/nederlandse_spoorwegen/sensor.py
|
||||
@ -373,7 +379,6 @@ omit =
|
||||
homeassistant/components/netatmo/*
|
||||
homeassistant/components/netatmo_public/sensor.py
|
||||
homeassistant/components/netdata/sensor.py
|
||||
homeassistant/components/netdata_public/sensor.py
|
||||
homeassistant/components/netgear/device_tracker.py
|
||||
homeassistant/components/netgear_lte/*
|
||||
homeassistant/components/netio/switch.py
|
||||
@ -394,6 +399,7 @@ omit =
|
||||
homeassistant/components/nzbget/sensor.py
|
||||
homeassistant/components/octoprint/*
|
||||
homeassistant/components/oem/climate.py
|
||||
homeassistant/components/oasa_telematics/sensor.py
|
||||
homeassistant/components/ohmconnect/sensor.py
|
||||
homeassistant/components/onewire/sensor.py
|
||||
homeassistant/components/onkyo/media_player.py
|
||||
@ -422,6 +428,7 @@ omit =
|
||||
homeassistant/components/pencom/switch.py
|
||||
homeassistant/components/philips_js/media_player.py
|
||||
homeassistant/components/pi_hole/sensor.py
|
||||
homeassistant/components/picotts/tts.py
|
||||
homeassistant/components/piglow/light.py
|
||||
homeassistant/components/pilight/*
|
||||
homeassistant/components/ping/binary_sensor.py
|
||||
@ -533,6 +540,7 @@ omit =
|
||||
homeassistant/components/sochain/sensor.py
|
||||
homeassistant/components/socialblade/sensor.py
|
||||
homeassistant/components/solaredge/sensor.py
|
||||
homeassistant/components/somfy_mylink/*
|
||||
homeassistant/components/sonarr/sensor.py
|
||||
homeassistant/components/songpal/media_player.py
|
||||
homeassistant/components/sonos/*
|
||||
@ -546,6 +554,7 @@ omit =
|
||||
homeassistant/components/srp_energy/sensor.py
|
||||
homeassistant/components/starlingbank/sensor.py
|
||||
homeassistant/components/steam_online/sensor.py
|
||||
homeassistant/components/stiebel_eltron/*
|
||||
homeassistant/components/stride/notify.py
|
||||
homeassistant/components/supervisord/sensor.py
|
||||
homeassistant/components/swiss_hydrological_data/sensor.py
|
||||
@ -573,7 +582,6 @@ omit =
|
||||
homeassistant/components/tellduslive/*
|
||||
homeassistant/components/tellstick/*
|
||||
homeassistant/components/telnet/switch.py
|
||||
homeassistant/components/telstra/notify.py
|
||||
homeassistant/components/temper/sensor.py
|
||||
homeassistant/components/tensorflow/image_processing.py
|
||||
homeassistant/components/tesla/*
|
||||
@ -605,10 +613,6 @@ omit =
|
||||
homeassistant/components/trafikverket_weatherstation/sensor.py
|
||||
homeassistant/components/transmission/*
|
||||
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/twilio_call/notify.py
|
||||
homeassistant/components/twilio_sms/notify.py
|
||||
@ -650,6 +654,7 @@ omit =
|
||||
homeassistant/components/wirelesstag/*
|
||||
homeassistant/components/worldtidesinfo/sensor.py
|
||||
homeassistant/components/worxlandroid/sensor.py
|
||||
homeassistant/components/wunderlist/*
|
||||
homeassistant/components/x10/light.py
|
||||
homeassistant/components/xbox_live/sensor.py
|
||||
homeassistant/components/xeoma/camera.py
|
||||
@ -663,7 +668,7 @@ omit =
|
||||
homeassistant/components/yale_smart_alarm/alarm_control_panel.py
|
||||
homeassistant/components/yamaha/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/yi/camera.py
|
||||
homeassistant/components/zabbix/*
|
||||
@ -688,6 +693,7 @@ omit =
|
||||
homeassistant/components/zigbee/*
|
||||
homeassistant/components/ziggo_mediabox_xl/media_player.py
|
||||
homeassistant/components/zoneminder/*
|
||||
homeassistant/components/supla/*
|
||||
homeassistant/components/zwave/util.py
|
||||
|
||||
[report]
|
||||
|
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -23,7 +23,8 @@ If user exposed functionality or configuration variables are added/changed:
|
||||
- [ ] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io)
|
||||
|
||||
If the code communicates with devices, web services, or third-party tools:
|
||||
- [ ] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]).
|
||||
- [ ] [_The manifest file_][manifest-docs] has all fields filled out correctly ([example][ex-manifest]).
|
||||
- [ ] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]).
|
||||
- [ ] New dependencies are only imported inside functions that use them ([example][ex-import]).
|
||||
- [ ] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
|
||||
- [ ] New files were added to `.coveragerc`.
|
||||
@ -31,5 +32,7 @@ If the code communicates with devices, web services, or third-party tools:
|
||||
If the code does not interact with devices:
|
||||
- [ ] Tests have been added to verify that the new code works.
|
||||
|
||||
[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14
|
||||
[ex-manifest]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json
|
||||
[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json#L5
|
||||
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
|
||||
[manifest-docs]: https://developers.home-assistant.io/docs/en/development_checklist.html#_the-manifest-file_
|
||||
|
45
.github/main.workflow
vendored
45
.github/main.workflow
vendored
@ -1,41 +1,14 @@
|
||||
workflow "Python 3.7 - tox" {
|
||||
resolves = ["Python 3.7 - tests"]
|
||||
on = "push"
|
||||
workflow "Mention CODEOWNERS of integrations when integration label is added to an issue" {
|
||||
on = "issues"
|
||||
resolves = "codeowners-mention"
|
||||
}
|
||||
|
||||
action "Python 3.7 - tests" {
|
||||
uses = "home-assistant/actions/py37-tox@master"
|
||||
args = "-e py37"
|
||||
workflow "Mention CODEOWNERS of integrations when integration label is added to an PRs" {
|
||||
on = "pull_request"
|
||||
resolves = "codeowners-mention"
|
||||
}
|
||||
|
||||
workflow "Python 3.6 - tox" {
|
||||
resolves = ["Python 3.6 - tests"]
|
||||
on = "push"
|
||||
}
|
||||
|
||||
action "Python 3.6 - tests" {
|
||||
uses = "home-assistant/actions/py36-tox@master"
|
||||
args = "-e py36"
|
||||
}
|
||||
|
||||
workflow "Python 3.5 - tox" {
|
||||
resolves = ["Pyton 3.5 - typing"]
|
||||
on = "push"
|
||||
}
|
||||
|
||||
action "Python 3.5 - tests" {
|
||||
uses = "home-assistant/actions/py35-tox@master"
|
||||
args = "-e py35"
|
||||
}
|
||||
|
||||
action "Python 3.5 - lints" {
|
||||
uses = "home-assistant/actions/py35-tox@master"
|
||||
needs = ["Python 3.5 - tests"]
|
||||
args = "-e lint"
|
||||
}
|
||||
|
||||
action "Pyton 3.5 - typing" {
|
||||
uses = "home-assistant/actions/py35-tox@master"
|
||||
args = "-e typing"
|
||||
needs = ["Python 3.5 - lints"]
|
||||
action "codeowners-mention" {
|
||||
uses = "home-assistant/codeowners-mention@master"
|
||||
secrets = ["GITHUB_TOKEN"]
|
||||
}
|
||||
|
55
.travis.yml
55
.travis.yml
@ -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
|
367
CODEOWNERS
367
CODEOWNERS
@ -1,3 +1,4 @@
|
||||
# This file is generated by script/manifest/codeowners.py
|
||||
# People marked here will be automatically requested for a review
|
||||
# when the code that they own is touched.
|
||||
# https://github.com/blog/2392-introducing-code-owners
|
||||
@ -7,285 +8,255 @@ setup.py @home-assistant/core
|
||||
homeassistant/*.py @home-assistant/core
|
||||
homeassistant/helpers/* @home-assistant/core
|
||||
homeassistant/util/* @home-assistant/core
|
||||
homeassistant/components/api/* @home-assistant/core
|
||||
homeassistant/components/auth/* @home-assistant/core
|
||||
homeassistant/components/automation/* @home-assistant/core
|
||||
homeassistant/components/cloud/* @home-assistant/core
|
||||
homeassistant/components/config/* @home-assistant/core
|
||||
homeassistant/components/configurator/* @home-assistant/core
|
||||
homeassistant/components/conversation/* @home-assistant/core
|
||||
homeassistant/components/frontend/* @home-assistant/core
|
||||
homeassistant/components/group/* @home-assistant/core
|
||||
homeassistant/components/history/* @home-assistant/core
|
||||
homeassistant/components/http/* @home-assistant/core
|
||||
homeassistant/components/input_*/* @home-assistant/core
|
||||
homeassistant/components/introduction/* @home-assistant/core
|
||||
homeassistant/components/logger/* @home-assistant/core
|
||||
homeassistant/components/lovelace/* @home-assistant/core
|
||||
homeassistant/components/mqtt/* @home-assistant/core
|
||||
homeassistant/components/panel_custom/* @home-assistant/core
|
||||
homeassistant/components/panel_iframe/* @home-assistant/core
|
||||
homeassistant/components/onboarding/* @home-assistant/core
|
||||
homeassistant/components/persistent_notification/* @home-assistant/core
|
||||
homeassistant/components/scene/__init__.py @home-assistant/core
|
||||
homeassistant/components/scene/homeassistant.py @home-assistant/core
|
||||
homeassistant/components/script/* @home-assistant/core
|
||||
homeassistant/components/shell_command/* @home-assistant/core
|
||||
homeassistant/components/sun/* @home-assistant/core
|
||||
homeassistant/components/updater/* @home-assistant/core
|
||||
homeassistant/components/weblink/* @home-assistant/core
|
||||
homeassistant/components/websocket_api/* @home-assistant/core
|
||||
homeassistant/components/zone/* @home-assistant/core
|
||||
|
||||
# Home Assistant Developer Teams
|
||||
# Virtualization
|
||||
Dockerfile @home-assistant/docker
|
||||
virtualization/Docker/* @home-assistant/docker
|
||||
|
||||
homeassistant/components/zwave/* @home-assistant/z-wave
|
||||
homeassistant/components/*/zwave.py @home-assistant/z-wave
|
||||
# Other code
|
||||
homeassistant/scripts/check_config.py @kellerza
|
||||
|
||||
homeassistant/components/hassio/* @home-assistant/hassio
|
||||
|
||||
# Individual platforms
|
||||
homeassistant/components/notify/aws_lambda.py @robbiet480
|
||||
homeassistant/components/notify/aws_sns.py @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
|
||||
# Integrations
|
||||
homeassistant/components/airvisual/* @bachya
|
||||
homeassistant/components/alarm_control_panel/* @colinodell
|
||||
homeassistant/components/alpha_vantage/* @fabaff
|
||||
homeassistant/components/amazon_polly/* @robbiet480
|
||||
homeassistant/components/ambient_station/* @bachya
|
||||
homeassistant/components/api/* @home-assistant/core
|
||||
homeassistant/components/arduino/* @fabaff
|
||||
homeassistant/components/arest/* @fabaff
|
||||
homeassistant/components/asuswrt/device_tracker.py @kennedyshead
|
||||
homeassistant/components/automatic/device_tracker.py @armills
|
||||
homeassistant/components/asuswrt/* @kennedyshead
|
||||
homeassistant/components/auth/* @home-assistant/core
|
||||
homeassistant/components/automatic/* @armills
|
||||
homeassistant/components/automation/* @home-assistant/core
|
||||
homeassistant/components/aws/* @awarecan @robbiet480
|
||||
homeassistant/components/axis/* @kane610
|
||||
|
||||
# B
|
||||
homeassistant/components/bitcoin/sensor.py @fabaff
|
||||
homeassistant/components/bitcoin/* @fabaff
|
||||
homeassistant/components/blink/* @fronzbot
|
||||
homeassistant/components/bmw_connected_drive/* @ChristianKuehnel
|
||||
homeassistant/components/braviatv/media_player.py @robbiet480
|
||||
homeassistant/components/braviatv/* @robbiet480
|
||||
homeassistant/components/broadlink/* @danielhiversen
|
||||
homeassistant/components/brunt/cover.py @eavanvalkenburg
|
||||
homeassistant/components/bt_smarthub/device_tracker.py @jxwolstenholme
|
||||
|
||||
# C
|
||||
homeassistant/components/brunt/* @eavanvalkenburg
|
||||
homeassistant/components/bt_smarthub/* @jxwolstenholme
|
||||
homeassistant/components/cisco_ios/* @fbradyirl
|
||||
homeassistant/components/cisco_mobility_express/* @fbradyirl
|
||||
homeassistant/components/cisco_webex_teams/* @fbradyirl
|
||||
homeassistant/components/ciscospark/* @fbradyirl
|
||||
homeassistant/components/cloud/* @home-assistant/core
|
||||
homeassistant/components/cloudflare/* @ludeeus
|
||||
homeassistant/components/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/cover/group.py @cdce8p
|
||||
homeassistant/components/cpuspeed/sensor.py @fabaff
|
||||
homeassistant/components/cups/sensor.py @fabaff
|
||||
|
||||
# D
|
||||
homeassistant/components/cover/* @home-assistant/core
|
||||
homeassistant/components/cpuspeed/* @fabaff
|
||||
homeassistant/components/cups/* @fabaff
|
||||
homeassistant/components/daikin/* @fredrike @rofrantz
|
||||
homeassistant/components/darksky/* @fabaff
|
||||
homeassistant/components/discogs/sensor.py @thibmaek
|
||||
homeassistant/components/deconz/* @kane610
|
||||
homeassistant/components/demo/weather.py @fabaff
|
||||
homeassistant/components/demo/* @home-assistant/core
|
||||
homeassistant/components/digital_ocean/* @fabaff
|
||||
homeassistant/components/discogs/* @thibmaek
|
||||
homeassistant/components/doorbird/* @oblogic7
|
||||
homeassistant/components/dweet/* @fabaff
|
||||
|
||||
# E
|
||||
homeassistant/components/ecovacs/* @OverloadUT
|
||||
homeassistant/components/edp_redy/* @abmantis
|
||||
homeassistant/components/eight_sleep/* @mezz64
|
||||
homeassistant/components/egardia/* @jeroenterheerdt
|
||||
homeassistant/components/emby/media_player.py @mezz64
|
||||
homeassistant/components/ephember/climate.py @ttroy50
|
||||
homeassistant/components/eq3btsmart/climate.py @rytilahti
|
||||
homeassistant/components/eight_sleep/* @mezz64
|
||||
homeassistant/components/emby/* @mezz64
|
||||
homeassistant/components/enigma2/* @fbradyirl
|
||||
homeassistant/components/ephember/* @ttroy50
|
||||
homeassistant/components/epsonworkforce/* @ThaStealth
|
||||
homeassistant/components/eq3btsmart/* @rytilahti
|
||||
homeassistant/components/esphome/* @OttoWinter
|
||||
|
||||
# F
|
||||
homeassistant/components/file/sensor.py @fabaff
|
||||
homeassistant/components/filter/sensor.py @dgomes
|
||||
homeassistant/components/fitbit/sensor.py @robbiet480
|
||||
homeassistant/components/fixer/sensor.py @fabaff
|
||||
homeassistant/components/flunearyou/sensor.py @bachya
|
||||
homeassistant/components/file/* @fabaff
|
||||
homeassistant/components/filter/* @dgomes
|
||||
homeassistant/components/fitbit/* @robbiet480
|
||||
homeassistant/components/fixer/* @fabaff
|
||||
homeassistant/components/flock/* @fabaff
|
||||
homeassistant/components/flunearyou/* @bachya
|
||||
homeassistant/components/foursquare/* @robbiet480
|
||||
homeassistant/components/freebox/* @snoof85
|
||||
|
||||
# G
|
||||
homeassistant/components/gearbest/sensor.py @HerrHofrat
|
||||
homeassistant/components/gitter/sensor.py @fabaff
|
||||
homeassistant/components/glances/sensor.py @fabaff
|
||||
homeassistant/components/google_travel_time/sensor.py @robbiet480
|
||||
homeassistant/components/frontend/* @home-assistant/core
|
||||
homeassistant/components/gearbest/* @HerrHofrat
|
||||
homeassistant/components/gitter/* @fabaff
|
||||
homeassistant/components/glances/* @fabaff
|
||||
homeassistant/components/gntp/* @robbiet480
|
||||
homeassistant/components/google_translate/* @awarecan
|
||||
homeassistant/components/google_travel_time/* @robbiet480
|
||||
homeassistant/components/googlehome/* @ludeeus
|
||||
homeassistant/components/gpsd/sensor.py @fabaff
|
||||
homeassistant/components/gtfs/sensor.py @robbiet480
|
||||
|
||||
# H
|
||||
homeassistant/components/gpsd/* @fabaff
|
||||
homeassistant/components/group/* @home-assistant/core
|
||||
homeassistant/components/gtfs/* @robbiet480
|
||||
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/hive/* @Rendili @KJonline
|
||||
homeassistant/components/homeassistant/* @home-assistant/core
|
||||
homeassistant/components/homekit/* @cdce8p
|
||||
homeassistant/components/homematic/* @pvizeli @danielperna84
|
||||
homeassistant/components/html5/* @robbiet480
|
||||
homeassistant/components/http/* @home-assistant/core
|
||||
homeassistant/components/huawei_lte/* @scop
|
||||
homeassistant/components/huawei_router/device_tracker.py @abmantis
|
||||
|
||||
# I
|
||||
homeassistant/components/huawei_router/* @abmantis
|
||||
homeassistant/components/hue/* @balloob
|
||||
homeassistant/components/ign_sismologia/* @exxamalte
|
||||
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/ipma/* @dgomes
|
||||
homeassistant/components/irish_rail_transport/sensor.py @ttroy50
|
||||
|
||||
# J
|
||||
homeassistant/components/jewish_calendar/sensor.py @tsvi
|
||||
|
||||
# K
|
||||
homeassistant/components/irish_rail_transport/* @ttroy50
|
||||
homeassistant/components/jewish_calendar/* @tsvi
|
||||
homeassistant/components/knx/* @Julius2342
|
||||
homeassistant/components/kodi/media_player.py @armills
|
||||
homeassistant/components/kodi/* @armills
|
||||
homeassistant/components/konnected/* @heythisisnate
|
||||
|
||||
# L
|
||||
homeassistant/components/lametric/notify.py @robbiet480
|
||||
homeassistant/components/launch_library/sensor.py @ludeeus
|
||||
homeassistant/components/lametric/* @robbiet480
|
||||
homeassistant/components/launch_library/* @ludeeus
|
||||
homeassistant/components/lifx/* @amelchio
|
||||
homeassistant/components/lifx_cloud/scene.py @amelchio
|
||||
homeassistant/components/lifx_legacy/light.py @amelchio
|
||||
homeassistant/components/linux_battery/sensor.py @fabaff
|
||||
homeassistant/components/liveboxplaytv/media_player.py @pschmitt
|
||||
homeassistant/components/lifx_cloud/* @amelchio
|
||||
homeassistant/components/lifx_legacy/* @amelchio
|
||||
homeassistant/components/linux_battery/* @fabaff
|
||||
homeassistant/components/liveboxplaytv/* @pschmitt
|
||||
homeassistant/components/logger/* @home-assistant/core
|
||||
homeassistant/components/logi_circle/* @evanjd
|
||||
homeassistant/components/lovelace/* @home-assistant/core
|
||||
homeassistant/components/luci/* @fbradyirl
|
||||
homeassistant/components/luftdaten/* @fabaff
|
||||
|
||||
# M
|
||||
homeassistant/components/mastodon/* @fabaff
|
||||
homeassistant/components/matrix/* @tinloaf
|
||||
homeassistant/components/mediaroom/media_player.py @dgomes
|
||||
homeassistant/components/mediaroom/* @dgomes
|
||||
homeassistant/components/melissa/* @kennedyshead
|
||||
homeassistant/components/met/weather.py @danielhiversen
|
||||
homeassistant/components/miflora/sensor.py @danielhiversen @ChristianKuehnel
|
||||
homeassistant/components/mill/climate.py @danielhiversen
|
||||
homeassistant/components/min_max/sensor.py @fabaff
|
||||
homeassistant/components/met/* @danielhiversen
|
||||
homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel
|
||||
homeassistant/components/mill/* @danielhiversen
|
||||
homeassistant/components/min_max/* @fabaff
|
||||
homeassistant/components/mobile_app/* @robbiet480
|
||||
homeassistant/components/monoprice/media_player.py @etsinko
|
||||
homeassistant/components/moon/sensor.py @fabaff
|
||||
homeassistant/components/mpd/media_player.py @fabaff
|
||||
homeassistant/components/monoprice/* @etsinko
|
||||
homeassistant/components/moon/* @fabaff
|
||||
homeassistant/components/mpd/* @fabaff
|
||||
homeassistant/components/mqtt/* @home-assistant/core
|
||||
homeassistant/components/mystrom/* @fabaff
|
||||
|
||||
# N
|
||||
homeassistant/components/nello/lock.py @pschmitt
|
||||
homeassistant/components/nello/* @pschmitt
|
||||
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/nmbs/sensor.py @thibmaek
|
||||
homeassistant/components/nmbs/* @thibmaek
|
||||
homeassistant/components/no_ip/* @fabaff
|
||||
homeassistant/components/nuki/lock.py @pschmitt
|
||||
homeassistant/components/nsw_fuel_station/sensor.py @nickw444
|
||||
|
||||
# O
|
||||
homeassistant/components/ohmconnect/sensor.py @robbiet480
|
||||
homeassistant/components/notify/* @flowolf
|
||||
homeassistant/components/nsw_fuel_station/* @nickw444
|
||||
homeassistant/components/nuki/* @pschmitt
|
||||
homeassistant/components/ohmconnect/* @robbiet480
|
||||
homeassistant/components/onboarding/* @home-assistant/core
|
||||
homeassistant/components/openuv/* @bachya
|
||||
homeassistant/components/openweathermap/weather.py @fabaff
|
||||
homeassistant/components/openweathermap/* @fabaff
|
||||
homeassistant/components/owlet/* @oblogic7
|
||||
|
||||
# P
|
||||
homeassistant/components/pi_hole/sensor.py @fabaff
|
||||
homeassistant/components/panel_custom/* @home-assistant/core
|
||||
homeassistant/components/panel_iframe/* @home-assistant/core
|
||||
homeassistant/components/persistent_notification/* @home-assistant/core
|
||||
homeassistant/components/pi_hole/* @fabaff
|
||||
homeassistant/components/plant/* @ChristianKuehnel
|
||||
homeassistant/components/point/* @fredrike
|
||||
homeassistant/components/pollen/sensor.py @bachya
|
||||
homeassistant/components/push/camera.py @dgomes
|
||||
homeassistant/components/pvoutput/sensor.py @fabaff
|
||||
|
||||
# Q
|
||||
homeassistant/components/qnap/sensor.py @colinodell
|
||||
homeassistant/components/quantum_gateway/device_tracker.py @cisasteelersfan
|
||||
homeassistant/components/pollen/* @bachya
|
||||
homeassistant/components/push/* @dgomes
|
||||
homeassistant/components/pvoutput/* @fabaff
|
||||
homeassistant/components/qnap/* @colinodell
|
||||
homeassistant/components/quantum_gateway/* @cisasteelersfan
|
||||
homeassistant/components/qwikswitch/* @kellerza
|
||||
|
||||
# R
|
||||
homeassistant/components/raincloud/* @vanstinator
|
||||
homeassistant/components/rainmachine/* @bachya
|
||||
homeassistant/components/random/* @fabaff
|
||||
homeassistant/components/rfxtrx/* @danielhiversen
|
||||
homeassistant/components/rmvtransport/* @cgtobi
|
||||
homeassistant/components/roomba/vacuum.py @pschmitt
|
||||
homeassistant/components/ruter/sensor.py @ludeeus
|
||||
|
||||
# S
|
||||
homeassistant/components/scrape/sensor.py @fabaff
|
||||
homeassistant/components/sensibo/climate.py @andrey-git
|
||||
homeassistant/components/serial/sensor.py @fabaff
|
||||
homeassistant/components/seventeentrack/sensor.py @bachya
|
||||
homeassistant/components/roomba/* @pschmitt
|
||||
homeassistant/components/ruter/* @ludeeus
|
||||
homeassistant/components/scene/* @home-assistant/core
|
||||
homeassistant/components/scrape/* @fabaff
|
||||
homeassistant/components/script/* @home-assistant/core
|
||||
homeassistant/components/sensibo/* @andrey-git
|
||||
homeassistant/components/serial/* @fabaff
|
||||
homeassistant/components/seventeentrack/* @bachya
|
||||
homeassistant/components/shell_command/* @home-assistant/core
|
||||
homeassistant/components/shiftr/* @fabaff
|
||||
homeassistant/components/shodan/sensor.py @fabaff
|
||||
homeassistant/components/shodan/* @fabaff
|
||||
homeassistant/components/simplisafe/* @bachya
|
||||
homeassistant/components/sma/sensor.py @kellerza
|
||||
homeassistant/components/sma/* @kellerza
|
||||
homeassistant/components/smartthings/* @andrewsayre
|
||||
homeassistant/components/smtp/* @fabaff
|
||||
homeassistant/components/sonos/* @amelchio
|
||||
homeassistant/components/spaceapi/* @fabaff
|
||||
homeassistant/components/spider/* @peternijssen
|
||||
homeassistant/components/sql/sensor.py @dgomes
|
||||
homeassistant/components/statistics/sensor.py @fabaff
|
||||
homeassistant/components/swiss_*/* @fabaff
|
||||
homeassistant/components/switchbot/switch.py @danielhiversen
|
||||
homeassistant/components/switchmate/switch.py @danielhiversen
|
||||
homeassistant/components/synology_srm/device_tracker.py @aerialls
|
||||
homeassistant/components/sytadin/sensor.py @gautric
|
||||
|
||||
# T
|
||||
homeassistant/components/sql/* @dgomes
|
||||
homeassistant/components/statistics/* @fabaff
|
||||
homeassistant/components/stiebel_eltron/* @fucm
|
||||
homeassistant/components/sun/* @home-assistant/core
|
||||
homeassistant/components/supla/* @mwegrzynek
|
||||
homeassistant/components/swiss_hydrological_data/* @fabaff
|
||||
homeassistant/components/swiss_public_transport/* @fabaff
|
||||
homeassistant/components/switchbot/* @danielhiversen
|
||||
homeassistant/components/switchmate/* @danielhiversen
|
||||
homeassistant/components/synology_srm/* @aerialls
|
||||
homeassistant/components/syslog/* @fabaff
|
||||
homeassistant/components/sytadin/* @gautric
|
||||
homeassistant/components/tahoma/* @philklei
|
||||
homeassistant/components/tautulli/sensor.py @ludeeus
|
||||
homeassistant/components/tautulli/* @ludeeus
|
||||
homeassistant/components/tellduslive/* @fredrike
|
||||
homeassistant/components/template/cover.py @PhracturedBlue
|
||||
homeassistant/components/template/* @PhracturedBlue
|
||||
homeassistant/components/tesla/* @zabuldon
|
||||
homeassistant/components/tfiac/* @fredrike @mellado
|
||||
homeassistant/components/thethingsnetwork/* @fabaff
|
||||
homeassistant/components/threshold/binary_sensor.py @fabaff
|
||||
homeassistant/components/threshold/* @fabaff
|
||||
homeassistant/components/tibber/* @danielhiversen
|
||||
homeassistant/components/tile/device_tracker.py @bachya
|
||||
homeassistant/components/time_date/sensor.py @fabaff
|
||||
homeassistant/components/tile/* @bachya
|
||||
homeassistant/components/time_date/* @fabaff
|
||||
homeassistant/components/toon/* @frenck
|
||||
homeassistant/components/tplink/* @rytilahti
|
||||
homeassistant/components/traccar/device_tracker.py @ludeeus
|
||||
homeassistant/components/traccar/* @ludeeus
|
||||
homeassistant/components/tradfri/* @ggravlingen
|
||||
|
||||
# U
|
||||
homeassistant/components/uber/sensor.py @robbiet480
|
||||
homeassistant/components/tts/* @robbiet480
|
||||
homeassistant/components/twilio_call/* @robbiet480
|
||||
homeassistant/components/twilio_sms/* @robbiet480
|
||||
homeassistant/components/uber/* @robbiet480
|
||||
homeassistant/components/unifi/* @kane610
|
||||
homeassistant/components/upcloud/* @scop
|
||||
homeassistant/components/updater/* @home-assistant/core
|
||||
homeassistant/components/upnp/* @robbiet480
|
||||
homeassistant/components/uptimerobot/binary_sensor.py @ludeeus
|
||||
homeassistant/components/uptimerobot/* @ludeeus
|
||||
homeassistant/components/utility_meter/* @dgomes
|
||||
|
||||
# V
|
||||
homeassistant/components/velux/* @Julius2342
|
||||
homeassistant/components/version/sensor.py @fabaff
|
||||
|
||||
# W
|
||||
homeassistant/components/waqi/sensor.py @andrey-git
|
||||
homeassistant/components/weather/__init__.py @fabaff
|
||||
homeassistant/components/version/* @fabaff
|
||||
homeassistant/components/waqi/* @andrey-git
|
||||
homeassistant/components/weather/* @fabaff
|
||||
homeassistant/components/weblink/* @home-assistant/core
|
||||
homeassistant/components/websocket_api/* @home-assistant/core
|
||||
homeassistant/components/wemo/* @sqldiablo
|
||||
homeassistant/components/worldclock/sensor.py @fabaff
|
||||
|
||||
# X
|
||||
homeassistant/components/xfinity/device_tracker.py @cisasteelersfan
|
||||
homeassistant/components/worldclock/* @fabaff
|
||||
homeassistant/components/xfinity/* @cisasteelersfan
|
||||
homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi
|
||||
homeassistant/components/xiaomi_miio/* @rytilahti @syssi
|
||||
homeassistant/components/xiaomi_tv/media_player.py @fattdev
|
||||
|
||||
# Y
|
||||
homeassistant/components/xiaomi_tv/* @fattdev
|
||||
homeassistant/components/xmpp/* @fabaff
|
||||
homeassistant/components/yamaha_musiccast/* @jalmeroth
|
||||
homeassistant/components/yeelight/* @rytilahti @zewelor
|
||||
homeassistant/components/yeelightsunflower/light.py @lindsaymarkward
|
||||
homeassistant/components/yi/camera.py @bachya
|
||||
|
||||
# Z
|
||||
homeassistant/components/yeelightsunflower/* @lindsaymarkward
|
||||
homeassistant/components/yessssms/* @flowolf
|
||||
homeassistant/components/yi/* @bachya
|
||||
homeassistant/components/zeroconf/* @robbiet480
|
||||
homeassistant/components/zha/* @dmulcahey @adminiuga
|
||||
homeassistant/components/zone/* @home-assistant/core
|
||||
homeassistant/components/zoneminder/* @rohankapoorcom
|
||||
homeassistant/components/zwave/* @home-assistant/z-wave
|
||||
|
||||
# Other code
|
||||
homeassistant/scripts/check_config.py @kellerza
|
||||
# Individual files
|
||||
homeassistant/components/group/cover @cdce8p
|
||||
homeassistant/components/demo/weather @fabaff
|
||||
|
@ -27,7 +27,7 @@ COPY requirements_all.txt requirements_all.txt
|
||||
# Uninstall enum34 because some dependencies install it but breaks Python 3.4+.
|
||||
# See PR #8103 for more info.
|
||||
RUN pip3 install --no-cache-dir -r requirements_all.txt && \
|
||||
pip3 install --no-cache-dir mysqlclient psycopg2 uvloop==0.11.3 cchardet cython tensorflow
|
||||
pip3 install --no-cache-dir mysqlclient psycopg2 uvloop==0.12.2 cchardet cython tensorflow
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
@ -11,9 +11,6 @@ from typing import Any, Optional, Dict, Set
|
||||
import voluptuous as vol
|
||||
|
||||
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.setup import async_setup_component
|
||||
from homeassistant.util.logging import AsyncHandler
|
||||
@ -29,50 +26,16 @@ ERROR_LOG_FILENAME = 'home-assistant.log'
|
||||
# hass.data key for logging information.
|
||||
DATA_LOGGING = 'logging'
|
||||
|
||||
LOGGING_COMPONENT = {'logger', 'system_log'}
|
||||
|
||||
FIRST_INIT_COMPONENT = {
|
||||
CORE_INTEGRATIONS = ('homeassistant', 'persistent_notification')
|
||||
LOGGING_INTEGRATIONS = {'logger', 'system_log'}
|
||||
STAGE_1_INTEGRATIONS = {
|
||||
# To record data
|
||||
'recorder',
|
||||
'mqtt',
|
||||
# To make sure we forward data to other instances
|
||||
'mqtt_eventstream',
|
||||
'introduction',
|
||||
'frontend',
|
||||
'history',
|
||||
}
|
||||
|
||||
|
||||
def from_config_dict(config: Dict[str, Any],
|
||||
hass: Optional[core.HomeAssistant] = None,
|
||||
config_dir: Optional[str] = None,
|
||||
enable_log: bool = True,
|
||||
verbose: bool = False,
|
||||
skip_pip: bool = False,
|
||||
log_rotate_days: Any = None,
|
||||
log_file: Any = None,
|
||||
log_no_color: bool = False) \
|
||||
-> Optional[core.HomeAssistant]:
|
||||
"""Try to configure Home Assistant from a configuration dictionary.
|
||||
|
||||
Dynamically loads required components and its dependencies.
|
||||
"""
|
||||
if hass is None:
|
||||
hass = core.HomeAssistant()
|
||||
if config_dir is not None:
|
||||
config_dir = os.path.abspath(config_dir)
|
||||
hass.config.config_dir = config_dir
|
||||
if not is_virtual_env():
|
||||
hass.loop.run_until_complete(
|
||||
async_mount_local_lib_path(config_dir))
|
||||
|
||||
# run task
|
||||
hass = hass.loop.run_until_complete(
|
||||
async_from_config_dict(
|
||||
config, hass, config_dir, enable_log, verbose, skip_pip,
|
||||
log_rotate_days, log_file, log_no_color)
|
||||
)
|
||||
return hass
|
||||
|
||||
|
||||
async def async_from_config_dict(config: Dict[str, Any],
|
||||
hass: core.HomeAssistant,
|
||||
config_dir: Optional[str] = None,
|
||||
@ -115,70 +78,17 @@ async def async_from_config_dict(config: Dict[str, Any],
|
||||
"Further initialization aborted")
|
||||
return None
|
||||
|
||||
await hass.async_add_executor_job(
|
||||
conf_util.process_ha_config_upgrade, hass)
|
||||
|
||||
# Make a copy because we are mutating it.
|
||||
config = OrderedDict(config)
|
||||
|
||||
# Merge packages
|
||||
conf_util.merge_packages_config(
|
||||
await conf_util.merge_packages_config(
|
||||
hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))
|
||||
|
||||
hass.config_entries = config_entries.ConfigEntries(hass, config)
|
||||
await hass.config_entries.async_initialize()
|
||||
|
||||
components = _get_components(hass, config)
|
||||
|
||||
# Resolve all dependencies of all components.
|
||||
for component in list(components):
|
||||
try:
|
||||
components.update(loader.component_dependencies(hass, component))
|
||||
except loader.LoaderError:
|
||||
# Ignore it, or we'll break startup
|
||||
# It will be properly handled during setup.
|
||||
pass
|
||||
|
||||
# setup components
|
||||
res = await core_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()
|
||||
await _async_set_up_integrations(hass, config)
|
||||
|
||||
stop = time()
|
||||
_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
|
||||
|
||||
|
||||
def from_config_file(config_path: str,
|
||||
hass: Optional[core.HomeAssistant] = None,
|
||||
verbose: bool = False,
|
||||
skip_pip: bool = True,
|
||||
log_rotate_days: Any = None,
|
||||
log_file: Any = None,
|
||||
log_no_color: bool = False)\
|
||||
-> Optional[core.HomeAssistant]:
|
||||
"""Read the configuration file and try to start all the functionality.
|
||||
|
||||
Will add functionality to 'hass' parameter if given,
|
||||
instantiates a new Home Assistant object if 'hass' is not given.
|
||||
"""
|
||||
if hass is None:
|
||||
hass = core.HomeAssistant()
|
||||
|
||||
# run task
|
||||
hass = hass.loop.run_until_complete(
|
||||
async_from_config_file(
|
||||
config_path, hass, verbose, skip_pip,
|
||||
log_rotate_days, log_file, log_no_color)
|
||||
)
|
||||
|
||||
return hass
|
||||
|
||||
|
||||
async def async_from_config_file(config_path: str,
|
||||
hass: core.HomeAssistant,
|
||||
verbose: bool = False,
|
||||
@ -280,6 +164,9 @@ async def async_from_config_file(config_path: str,
|
||||
async_enable_logging(hass, verbose, log_rotate_days, log_file,
|
||||
log_no_color)
|
||||
|
||||
await hass.async_add_executor_job(
|
||||
conf_util.process_ha_config_upgrade, hass)
|
||||
|
||||
try:
|
||||
config_dict = await hass.async_add_executor_job(
|
||||
conf_util.load_yaml_config_file, config_path)
|
||||
@ -398,18 +285,127 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
|
||||
|
||||
|
||||
@core.callback
|
||||
def _get_components(hass: core.HomeAssistant,
|
||||
config: Dict[str, Any]) -> Set[str]:
|
||||
"""Get components to set up."""
|
||||
def _get_domains(hass: core.HomeAssistant, config: Dict[str, Any]) -> Set[str]:
|
||||
"""Get domains of components to set up."""
|
||||
# Filter out the repeating and common config section [homeassistant]
|
||||
components = set(key.split(' ')[0] for key in config.keys()
|
||||
if key != core.DOMAIN)
|
||||
domains = set(key.split(' ')[0] for key in config.keys()
|
||||
if key != core.DOMAIN)
|
||||
|
||||
# Add config entry domains
|
||||
components.update(hass.config_entries.async_domains()) # type: ignore
|
||||
domains.update(hass.config_entries.async_domains()) # type: ignore
|
||||
|
||||
# Make sure the Hass.io component is loaded
|
||||
if 'HASSIO' in os.environ:
|
||||
components.add('hassio')
|
||||
domains.add('hassio')
|
||||
|
||||
return components
|
||||
return domains
|
||||
|
||||
|
||||
async def _async_set_up_integrations(
|
||||
hass: core.HomeAssistant, config: Dict[str, Any]) -> None:
|
||||
"""Set up all the integrations."""
|
||||
domains = _get_domains(hass, config)
|
||||
|
||||
# Resolve all dependencies of all components so we can find the logging
|
||||
# and integrations that need faster initialization.
|
||||
resolved_domains_task = asyncio.gather(*[
|
||||
loader.async_component_dependencies(hass, domain)
|
||||
for domain in domains
|
||||
], return_exceptions=True)
|
||||
|
||||
# Set up core.
|
||||
_LOGGER.debug("Setting up %s", CORE_INTEGRATIONS)
|
||||
|
||||
if not all(await asyncio.gather(*[
|
||||
async_setup_component(hass, domain, config)
|
||||
for domain in CORE_INTEGRATIONS
|
||||
])):
|
||||
_LOGGER.error("Home Assistant core failed to initialize. "
|
||||
"Further initialization aborted")
|
||||
return
|
||||
|
||||
_LOGGER.debug("Home Assistant core initialized")
|
||||
|
||||
# Finish resolving domains
|
||||
for dep_domains in await resolved_domains_task:
|
||||
# Result is either a set or an exception. We ignore exceptions
|
||||
# It will be properly handled during setup of the domain.
|
||||
if isinstance(dep_domains, set):
|
||||
domains.update(dep_domains)
|
||||
|
||||
# setup components
|
||||
logging_domains = domains & LOGGING_INTEGRATIONS
|
||||
stage_1_domains = domains & STAGE_1_INTEGRATIONS
|
||||
stage_2_domains = domains - logging_domains - stage_1_domains
|
||||
|
||||
if logging_domains:
|
||||
_LOGGER.debug("Setting up %s", logging_domains)
|
||||
|
||||
await asyncio.gather(*[
|
||||
async_setup_component(hass, domain, config)
|
||||
for domain in logging_domains
|
||||
])
|
||||
|
||||
# Kick off loading the registries. They don't need to be awaited.
|
||||
asyncio.gather(
|
||||
hass.helpers.device_registry.async_get_registry(),
|
||||
hass.helpers.entity_registry.async_get_registry(),
|
||||
hass.helpers.area_registry.async_get_registry())
|
||||
|
||||
if stage_1_domains:
|
||||
await asyncio.gather(*[
|
||||
async_setup_component(hass, domain, config)
|
||||
for domain in 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()
|
||||
|
@ -13,8 +13,6 @@ from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
REQUIREMENTS = ['abodepy==0.15.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTRIBUTION = "Data provided by goabode.com"
|
||||
|
@ -8,8 +8,6 @@ from homeassistant.const import (
|
||||
|
||||
from . import ATTRIBUTION, DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ICON = 'mdi:security'
|
||||
|
@ -7,8 +7,6 @@ from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up a sensor for an Abode device."""
|
||||
|
@ -9,8 +9,6 @@ from homeassistant.util import Throttle
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -5,8 +5,6 @@ from homeassistant.components.cover import CoverDevice
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -10,8 +10,6 @@ from homeassistant.util.color import (
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -5,8 +5,6 @@ from homeassistant.components.lock import LockDevice
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
10
homeassistant/components/abode/manifest.json
Normal file
10
homeassistant/components/abode/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "abode",
|
||||
"name": "Abode",
|
||||
"documentation": "https://www.home-assistant.io/components/abode",
|
||||
"requirements": [
|
||||
"abodepy==0.15.0"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -8,8 +8,6 @@ from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
# Sensor types: Name, icon
|
||||
SENSOR_TYPES = {
|
||||
'temp': ['Temperature', DEVICE_CLASS_TEMPERATURE],
|
||||
|
@ -7,8 +7,6 @@ from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up Abode switch devices."""
|
||||
|
10
homeassistant/components/acer_projector/manifest.json
Normal file
10
homeassistant/components/acer_projector/manifest.json
Normal 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": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Use serial protocol of Acer projector to obtain state of the projector."""
|
||||
import logging
|
||||
import re
|
||||
|
||||
@ -14,8 +9,6 @@ from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, STATE_UNKNOWN, CONF_NAME, CONF_FILENAME)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['pyserial==3.1.1']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_TIMEOUT = 'timeout'
|
||||
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for Actiontec MI424WR (Verizon FIOS) routers."""
|
||||
import logging
|
||||
import re
|
||||
import telnetlib
|
||||
|
8
homeassistant/components/actiontec/manifest.json
Normal file
8
homeassistant/components/actiontec/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"domain": "actiontec",
|
||||
"name": "Actiontec",
|
||||
"documentation": "https://www.home-assistant.io/components/actiontec",
|
||||
"requirements": [],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -4,14 +4,15 @@ import struct
|
||||
import logging
|
||||
import ctypes
|
||||
from collections import namedtuple
|
||||
import asyncio
|
||||
import async_timeout
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE, CONF_IP_ADDRESS, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['pyads==3.0.7']
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -31,6 +32,9 @@ CONF_ADS_VALUE = 'value'
|
||||
CONF_ADS_VAR = 'adsvar'
|
||||
CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness'
|
||||
|
||||
STATE_KEY_STATE = 'state'
|
||||
STATE_KEY_BRIGHTNESS = 'brightness'
|
||||
|
||||
DOMAIN = 'ads'
|
||||
|
||||
SERVICE_WRITE_DATA_BY_NAME = 'write_data_by_name'
|
||||
@ -154,28 +158,41 @@ class AdsHub:
|
||||
|
||||
def write_by_name(self, name, value, plc_datatype):
|
||||
"""Write a value to the device."""
|
||||
import pyads
|
||||
with self._lock:
|
||||
return self._client.write_by_name(name, value, plc_datatype)
|
||||
try:
|
||||
return self._client.write_by_name(name, value, plc_datatype)
|
||||
except pyads.ADSError as err:
|
||||
_LOGGER.error("Error writing %s: %s", name, err)
|
||||
|
||||
def read_by_name(self, name, plc_datatype):
|
||||
"""Read a value from the device."""
|
||||
import pyads
|
||||
with self._lock:
|
||||
return self._client.read_by_name(name, plc_datatype)
|
||||
try:
|
||||
return self._client.read_by_name(name, plc_datatype)
|
||||
except pyads.ADSError as err:
|
||||
_LOGGER.error("Error reading %s: %s", name, err)
|
||||
|
||||
def add_device_notification(self, name, plc_datatype, callback):
|
||||
"""Add a notification to the ADS devices."""
|
||||
from pyads import NotificationAttrib
|
||||
attr = NotificationAttrib(ctypes.sizeof(plc_datatype))
|
||||
import pyads
|
||||
attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype))
|
||||
|
||||
with self._lock:
|
||||
hnotify, huser = self._client.add_device_notification(
|
||||
name, attr, self._device_notification_callback)
|
||||
hnotify = int(hnotify)
|
||||
self._notification_items[hnotify] = NotificationItem(
|
||||
hnotify, huser, name, plc_datatype, callback)
|
||||
try:
|
||||
hnotify, huser = self._client.add_device_notification(
|
||||
name, attr, self._device_notification_callback)
|
||||
except pyads.ADSError as err:
|
||||
_LOGGER.error("Error subscribing to %s: %s", name, err)
|
||||
else:
|
||||
hnotify = int(hnotify)
|
||||
self._notification_items[hnotify] = NotificationItem(
|
||||
hnotify, huser, name, plc_datatype, callback)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Added device notification %d for variable %s", hnotify, name)
|
||||
_LOGGER.debug(
|
||||
"Added device notification %d for variable %s",
|
||||
hnotify, name)
|
||||
|
||||
def _device_notification_callback(self, notification, name):
|
||||
"""Handle device notifications."""
|
||||
@ -210,3 +227,68 @@ class AdsHub:
|
||||
_LOGGER.warning("No callback available for this datatype")
|
||||
|
||||
notification_item.callback(notification_item.name, value)
|
||||
|
||||
|
||||
class AdsEntity(Entity):
|
||||
"""Representation of ADS entity."""
|
||||
|
||||
def __init__(self, ads_hub, name, ads_var):
|
||||
"""Initialize ADS binary sensor."""
|
||||
self._name = name
|
||||
self._unique_id = ads_var
|
||||
self._state_dict = {}
|
||||
self._state_dict[STATE_KEY_STATE] = None
|
||||
self._ads_hub = ads_hub
|
||||
self._ads_var = ads_var
|
||||
self._event = None
|
||||
|
||||
async def async_initialize_device(
|
||||
self, ads_var, plctype, state_key=STATE_KEY_STATE, factor=None):
|
||||
"""Register device notification."""
|
||||
def update(name, value):
|
||||
"""Handle device notifications."""
|
||||
_LOGGER.debug('Variable %s changed its value to %d', name, value)
|
||||
|
||||
if factor is None:
|
||||
self._state_dict[state_key] = value
|
||||
else:
|
||||
self._state_dict[state_key] = value / factor
|
||||
|
||||
asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def async_event_set():
|
||||
"""Set event in async context."""
|
||||
self._event.set()
|
||||
|
||||
self._event = asyncio.Event()
|
||||
|
||||
await self.hass.async_add_executor_job(
|
||||
self._ads_hub.add_device_notification,
|
||||
ads_var, plctype, update)
|
||||
try:
|
||||
with async_timeout.timeout(10):
|
||||
await self._event.wait()
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.debug('Variable %s: Timeout during first update',
|
||||
ads_var)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the default name of the binary sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return an unique identifier for this entity."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return False because entity pushes its state to HA."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return False if state has not been updated yet."""
|
||||
return self._state_dict[STATE_KEY_STATE] is not None
|
||||
|
@ -8,13 +8,11 @@ from homeassistant.components.binary_sensor import (
|
||||
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
|
||||
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__)
|
||||
|
||||
DEFAULT_NAME = 'ADS binary sensor'
|
||||
DEPENDENCIES = ['ads']
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_ADS_VAR): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
@ -34,51 +32,25 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
add_entities([ads_sensor])
|
||||
|
||||
|
||||
class AdsBinarySensor(BinarySensorDevice):
|
||||
class AdsBinarySensor(AdsEntity, BinarySensorDevice):
|
||||
"""Representation of ADS binary sensors."""
|
||||
|
||||
def __init__(self, ads_hub, name, ads_var, device_class):
|
||||
"""Initialize ADS binary sensor."""
|
||||
self._name = name
|
||||
self._unique_id = ads_var
|
||||
self._state = False
|
||||
super().__init__(ads_hub, name, ads_var)
|
||||
self._device_class = device_class or 'moving'
|
||||
self._ads_hub = ads_hub
|
||||
self.ads_var = ads_var
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register device notification."""
|
||||
def update(name, value):
|
||||
"""Handle device notifications."""
|
||||
_LOGGER.debug('Variable %s changed its value to %d', name, value)
|
||||
self._state = value
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
self.hass.async_add_job(
|
||||
self._ads_hub.add_device_notification,
|
||||
self.ads_var, self._ads_hub.PLCTYPE_BOOL, update)
|
||||
await self.async_initialize_device(self._ads_var,
|
||||
self._ads_hub.PLCTYPE_BOOL)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the default name of the binary sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return an unique identifier for this entity."""
|
||||
return self._unique_id
|
||||
def is_on(self):
|
||||
"""Return True if the entity is on."""
|
||||
return self._state_dict[STATE_KEY_STATE]
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the device class."""
|
||||
return self._device_class
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return if the binary sensor is on."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return False because entity pushes its state to HA."""
|
||||
return False
|
||||
|
@ -8,12 +8,11 @@ from homeassistant.components.light import (
|
||||
from homeassistant.const import CONF_NAME
|
||||
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__)
|
||||
DEPENDENCIES = ['ads']
|
||||
DEFAULT_NAME = 'ADS Light'
|
||||
CONF_ADSVAR_BRIGHTNESS = 'adsvar_brightness'
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_ADS_VAR): cv.string,
|
||||
vol.Optional(CONF_ADS_VAR_BRIGHTNESS): cv.string,
|
||||
@ -30,91 +29,57 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
name = config.get(CONF_NAME)
|
||||
|
||||
add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness,
|
||||
name)], True)
|
||||
name)])
|
||||
|
||||
|
||||
class AdsLight(Light):
|
||||
class AdsLight(AdsEntity, Light):
|
||||
"""Representation of ADS light."""
|
||||
|
||||
def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name):
|
||||
"""Initialize AdsLight entity."""
|
||||
self._ads_hub = ads_hub
|
||||
self._on_state = False
|
||||
self._brightness = None
|
||||
self._name = name
|
||||
self._unique_id = ads_var_enable
|
||||
self.ads_var_enable = ads_var_enable
|
||||
self.ads_var_brightness = ads_var_brightness
|
||||
super().__init__(ads_hub, name, ads_var_enable)
|
||||
self._state_dict[STATE_KEY_BRIGHTNESS] = None
|
||||
self._ads_var_brightness = ads_var_brightness
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register device notification."""
|
||||
def update_on_state(name, value):
|
||||
"""Handle device notifications for state."""
|
||||
_LOGGER.debug('Variable %s changed its value to %d', name, value)
|
||||
self._on_state = value
|
||||
self.schedule_update_ha_state()
|
||||
await self.async_initialize_device(self._ads_var,
|
||||
self._ads_hub.PLCTYPE_BOOL)
|
||||
|
||||
def update_brightness(name, value):
|
||||
"""Handle device notification for brightness."""
|
||||
_LOGGER.debug('Variable %s changed its value to %d', name, value)
|
||||
self._brightness = value
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
self.hass.async_add_executor_job(
|
||||
self._ads_hub.add_device_notification,
|
||||
self.ads_var_enable, self._ads_hub.PLCTYPE_BOOL, update_on_state
|
||||
)
|
||||
if self.ads_var_brightness is not None:
|
||||
self.hass.async_add_executor_job(
|
||||
self._ads_hub.add_device_notification,
|
||||
self.ads_var_brightness, self._ads_hub.PLCTYPE_INT,
|
||||
update_brightness
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device if any."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return an unique identifier for this entity."""
|
||||
return self._unique_id
|
||||
if self._ads_var_brightness is not None:
|
||||
await self.async_initialize_device(self._ads_var_brightness,
|
||||
self._ads_hub.PLCTYPE_UINT,
|
||||
STATE_KEY_BRIGHTNESS)
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of the light (0..255)."""
|
||||
return self._brightness
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return if light is on."""
|
||||
return self._on_state
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return False because entity pushes its state to HA."""
|
||||
return False
|
||||
return self._state_dict[STATE_KEY_BRIGHTNESS]
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
support = 0
|
||||
if self.ads_var_brightness is not None:
|
||||
if self._ads_var_brightness is not None:
|
||||
support = SUPPORT_BRIGHTNESS
|
||||
return support
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return True if the entity is on."""
|
||||
return self._state_dict[STATE_KEY_STATE]
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the light on or set a specific dimmer value."""
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||
self._ads_hub.write_by_name(self.ads_var_enable, True,
|
||||
self._ads_hub.write_by_name(self._ads_var, True,
|
||||
self._ads_hub.PLCTYPE_BOOL)
|
||||
|
||||
if self.ads_var_brightness is not None and brightness is not None:
|
||||
self._ads_hub.write_by_name(self.ads_var_brightness, brightness,
|
||||
if self._ads_var_brightness is not None and brightness is not None:
|
||||
self._ads_hub.write_by_name(self._ads_var_brightness, brightness,
|
||||
self._ads_hub.PLCTYPE_UINT)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the light off."""
|
||||
self._ads_hub.write_by_name(self.ads_var_enable, False,
|
||||
self._ads_hub.write_by_name(self._ads_var, False,
|
||||
self._ads_hub.PLCTYPE_BOOL)
|
||||
|
10
homeassistant/components/ads/manifest.json
Normal file
10
homeassistant/components/ads/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "ads",
|
||||
"name": "Ads",
|
||||
"documentation": "https://www.home-assistant.io/components/ads",
|
||||
"requirements": [
|
||||
"pyads==3.0.7"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -7,15 +7,13 @@ from homeassistant.components import ads
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR
|
||||
from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR, \
|
||||
AdsEntity, STATE_KEY_STATE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_NAME = "ADS sensor"
|
||||
DEPENDENCIES = ['ads']
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_ADS_VAR): cv.string,
|
||||
vol.Optional(CONF_ADS_FACTOR): cv.positive_int,
|
||||
@ -43,60 +41,31 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
add_entities([entity])
|
||||
|
||||
|
||||
class AdsSensor(Entity):
|
||||
class AdsSensor(AdsEntity):
|
||||
"""Representation of an ADS sensor entity."""
|
||||
|
||||
def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement,
|
||||
factor):
|
||||
"""Initialize AdsSensor entity."""
|
||||
self._ads_hub = ads_hub
|
||||
self._name = name
|
||||
self._unique_id = ads_var
|
||||
self._value = None
|
||||
super().__init__(ads_hub, name, ads_var)
|
||||
self._unit_of_measurement = unit_of_measurement
|
||||
self.ads_var = ads_var
|
||||
self.ads_type = ads_type
|
||||
self.factor = factor
|
||||
self._ads_type = ads_type
|
||||
self._factor = factor
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register device notification."""
|
||||
def update(name, value):
|
||||
"""Handle device notifications."""
|
||||
_LOGGER.debug("Variable %s changed its value to %d", name, value)
|
||||
|
||||
# If factor is set use it otherwise not
|
||||
if self.factor is None:
|
||||
self._value = value
|
||||
else:
|
||||
self._value = value / self.factor
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
self.hass.async_add_job(
|
||||
self._ads_hub.add_device_notification,
|
||||
self.ads_var, self._ads_hub.ADS_TYPEMAP[self.ads_type], update
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the entity."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return an unique identifier for this entity."""
|
||||
return self._unique_id
|
||||
await self.async_initialize_device(
|
||||
self._ads_var,
|
||||
self._ads_hub.ADS_TYPEMAP[self._ads_type],
|
||||
STATE_KEY_STATE,
|
||||
self._factor)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
return self._value
|
||||
return self._state_dict[STATE_KEY_STATE]
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement."""
|
||||
return self._unit_of_measurement
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return False because entity pushes its state."""
|
||||
return False
|
||||
|
@ -3,17 +3,14 @@ import logging
|
||||
|
||||
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
|
||||
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__)
|
||||
|
||||
DEPENDENCIES = ['ads']
|
||||
|
||||
DEFAULT_NAME = 'ADS Switch'
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
@ -29,58 +26,28 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
name = config.get(CONF_NAME)
|
||||
ads_var = config.get(CONF_ADS_VAR)
|
||||
|
||||
add_entities([AdsSwitch(ads_hub, name, ads_var)], True)
|
||||
add_entities([AdsSwitch(ads_hub, name, ads_var)])
|
||||
|
||||
|
||||
class AdsSwitch(ToggleEntity):
|
||||
class AdsSwitch(AdsEntity, SwitchDevice):
|
||||
"""Representation of an ADS switch device."""
|
||||
|
||||
def __init__(self, ads_hub, name, ads_var):
|
||||
"""Initialize the AdsSwitch entity."""
|
||||
self._ads_hub = ads_hub
|
||||
self._on_state = False
|
||||
self._name = name
|
||||
self._unique_id = ads_var
|
||||
self.ads_var = ads_var
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register device notification."""
|
||||
def update(name, value):
|
||||
"""Handle device notification."""
|
||||
_LOGGER.debug("Variable %s changed its value to %d", name, value)
|
||||
self._on_state = value
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
self.hass.async_add_job(
|
||||
self._ads_hub.add_device_notification,
|
||||
self.ads_var, self._ads_hub.PLCTYPE_BOOL, update)
|
||||
await self.async_initialize_device(self._ads_var,
|
||||
self._ads_hub.PLCTYPE_BOOL)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return if the switch is turned on."""
|
||||
return self._on_state
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the entity."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return an unique identifier for this entity."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return False because entity pushes its state to HA."""
|
||||
return False
|
||||
"""Return True if the entity is on."""
|
||||
return self._state_dict[STATE_KEY_STATE]
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the switch on."""
|
||||
self._ads_hub.write_by_name(
|
||||
self.ads_var, True, self._ads_hub.PLCTYPE_BOOL)
|
||||
self._ads_var, True, self._ads_hub.PLCTYPE_BOOL)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the switch off."""
|
||||
self._ads_hub.write_by_name(
|
||||
self.ads_var, False, self._ads_hub.PLCTYPE_BOOL)
|
||||
self._ads_var, False, self._ads_hub.PLCTYPE_BOOL)
|
||||
|
2
homeassistant/components/aftership/const.py
Normal file
2
homeassistant/components/aftership/const.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""Constants for the Aftership integration."""
|
||||
DOMAIN = 'aftership'
|
10
homeassistant/components/aftership/manifest.json
Normal file
10
homeassistant/components/aftership/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "aftership",
|
||||
"name": "Aftership",
|
||||
"documentation": "https://www.home-assistant.io/components/aftership",
|
||||
"requirements": [
|
||||
"pyaftership==0.1.2"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for non-delivered packages recorded in AfterShip."""
|
||||
from datetime import timedelta
|
||||
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.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
REQUIREMENTS = ['pyaftership==0.1.2']
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTRIBUTION = 'Information provided by AfterShip'
|
||||
ATTR_TRACKINGS = 'trackings'
|
||||
|
||||
BASE = 'https://track.aftership.com/'
|
||||
|
||||
CONF_SLUG = 'slug'
|
||||
CONF_TITLE = 'title'
|
||||
CONF_TRACKING_NUMBER = 'tracking_number'
|
||||
|
||||
DEFAULT_NAME = 'aftership'
|
||||
UPDATE_TOPIC = DOMAIN + '_update'
|
||||
|
||||
ICON = 'mdi:package-variant-closed'
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=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({
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
@ -56,7 +71,40 @@ async def async_setup_platform(
|
||||
aftership.meta)
|
||||
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):
|
||||
@ -94,8 +142,18 @@ class AfterShipSensor(Entity):
|
||||
"""Icon to use in the frontend."""
|
||||
return ICON
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||
UPDATE_TOPIC, self.force_update)
|
||||
|
||||
async def force_update(self):
|
||||
"""Force update of data."""
|
||||
await self.async_update(no_throttle=True)
|
||||
await self.async_update_ha_state()
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
async def async_update(self):
|
||||
async def async_update(self, **kwargs):
|
||||
"""Get the latest data from the AfterShip API."""
|
||||
await self.aftership.get_trackings()
|
||||
|
||||
@ -109,12 +167,29 @@ class AfterShipSensor(Entity):
|
||||
|
||||
status_to_ignore = {'delivered'}
|
||||
status_counts = {}
|
||||
trackings = []
|
||||
not_delivered_count = 0
|
||||
|
||||
for tracking in self.aftership.trackings['trackings']:
|
||||
status = tracking['tag'].lower()
|
||||
name = tracking['tracking_number']
|
||||
status_counts[status] = status_counts.get(status, 0)+1
|
||||
for track in self.aftership.trackings['trackings']:
|
||||
status = track['tag'].lower()
|
||||
name = (
|
||||
track['tracking_number']
|
||||
if track['title'] is None
|
||||
else track['title']
|
||||
)
|
||||
status_counts[status] = status_counts.get(status, 0) + 1
|
||||
trackings.append({
|
||||
'name': name,
|
||||
'tracking_number': track['tracking_number'],
|
||||
'slug': track['slug'],
|
||||
'link': '%s%s/%s' %
|
||||
(BASE, track['slug'], track['tracking_number']),
|
||||
'last_update': track['updated_at'],
|
||||
'expected_delivery': track['expected_delivery'],
|
||||
'status': track['tag'],
|
||||
'last_checkpoint': track['checkpoints'][-1]
|
||||
})
|
||||
|
||||
if status not in status_to_ignore:
|
||||
not_delivered_count += 1
|
||||
else:
|
||||
@ -122,7 +197,8 @@ class AfterShipSensor(Entity):
|
||||
|
||||
self._attributes = {
|
||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||
**status_counts
|
||||
**status_counts,
|
||||
ATTR_TRACKINGS: trackings,
|
||||
}
|
||||
|
||||
self._state = not_delivered_count
|
||||
|
24
homeassistant/components/aftership/services.yaml
Normal file
24
homeassistant/components/aftership/services.yaml
Normal 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'
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
Component for handling Air Quality data for your location.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/air_quality/
|
||||
"""
|
||||
"""Component for handling Air Quality data for your location."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
|
8
homeassistant/components/air_quality/manifest.json
Normal file
8
homeassistant/components/air_quality/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"domain": "air_quality",
|
||||
"name": "Air quality",
|
||||
"documentation": "https://www.home-assistant.io/components/air_quality",
|
||||
"requirements": [],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
12
homeassistant/components/airvisual/manifest.json
Normal file
12
homeassistant/components/airvisual/manifest.json
Normal 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"
|
||||
]
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for AirVisual air quality sensors."""
|
||||
from logging import getLogger
|
||||
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.util import Throttle
|
||||
|
||||
REQUIREMENTS = ['pyairvisual==3.0.1']
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
ATTR_CITY = 'city'
|
||||
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Platform for the Aladdin Connect cover component."""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
@ -14,8 +9,6 @@ from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, STATE_CLOSED,
|
||||
STATE_OPENING, STATE_CLOSING, STATE_OPEN)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['aladdin_connect==0.3']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
NOTIFICATION_ID = 'aladdin_notification'
|
||||
|
10
homeassistant/components/aladdin_connect/manifest.json
Normal file
10
homeassistant/components/aladdin_connect/manifest.json
Normal 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": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
Component to interface with an alarm control panel.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/alarm_control_panel/
|
||||
"""
|
||||
"""Component to interface with an alarm control panel."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
|
10
homeassistant/components/alarm_control_panel/manifest.json
Normal file
10
homeassistant/components/alarm_control_panel/manifest.json
Normal 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"
|
||||
]
|
||||
}
|
@ -10,8 +10,6 @@ from homeassistant.helpers.discovery import load_platform
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA
|
||||
|
||||
REQUIREMENTS = ['alarmdecoder==1.13.2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'alarmdecoder'
|
||||
|
@ -13,8 +13,6 @@ from . import DATA_AD, SIGNAL_PANEL_MESSAGE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['alarmdecoder']
|
||||
|
||||
SERVICE_ALARM_TOGGLE_CHIME = 'alarmdecoder_alarm_toggle_chime'
|
||||
ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_CODE): cv.string,
|
||||
|
@ -8,8 +8,6 @@ from . import (
|
||||
CONF_ZONE_RFID, CONF_ZONE_TYPE, CONF_ZONES, SIGNAL_REL_MESSAGE,
|
||||
SIGNAL_RFX_MESSAGE, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE, ZONE_SCHEMA)
|
||||
|
||||
DEPENDENCIES = ['alarmdecoder']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_RF_BIT0 = 'rf_bit0'
|
||||
|
10
homeassistant/components/alarmdecoder/manifest.json
Normal file
10
homeassistant/components/alarmdecoder/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "alarmdecoder",
|
||||
"name": "Alarmdecoder",
|
||||
"documentation": "https://www.home-assistant.io/components/alarmdecoder",
|
||||
"requirements": [
|
||||
"alarmdecoder==1.13.2"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -7,8 +7,6 @@ from . import SIGNAL_PANEL_MESSAGE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['alarmdecoder']
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up for AlarmDecoder sensor devices."""
|
||||
|
0
homeassistant/components/alarmdecoder/services.yaml
Normal file
0
homeassistant/components/alarmdecoder/services.yaml
Normal file
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Interfaces with Alarm.com alarm control panels."""
|
||||
import logging
|
||||
import re
|
||||
|
||||
@ -17,8 +12,6 @@ from homeassistant.const import (
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['pyalarmdotcom==0.3.2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_NAME = 'Alarm.com'
|
||||
|
10
homeassistant/components/alarmdotcom/manifest.json
Normal file
10
homeassistant/components/alarmdotcom/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "alarmdotcom",
|
||||
"name": "Alarmdotcom",
|
||||
"documentation": "https://www.home-assistant.io/components/alarmdotcom",
|
||||
"requirements": [
|
||||
"pyalarmdotcom==0.3.2"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
8
homeassistant/components/alert/manifest.json
Normal file
8
homeassistant/components/alert/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"domain": "alert",
|
||||
"name": "Alert",
|
||||
"documentation": "https://www.home-assistant.io/components/alert",
|
||||
"requirements": [],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -17,8 +17,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||
CONF_FLASH_BRIEFINGS = 'flash_briefings'
|
||||
CONF_SMART_HOME = 'smart_home'
|
||||
|
||||
DEPENDENCIES = ['http']
|
||||
|
||||
ALEXA_ENTITY_SCHEMA = vol.Schema({
|
||||
vol.Optional(smart_home.CONF_DESCRIPTION): cv.string,
|
||||
vol.Optional(smart_home.CONF_DISPLAY_CATEGORIES): cv.string,
|
||||
|
10
homeassistant/components/alexa/manifest.json
Normal file
10
homeassistant/components/alexa/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "alexa",
|
||||
"name": "Alexa",
|
||||
"documentation": "https://www.home-assistant.io/components/alexa",
|
||||
"requirements": [],
|
||||
"dependencies": [
|
||||
"http"
|
||||
],
|
||||
"codeowners": []
|
||||
}
|
0
homeassistant/components/alexa/services.yaml
Normal file
0
homeassistant/components/alexa/services.yaml
Normal file
12
homeassistant/components/alpha_vantage/manifest.json
Normal file
12
homeassistant/components/alpha_vantage/manifest.json
Normal 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"
|
||||
]
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Stock market information from Alpha Vantage."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
@ -15,8 +10,6 @@ from homeassistant.const import (
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
REQUIREMENTS = ['alpha_vantage==2.1.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_CLOSE = 'close'
|
||||
|
12
homeassistant/components/amazon_polly/manifest.json
Normal file
12
homeassistant/components/amazon_polly/manifest.json
Normal 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"
|
||||
]
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for the Amazon Polly text to speech service."""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
@ -11,8 +6,6 @@ import voluptuous as vol
|
||||
from homeassistant.components.tts import PLATFORM_SCHEMA, Provider
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['boto3==1.9.16']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_REGION = 'region_name'
|
||||
|
@ -1,9 +1,19 @@
|
||||
{
|
||||
"config": {
|
||||
"error": {
|
||||
"identifier_exists": "La clave API y/o la clave de aplicaci\u00f3n ya est\u00e1 registrada",
|
||||
"invalid_key": "Clave API y/o clave de aplicaci\u00f3n no v\u00e1lida",
|
||||
"no_devices": "No se han encontrado dispositivos en la cuenta"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "Clave API",
|
||||
"app_key": "Clave de aplicaci\u00f3n"
|
||||
},
|
||||
"title": "Completa tu informaci\u00f3n"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Ambient PWS"
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
},
|
||||
"title": "Veuillez saisir vos informations"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Ambient PWS"
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
"api_key": "API \ud0a4",
|
||||
"app_key": "Application \ud0a4"
|
||||
},
|
||||
"title": "\uc0ac\uc6a9\uc790 \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694"
|
||||
"title": "\uc0ac\uc6a9\uc790 \uc815\ubcf4 \uc785\ub825"
|
||||
}
|
||||
},
|
||||
"title": "Ambient PWS"
|
||||
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"config": {
|
||||
"error": {
|
||||
"no_devices": "\u0e44\u0e21\u0e48\u0e1e\u0e1a\u0e2d\u0e38\u0e1b\u0e01\u0e23\u0e13\u0e4c\u0e43\u0e14\u0e46 \u0e43\u0e19\u0e1a\u0e31\u0e0d\u0e0a\u0e35\u0e40\u0e25\u0e22"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
|
@ -20,8 +20,6 @@ from .const import (
|
||||
ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE,
|
||||
TYPE_BINARY_SENSOR, TYPE_SENSOR)
|
||||
|
||||
REQUIREMENTS = ['aioambient==0.2.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DATA_CONFIG = 'config'
|
||||
@ -329,6 +327,8 @@ class AmbientStation:
|
||||
"""Define a handler to fire when the websocket is connected."""
|
||||
_LOGGER.info('Connected to websocket')
|
||||
_LOGGER.debug('Watchdog starting')
|
||||
if self._watchdog_listener:
|
||||
self._watchdog_listener()
|
||||
self._watchdog_listener = async_call_later(
|
||||
self._hass, DEFAULT_WATCHDOG_SECONDS, _ws_reconnect)
|
||||
|
||||
|
@ -12,8 +12,6 @@ from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_BINARY_SENSOR
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['ambient_station']
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
|
12
homeassistant/components/ambient_station/manifest.json
Normal file
12
homeassistant/components/ambient_station/manifest.json
Normal 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"
|
||||
]
|
||||
}
|
@ -8,8 +8,6 @@ from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_SENSOR
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['ambient_station']
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
|
@ -7,14 +7,11 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD,
|
||||
CONF_SENSORS, CONF_SWITCHES, CONF_SCAN_INTERVAL, HTTP_BASIC_AUTHENTICATION)
|
||||
CONF_BINARY_SENSORS, CONF_SENSORS, CONF_SWITCHES, CONF_SCAN_INTERVAL,
|
||||
HTTP_BASIC_AUTHENTICATION)
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
|
||||
REQUIREMENTS = ['amcrest==1.2.7']
|
||||
DEPENDENCIES = ['ffmpeg']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_AUTHENTICATION = 'authentication'
|
||||
@ -52,9 +49,14 @@ STREAM_SOURCE_LIST = {
|
||||
'rtsp': 2,
|
||||
}
|
||||
|
||||
BINARY_SENSORS = {
|
||||
'motion_detected': 'Motion Detected'
|
||||
}
|
||||
|
||||
# Sensor types are defined like: Name, units, icon
|
||||
SENSOR_MOTION_DETECTOR = 'motion_detector'
|
||||
SENSORS = {
|
||||
'motion_detector': ['Motion Detected', None, 'mdi:run'],
|
||||
SENSOR_MOTION_DETECTOR: ['Motion Detected', None, 'mdi:run'],
|
||||
'sdcard': ['SD Used', '%', 'mdi:sd'],
|
||||
'ptz_preset': ['PTZ Preset', None, 'mdi:camera-iris'],
|
||||
}
|
||||
@ -65,28 +67,49 @@ SWITCHES = {
|
||||
'motion_recording': ['Motion Recording', 'mdi:record-rec']
|
||||
}
|
||||
|
||||
|
||||
def _deprecated_sensors(value):
|
||||
if SENSOR_MOTION_DETECTOR in value:
|
||||
_LOGGER.warning(
|
||||
'sensors option %s is deprecated. '
|
||||
'Please remove from your configuration and '
|
||||
'use binary_sensors option motion_detected instead.',
|
||||
SENSOR_MOTION_DETECTOR)
|
||||
return value
|
||||
|
||||
|
||||
def _has_unique_names(value):
|
||||
names = [camera[CONF_NAME] for camera in value]
|
||||
vol.Schema(vol.Unique())(names)
|
||||
return value
|
||||
|
||||
|
||||
AMCREST_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION):
|
||||
vol.All(vol.In(AUTHENTICATION_LIST)),
|
||||
vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION):
|
||||
vol.All(vol.In(RESOLUTION_LIST)),
|
||||
vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE):
|
||||
vol.All(vol.In(STREAM_SOURCE_LIST)),
|
||||
vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS):
|
||||
cv.string,
|
||||
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
|
||||
cv.time_period,
|
||||
vol.Optional(CONF_BINARY_SENSORS):
|
||||
vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)]),
|
||||
vol.Optional(CONF_SENSORS):
|
||||
vol.All(cv.ensure_list, [vol.In(SENSORS)], _deprecated_sensors),
|
||||
vol.Optional(CONF_SWITCHES):
|
||||
vol.All(cv.ensure_list, [vol.In(SWITCHES)]),
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.All(cv.ensure_list, [vol.Schema({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION):
|
||||
vol.All(vol.In(AUTHENTICATION_LIST)),
|
||||
vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION):
|
||||
vol.All(vol.In(RESOLUTION_LIST)),
|
||||
vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE):
|
||||
vol.All(vol.In(STREAM_SOURCE_LIST)),
|
||||
vol.Optional(CONF_FFMPEG_ARGUMENTS, 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)]),
|
||||
})])
|
||||
DOMAIN: vol.All(cv.ensure_list, [AMCREST_SCHEMA], _has_unique_names)
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
@ -94,20 +117,24 @@ def setup(hass, config):
|
||||
"""Set up the Amcrest IP Camera component."""
|
||||
from amcrest import AmcrestCamera, AmcrestError
|
||||
|
||||
hass.data[DATA_AMCREST] = {}
|
||||
hass.data.setdefault(DATA_AMCREST, {})
|
||||
amcrest_cams = config[DOMAIN]
|
||||
|
||||
for device in amcrest_cams:
|
||||
name = device[CONF_NAME]
|
||||
username = device[CONF_USERNAME]
|
||||
password = device[CONF_PASSWORD]
|
||||
|
||||
try:
|
||||
camera = AmcrestCamera(device.get(CONF_HOST),
|
||||
device.get(CONF_PORT),
|
||||
device.get(CONF_USERNAME),
|
||||
device.get(CONF_PASSWORD)).camera
|
||||
camera = AmcrestCamera(device[CONF_HOST],
|
||||
device[CONF_PORT],
|
||||
username,
|
||||
password).camera
|
||||
# pylint: disable=pointless-statement
|
||||
camera.current_time
|
||||
|
||||
except 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(
|
||||
'Error: {}<br />'
|
||||
'You will need to restart hass after fixing.'
|
||||
@ -116,23 +143,19 @@ def setup(hass, config):
|
||||
notification_id=NOTIFICATION_ID)
|
||||
continue
|
||||
|
||||
ffmpeg_arguments = device.get(CONF_FFMPEG_ARGUMENTS)
|
||||
name = device.get(CONF_NAME)
|
||||
resolution = RESOLUTION_LIST[device.get(CONF_RESOLUTION)]
|
||||
ffmpeg_arguments = device[CONF_FFMPEG_ARGUMENTS]
|
||||
resolution = RESOLUTION_LIST[device[CONF_RESOLUTION]]
|
||||
binary_sensors = device.get(CONF_BINARY_SENSORS)
|
||||
sensors = device.get(CONF_SENSORS)
|
||||
switches = device.get(CONF_SWITCHES)
|
||||
stream_source = STREAM_SOURCE_LIST[device.get(CONF_STREAM_SOURCE)]
|
||||
|
||||
username = device.get(CONF_USERNAME)
|
||||
password = device.get(CONF_PASSWORD)
|
||||
stream_source = STREAM_SOURCE_LIST[device[CONF_STREAM_SOURCE]]
|
||||
|
||||
# currently aiohttp only works with basic authentication
|
||||
# only valid for mjpeg streaming
|
||||
if username is not None and password is not None:
|
||||
if device.get(CONF_AUTHENTICATION) == HTTP_BASIC_AUTHENTICATION:
|
||||
authentication = aiohttp.BasicAuth(username, password)
|
||||
else:
|
||||
authentication = None
|
||||
if device[CONF_AUTHENTICATION] == HTTP_BASIC_AUTHENTICATION:
|
||||
authentication = aiohttp.BasicAuth(username, password)
|
||||
else:
|
||||
authentication = None
|
||||
|
||||
hass.data[DATA_AMCREST][name] = AmcrestDevice(
|
||||
camera, name, authentication, ffmpeg_arguments, stream_source,
|
||||
@ -143,6 +166,13 @@ def setup(hass, config):
|
||||
CONF_NAME: name,
|
||||
}, config)
|
||||
|
||||
if binary_sensors:
|
||||
discovery.load_platform(
|
||||
hass, 'binary_sensor', DOMAIN, {
|
||||
CONF_NAME: name,
|
||||
CONF_BINARY_SENSORS: binary_sensors
|
||||
}, config)
|
||||
|
||||
if sensors:
|
||||
discovery.load_platform(
|
||||
hass, 'sensor', DOMAIN, {
|
||||
@ -157,7 +187,7 @@ def setup(hass, config):
|
||||
CONF_SWITCHES: switches
|
||||
}, config)
|
||||
|
||||
return True
|
||||
return len(hass.data[DATA_AMCREST]) >= 1
|
||||
|
||||
|
||||
class AmcrestDevice:
|
||||
|
69
homeassistant/components/amcrest/binary_sensor.py
Normal file
69
homeassistant/components/amcrest/binary_sensor.py
Normal 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)
|
@ -3,7 +3,7 @@ import asyncio
|
||||
import logging
|
||||
|
||||
from homeassistant.components.camera import (
|
||||
Camera, SUPPORT_STREAM)
|
||||
Camera, SUPPORT_ON_OFF, SUPPORT_STREAM)
|
||||
from homeassistant.components.ffmpeg import DATA_FFMPEG
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.helpers.aiohttp_client import (
|
||||
@ -12,8 +12,6 @@ from homeassistant.helpers.aiohttp_client import (
|
||||
|
||||
from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT
|
||||
|
||||
DEPENDENCIES = ['amcrest', 'ffmpeg']
|
||||
|
||||
_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)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class AmcrestCam(Camera):
|
||||
"""An implementation of an Amcrest IP camera."""
|
||||
@ -39,18 +35,23 @@ class AmcrestCam(Camera):
|
||||
super(AmcrestCam, self).__init__()
|
||||
self._name = amcrest.name
|
||||
self._camera = amcrest.device
|
||||
self._base_url = self._camera.get_base_url()
|
||||
self._ffmpeg = hass.data[DATA_FFMPEG]
|
||||
self._ffmpeg_arguments = amcrest.ffmpeg_arguments
|
||||
self._stream_source = amcrest.stream_source
|
||||
self._resolution = amcrest.resolution
|
||||
self._token = self._auth = amcrest.authentication
|
||||
self._is_recording = False
|
||||
self._model = None
|
||||
self._snapshot_lock = asyncio.Lock()
|
||||
|
||||
async def async_camera_image(self):
|
||||
"""Return a still image response from the camera."""
|
||||
from amcrest import AmcrestError
|
||||
|
||||
if not self.is_on:
|
||||
_LOGGER.error(
|
||||
'Attempt to take snaphot when %s camera is off', self.name)
|
||||
return None
|
||||
async with self._snapshot_lock:
|
||||
try:
|
||||
# Send the request to snap a picture and return raw jpg data
|
||||
@ -59,7 +60,8 @@ class AmcrestCam(Camera):
|
||||
return response.data
|
||||
except AmcrestError as error:
|
||||
_LOGGER.error(
|
||||
'Could not get camera image due to error %s', error)
|
||||
'Could not get image from %s camera due to error: %s',
|
||||
self.name, error)
|
||||
return None
|
||||
|
||||
async def handle_async_mjpeg_stream(self, request):
|
||||
@ -94,6 +96,8 @@ class AmcrestCam(Camera):
|
||||
finally:
|
||||
await stream.close()
|
||||
|
||||
# Entity property overrides
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of this camera."""
|
||||
@ -102,9 +106,80 @@ class AmcrestCam(Camera):
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""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
|
||||
def stream_source(self):
|
||||
"""Return the source of the stream."""
|
||||
return self._camera.rtsp_url(typeno=self._resolution)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if on."""
|
||||
return self.is_streaming
|
||||
|
||||
# Other Entity method overrides
|
||||
|
||||
def update(self):
|
||||
"""Update entity status."""
|
||||
from amcrest import AmcrestError
|
||||
|
||||
_LOGGER.debug('Pulling data from %s camera', self.name)
|
||||
if self._model is None:
|
||||
try:
|
||||
self._model = self._camera.device_type.split('=')[-1].strip()
|
||||
except AmcrestError as error:
|
||||
_LOGGER.error(
|
||||
'Could not get %s camera model due to error: %s',
|
||||
self.name, error)
|
||||
self._model = ''
|
||||
try:
|
||||
self.is_streaming = self._camera.video_enabled
|
||||
self._is_recording = self._camera.record_mode == 'Manual'
|
||||
except AmcrestError as error:
|
||||
_LOGGER.error(
|
||||
'Could not get %s camera attributes due to error: %s',
|
||||
self.name, error)
|
||||
|
||||
# Other Camera method overrides
|
||||
|
||||
def turn_off(self):
|
||||
"""Turn off camera."""
|
||||
self._enable_video_stream(False)
|
||||
|
||||
def turn_on(self):
|
||||
"""Turn on camera."""
|
||||
self._enable_video_stream(True)
|
||||
|
||||
# Utility methods
|
||||
|
||||
def _enable_video_stream(self, enable):
|
||||
"""Enable or disable camera video stream."""
|
||||
from amcrest import AmcrestError
|
||||
|
||||
try:
|
||||
self._camera.video_enabled = enable
|
||||
except AmcrestError as error:
|
||||
_LOGGER.error(
|
||||
'Could not %s %s camera video stream due to error: %s',
|
||||
'enable' if enable else 'disable', self.name, error)
|
||||
else:
|
||||
self.is_streaming = enable
|
||||
self.schedule_update_ha_state()
|
||||
|
12
homeassistant/components/amcrest/manifest.json
Normal file
12
homeassistant/components/amcrest/manifest.json
Normal 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": []
|
||||
}
|
@ -7,8 +7,6 @@ from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import DATA_AMCREST, SENSORS
|
||||
|
||||
DEPENDENCIES = ['amcrest']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=10)
|
||||
@ -30,7 +28,6 @@ async def async_setup_platform(
|
||||
AmcrestSensor(amcrest.name, amcrest.device, sensor_type))
|
||||
|
||||
async_add_entities(amcrest_sensors, True)
|
||||
return True
|
||||
|
||||
|
||||
class AmcrestSensor(Entity):
|
||||
@ -75,19 +72,6 @@ class AmcrestSensor(Entity):
|
||||
"""Get the latest data and updates the state."""
|
||||
_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':
|
||||
self._state = self._camera.is_motion_detected
|
||||
self._attrs['Record Mode'] = self._camera.record_mode
|
||||
|
@ -8,8 +8,6 @@ from . import DATA_AMCREST, SWITCHES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['amcrest']
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
|
1
homeassistant/components/ampio/__init__.py
Normal file
1
homeassistant/components/ampio/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The Ampio component."""
|
95
homeassistant/components/ampio/air_quality.py
Normal file
95
homeassistant/components/ampio/air_quality.py
Normal 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()
|
10
homeassistant/components/ampio/manifest.json
Normal file
10
homeassistant/components/ampio/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "ampio",
|
||||
"name": "Ampio",
|
||||
"documentation": "https://www.home-assistant.io/components/ampio",
|
||||
"requirements": [
|
||||
"asmog==0.0.6"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -21,8 +21,6 @@ from homeassistant.util.dt import utcnow
|
||||
from homeassistant.components.mjpeg.camera import (
|
||||
CONF_MJPEG_URL, CONF_STILL_IMAGE_URL)
|
||||
|
||||
REQUIREMENTS = ['pydroid-ipcam==0.8']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_AUD_CONNS = 'Audio Connections'
|
||||
|
@ -3,8 +3,6 @@ from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
|
||||
from . import CONF_HOST, CONF_NAME, DATA_IP_WEBCAM, KEY_MAP, AndroidIPCamEntity
|
||||
|
||||
DEPENDENCIES = ['android_ip_webcam']
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
|
10
homeassistant/components/android_ip_webcam/manifest.json
Normal file
10
homeassistant/components/android_ip_webcam/manifest.json
Normal 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": []
|
||||
}
|
@ -5,8 +5,6 @@ from . import (
|
||||
CONF_HOST, CONF_NAME, CONF_SENSORS, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
|
||||
AndroidIPCamEntity)
|
||||
|
||||
DEPENDENCIES = ['android_ip_webcam']
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
|
@ -5,8 +5,6 @@ from . import (
|
||||
CONF_HOST, CONF_NAME, CONF_SWITCHES, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
|
||||
AndroidIPCamEntity)
|
||||
|
||||
DEPENDENCIES = ['android_ip_webcam']
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
|
@ -1,6 +1 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for functionality to interact with Android TV/Fire TV devices."""
|
||||
|
10
homeassistant/components/androidtv/manifest.json
Normal file
10
homeassistant/components/androidtv/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "androidtv",
|
||||
"name": "Androidtv",
|
||||
"documentation": "https://www.home-assistant.io/components/androidtv",
|
||||
"requirements": [
|
||||
"androidtv==0.0.15"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for functionality to interact with Android TV / Fire TV devices."""
|
||||
import functools
|
||||
import logging
|
||||
import voluptuous as vol
|
||||
@ -18,12 +13,11 @@ from homeassistant.const import (
|
||||
ATTR_COMMAND, ATTR_ENTITY_ID, CONF_DEVICE_CLASS, CONF_HOST, CONF_NAME,
|
||||
CONF_PORT, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING,
|
||||
STATE_STANDBY)
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
ANDROIDTV_DOMAIN = 'androidtv'
|
||||
|
||||
REQUIREMENTS = ['androidtv==0.0.14']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
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",
|
||||
device_name, host, adb_log)
|
||||
return
|
||||
raise PlatformNotReady
|
||||
|
||||
if host in hass.data[ANDROIDTV_DOMAIN]:
|
||||
_LOGGER.warning("Platform already setup on %s, skipping", host)
|
||||
@ -298,12 +292,12 @@ class ADBDevice(MediaPlayerDevice):
|
||||
@adb_decorator()
|
||||
def media_previous_track(self):
|
||||
"""Send previous track command (results in rewind)."""
|
||||
self.aftv.media_previous()
|
||||
self.aftv.media_previous_track()
|
||||
|
||||
@adb_decorator()
|
||||
def media_next_track(self):
|
||||
"""Send next track command (results in fast-forward)."""
|
||||
self.aftv.media_next()
|
||||
self.aftv.media_next_track()
|
||||
|
||||
@adb_decorator()
|
||||
def adb_command(self, cmd):
|
||||
@ -328,11 +322,10 @@ class AndroidTVDevice(ADBDevice):
|
||||
turn_off_command)
|
||||
|
||||
self._device = None
|
||||
self._muted = None
|
||||
self._device_properties = self.aftv.device_properties
|
||||
self._unique_id = 'androidtv-{}-{}'.format(
|
||||
name, self._device_properties['serialno'])
|
||||
self._volume = None
|
||||
self._is_volume_muted = None
|
||||
self._unique_id = self._device_properties.get('serialno')
|
||||
self._volume_level = None
|
||||
|
||||
@adb_decorator(override_available=True)
|
||||
def update(self):
|
||||
@ -349,16 +342,16 @@ class AndroidTVDevice(ADBDevice):
|
||||
if not self._available:
|
||||
return
|
||||
|
||||
# Get the `state`, `current_app`, and `running_apps`.
|
||||
state, self._current_app, self._device, self._muted, self._volume = \
|
||||
self.aftv.update()
|
||||
# Get the updated state and attributes.
|
||||
state, self._current_app, self._device, self._is_volume_muted, \
|
||||
self._volume_level = self.aftv.update()
|
||||
|
||||
self._state = ANDROIDTV_STATES[state]
|
||||
|
||||
@property
|
||||
def is_volume_muted(self):
|
||||
"""Boolean if volume is currently muted."""
|
||||
return self._muted
|
||||
return self._is_volume_muted
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
@ -378,7 +371,7 @@ class AndroidTVDevice(ADBDevice):
|
||||
@property
|
||||
def volume_level(self):
|
||||
"""Return the volume level."""
|
||||
return self._volume
|
||||
return self._volume_level
|
||||
|
||||
@adb_decorator()
|
||||
def media_stop(self):
|
||||
@ -393,12 +386,12 @@ class AndroidTVDevice(ADBDevice):
|
||||
@adb_decorator()
|
||||
def volume_down(self):
|
||||
"""Send volume down command."""
|
||||
self.aftv.volume_down()
|
||||
self._volume_level = self.aftv.volume_down(self._volume_level)
|
||||
|
||||
@adb_decorator()
|
||||
def volume_up(self):
|
||||
"""Send volume up command."""
|
||||
self.aftv.volume_up()
|
||||
self._volume_level = self.aftv.volume_up(self._volume_level)
|
||||
|
||||
|
||||
class FireTVDevice(ADBDevice):
|
||||
|
10
homeassistant/components/anel_pwrctrl/manifest.json
Normal file
10
homeassistant/components/anel_pwrctrl/manifest.json
Normal 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": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
Support for ANEL PwrCtrl switches.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/switch.pwrctrl/
|
||||
"""
|
||||
"""Support for ANEL PwrCtrl switches."""
|
||||
import logging
|
||||
import socket
|
||||
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.util import Throttle
|
||||
|
||||
REQUIREMENTS = ['anel_pwrctrl-homeassistant==0.0.1.dev2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_PORT_RECV = 'port_recv'
|
||||
|
10
homeassistant/components/anthemav/manifest.json
Normal file
10
homeassistant/components/anthemav/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "anthemav",
|
||||
"name": "Anthemav",
|
||||
"documentation": "https://www.home-assistant.io/components/anthemav",
|
||||
"requirements": [
|
||||
"anthemav==1.1.10"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
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/
|
||||
"""
|
||||
"""Support for Anthem Network Receivers and Processors."""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
@ -18,8 +13,6 @@ from homeassistant.const import (
|
||||
STATE_ON)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['anthemav==1.1.10']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'anthemav'
|
||||
|
@ -8,8 +8,6 @@ from homeassistant.const import (CONF_HOST, CONF_PORT)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
REQUIREMENTS = ['apcaccess==0.0.13']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_TYPE = 'type'
|
||||
|
@ -8,8 +8,6 @@ import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components import apcupsd
|
||||
|
||||
DEFAULT_NAME = 'UPS Online Status'
|
||||
DEPENDENCIES = [apcupsd.DOMAIN]
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
})
|
||||
|
10
homeassistant/components/apcupsd/manifest.json
Normal file
10
homeassistant/components/apcupsd/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "apcupsd",
|
||||
"name": "Apcupsd",
|
||||
"documentation": "https://www.home-assistant.io/components/apcupsd",
|
||||
"requirements": [
|
||||
"apcaccess==0.0.13"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -11,8 +11,6 @@ from homeassistant.helpers.entity import Entity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = [apcupsd.DOMAIN]
|
||||
|
||||
SENSOR_PREFIX = 'UPS '
|
||||
SENSOR_TYPES = {
|
||||
'alarmdel': ['Alarm Delay', '', 'mdi:alarm'],
|
||||
|
@ -33,8 +33,6 @@ ATTR_REQUIRES_API_PASSWORD = 'requires_api_password'
|
||||
ATTR_VERSION = 'version'
|
||||
|
||||
DOMAIN = 'api'
|
||||
DEPENDENCIES = ['http']
|
||||
|
||||
STREAM_PING_PAYLOAD = 'ping'
|
||||
STREAM_PING_INTERVAL = 50 # seconds
|
||||
|
||||
|
12
homeassistant/components/api/manifest.json
Normal file
12
homeassistant/components/api/manifest.json
Normal 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"
|
||||
]
|
||||
}
|
0
homeassistant/components/api/services.yaml
Normal file
0
homeassistant/components/api/services.yaml
Normal file
@ -1 +0,0 @@
|
||||
"""The api_streams component."""
|
10
homeassistant/components/apns/manifest.json
Normal file
10
homeassistant/components/apns/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "apns",
|
||||
"name": "Apns",
|
||||
"documentation": "https://www.home-assistant.io/components/apns",
|
||||
"requirements": [
|
||||
"apns2==0.3.0"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
"""
|
||||
APNS Notification platform.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/notify.apns/
|
||||
"""
|
||||
"""APNS Notification platform."""
|
||||
import logging
|
||||
import os
|
||||
|
||||
@ -18,8 +13,6 @@ from homeassistant.helpers.event import track_state_change
|
||||
from homeassistant.components.notify import (
|
||||
ATTR_DATA, ATTR_TARGET, DOMAIN, PLATFORM_SCHEMA, BaseNotificationService)
|
||||
|
||||
REQUIREMENTS = ['apns2==0.3.0']
|
||||
|
||||
APNS_DEVICES = 'apns.yaml'
|
||||
CONF_CERTFILE = 'cert_file'
|
||||
CONF_TOPIC = 'topic'
|
||||
|
0
homeassistant/components/apns/services.yaml
Normal file
0
homeassistant/components/apns/services.yaml
Normal file
@ -11,8 +11,6 @@ from homeassistant.helpers import discovery
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['pyatv==0.3.12']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'apple_tv'
|
||||
|
10
homeassistant/components/apple_tv/manifest.json
Normal file
10
homeassistant/components/apple_tv/manifest.json
Normal 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": []
|
||||
}
|
@ -14,8 +14,6 @@ import homeassistant.util.dt as dt_util
|
||||
|
||||
from . import ATTR_ATV, ATTR_POWER, DATA_APPLE_TV, DATA_ENTITIES
|
||||
|
||||
DEPENDENCIES = ['apple_tv']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
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
Loading…
x
Reference in New Issue
Block a user