Merge pull request #22688 from home-assistant/rc

0.91.0
This commit is contained in:
Paulus Schoutsen 2019-04-03 14:39:21 -07:00 committed by GitHub
commit 360caa3b1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2276 changed files with 18488 additions and 7640 deletions

262
.circleci/config.yml Normal file
View File

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

File diff suppressed because it is too large Load Diff

1
.gitignore vendored
View File

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

View File

@ -18,7 +18,7 @@ homeassistant/components/frontend/* @home-assistant/core
homeassistant/components/group/* @home-assistant/core homeassistant/components/group/* @home-assistant/core
homeassistant/components/history/* @home-assistant/core homeassistant/components/history/* @home-assistant/core
homeassistant/components/http/* @home-assistant/core homeassistant/components/http/* @home-assistant/core
homeassistant/components/input_*.py @home-assistant/core homeassistant/components/input_*/* @home-assistant/core
homeassistant/components/introduction/* @home-assistant/core homeassistant/components/introduction/* @home-assistant/core
homeassistant/components/logger/* @home-assistant/core homeassistant/components/logger/* @home-assistant/core
homeassistant/components/lovelace/* @home-assistant/core homeassistant/components/lovelace/* @home-assistant/core
@ -47,123 +47,58 @@ homeassistant/components/*/zwave.py @home-assistant/z-wave
homeassistant/components/hassio/* @home-assistant/hassio homeassistant/components/hassio/* @home-assistant/hassio
# Individual platforms # Individual platforms
homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell homeassistant/components/notify/aws_lambda.py @robbiet480
homeassistant/components/binary_sensor/hikvision.py @mezz64 homeassistant/components/notify/aws_sns.py @robbiet480
homeassistant/components/binary_sensor/threshold.py @fabaff homeassistant/components/notify/aws_sqs.py @robbiet480
homeassistant/components/binary_sensor/uptimerobot.py @ludeeus
homeassistant/components/camera/push.py @dgomes
homeassistant/components/camera/yi.py @bachya
homeassistant/components/climate/coolmaster.py @OnFreund
homeassistant/components/climate/ephember.py @ttroy50
homeassistant/components/climate/eq3btsmart.py @rytilahti
homeassistant/components/climate/mill.py @danielhiversen
homeassistant/components/climate/sensibo.py @andrey-git
homeassistant/components/cover/brunt.py @eavanvalkenburg
homeassistant/components/cover/group.py @cdce8p
homeassistant/components/cover/template.py @PhracturedBlue
homeassistant/components/device_tracker/asuswrt.py @kennedyshead
homeassistant/components/device_tracker/automatic.py @armills
homeassistant/components/device_tracker/bt_smarthub.py @jxwolstenholme
homeassistant/components/device_tracker/huawei_router.py @abmantis
homeassistant/components/device_tracker/quantum_gateway.py @cisasteelersfan
homeassistant/components/device_tracker/tile.py @bachya
homeassistant/components/device_tracker/traccar.py @ludeeus
homeassistant/components/device_tracker/synology_srm.py @aerialls
homeassistant/components/device_tracker/xfinity.py @cisasteelersfan
homeassistant/components/light/lifx_legacy.py @amelchio
homeassistant/components/light/yeelight.py @rytilahti
homeassistant/components/light/yeelightsunflower.py @lindsaymarkward
homeassistant/components/lock/nello.py @pschmitt
homeassistant/components/lock/nuki.py @pschmitt
homeassistant/components/media_player/emby.py @mezz64
homeassistant/components/media_player/kodi.py @armills
homeassistant/components/media_player/liveboxplaytv.py @pschmitt
homeassistant/components/media_player/mediaroom.py @dgomes
homeassistant/components/media_player/monoprice.py @etsinko
homeassistant/components/media_player/mpd.py @fabaff
homeassistant/components/media_player/xiaomi_tv.py @fattdev
homeassistant/components/media_player/yamaha_musiccast.py @jalmeroth
homeassistant/components/notify/file.py @fabaff homeassistant/components/notify/file.py @fabaff
homeassistant/components/notify/flock.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/mastodon.py @fabaff
homeassistant/components/notify/smtp.py @fabaff homeassistant/components/notify/smtp.py @fabaff
homeassistant/components/notify/syslog.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/xmpp.py @fabaff
homeassistant/components/notify/yessssms.py @flowolf homeassistant/components/notify/yessssms.py @flowolf
homeassistant/components/scene/lifx_cloud.py @amelchio homeassistant/components/tts/amazon_polly.py @robbiet480
homeassistant/components/sensor/airvisual.py @bachya
homeassistant/components/sensor/alpha_vantage.py @fabaff
homeassistant/components/sensor/bitcoin.py @fabaff
homeassistant/components/sensor/cpuspeed.py @fabaff
homeassistant/components/sensor/cups.py @fabaff
homeassistant/components/sensor/darksky.py @fabaff
homeassistant/components/sensor/discogs.py @thibmaek
homeassistant/components/sensor/file.py @fabaff
homeassistant/components/sensor/filter.py @dgomes
homeassistant/components/sensor/fixer.py @fabaff
homeassistant/components/sensor/flunearyou.py @bachya
homeassistant/components/sensor/gearbest.py @HerrHofrat
homeassistant/components/sensor/gitter.py @fabaff
homeassistant/components/sensor/glances.py @fabaff
homeassistant/components/sensor/gpsd.py @fabaff
homeassistant/components/sensor/integration.py @dgomes
homeassistant/components/sensor/irish_rail_transport.py @ttroy50
homeassistant/components/sensor/jewish_calendar.py @tsvi
homeassistant/components/sensor/launch_library.py @ludeeus
homeassistant/components/sensor/linux_battery.py @fabaff
homeassistant/components/sensor/miflora.py @danielhiversen @ChristianKuehnel
homeassistant/components/sensor/min_max.py @fabaff
homeassistant/components/sensor/moon.py @fabaff
homeassistant/components/sensor/netdata.py @fabaff
homeassistant/components/sensor/nmbs.py @thibmaek
homeassistant/components/sensor/nsw_fuel_station.py @nickw444
homeassistant/components/sensor/pi_hole.py @fabaff
homeassistant/components/sensor/pollen.py @bachya
homeassistant/components/sensor/pvoutput.py @fabaff
homeassistant/components/sensor/qnap.py @colinodell
homeassistant/components/sensor/ruter.py @ludeeus
homeassistant/components/sensor/scrape.py @fabaff
homeassistant/components/sensor/serial.py @fabaff
homeassistant/components/sensor/seventeentrack.py @bachya
homeassistant/components/sensor/shodan.py @fabaff
homeassistant/components/sensor/sma.py @kellerza
homeassistant/components/sensor/sql.py @dgomes
homeassistant/components/sensor/statistics.py @fabaff
homeassistant/components/sensor/swiss*.py @fabaff
homeassistant/components/sensor/sytadin.py @gautric
homeassistant/components/sensor/tautulli.py @ludeeus
homeassistant/components/sensor/time_date.py @fabaff
homeassistant/components/sensor/version.py @fabaff
homeassistant/components/sensor/waqi.py @andrey-git
homeassistant/components/sensor/worldclock.py @fabaff
homeassistant/components/switch/switchbot.py @danielhiversen
homeassistant/components/switch/switchmate.py @danielhiversen
homeassistant/components/vacuum/roomba.py @pschmitt
homeassistant/components/weather/__init__.py @fabaff
homeassistant/components/weather/darksky.py @fabaff
homeassistant/components/weather/demo.py @fabaff
homeassistant/components/weather/met.py @danielhiversen
homeassistant/components/weather/openweathermap.py @fabaff
# A # A
homeassistant/components/airvisual/sensor.py @bachya
homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell
homeassistant/components/alpha_vantage/sensor.py @fabaff
homeassistant/components/ambient_station/* @bachya homeassistant/components/ambient_station/* @bachya
homeassistant/components/arduino/* @fabaff homeassistant/components/arduino/* @fabaff
homeassistant/components/arest/* @fabaff
homeassistant/components/asuswrt/device_tracker.py @kennedyshead
homeassistant/components/automatic/device_tracker.py @armills
homeassistant/components/axis/* @kane610 homeassistant/components/axis/* @kane610
homeassistant/components/*/arest.py @fabaff
# B # B
homeassistant/components/bitcoin/sensor.py @fabaff
homeassistant/components/blink/* @fronzbot homeassistant/components/blink/* @fronzbot
homeassistant/components/bmw_connected_drive/* @ChristianKuehnel homeassistant/components/bmw_connected_drive/* @ChristianKuehnel
homeassistant/components/*/broadlink.py @danielhiversen homeassistant/components/braviatv/media_player.py @robbiet480
homeassistant/components/broadlink/* @danielhiversen
homeassistant/components/brunt/cover.py @eavanvalkenburg
homeassistant/components/bt_smarthub/device_tracker.py @jxwolstenholme
# C # C
homeassistant/components/cloudflare/* @ludeeus homeassistant/components/cloudflare/* @ludeeus
homeassistant/components/coolmaster/climate.py @OnFreund
homeassistant/components/counter/* @fabaff homeassistant/components/counter/* @fabaff
homeassistant/components/cover/group.py @cdce8p
homeassistant/components/cpuspeed/sensor.py @fabaff
homeassistant/components/cups/sensor.py @fabaff
# D # D
homeassistant/components/daikin/* @fredrike @rofrantz homeassistant/components/daikin/* @fredrike @rofrantz
homeassistant/components/darksky/* @fabaff
homeassistant/components/discogs/sensor.py @thibmaek
homeassistant/components/deconz/* @kane610 homeassistant/components/deconz/* @kane610
homeassistant/components/demo/weather.py @fabaff
homeassistant/components/digital_ocean/* @fabaff homeassistant/components/digital_ocean/* @fabaff
homeassistant/components/doorbird/* @oblogic7
homeassistant/components/dweet/* @fabaff homeassistant/components/dweet/* @fabaff
# E # E
@ -171,94 +106,185 @@ homeassistant/components/ecovacs/* @OverloadUT
homeassistant/components/edp_redy/* @abmantis homeassistant/components/edp_redy/* @abmantis
homeassistant/components/eight_sleep/* @mezz64 homeassistant/components/eight_sleep/* @mezz64
homeassistant/components/egardia/* @jeroenterheerdt homeassistant/components/egardia/* @jeroenterheerdt
homeassistant/components/esphome/*.py @OttoWinter homeassistant/components/emby/media_player.py @mezz64
homeassistant/components/ephember/climate.py @ttroy50
homeassistant/components/eq3btsmart/climate.py @rytilahti
homeassistant/components/esphome/* @OttoWinter
# F # F
homeassistant/components/freebox/*.py @snoof85 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/foursquare/* @robbiet480
homeassistant/components/freebox/* @snoof85
# G # 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/googlehome/* @ludeeus homeassistant/components/googlehome/* @ludeeus
homeassistant/components/gpsd/sensor.py @fabaff
homeassistant/components/gtfs/sensor.py @robbiet480
# H # H
homeassistant/components/harmony/* @ehendrix23 homeassistant/components/harmony/* @ehendrix23
homeassistant/components/hikvision/binary_sensor.py @mezz64
homeassistant/components/history_graph/* @andrey-git homeassistant/components/history_graph/* @andrey-git
homeassistant/components/hive/* @Rendili @KJonline homeassistant/components/hive/* @Rendili @KJonline
homeassistant/components/homekit/* @cdce8p homeassistant/components/homekit/* @cdce8p
homeassistant/components/huawei_lte/* @scop homeassistant/components/huawei_lte/* @scop
homeassistant/components/huawei_router/device_tracker.py @abmantis
# I # I
homeassistant/components/influx/* @fabaff homeassistant/components/influxdb/* @fabaff
homeassistant/components/integration/sensor.py @dgomes
homeassistant/components/ios/* @robbiet480
homeassistant/components/ipma/* @dgomes homeassistant/components/ipma/* @dgomes
homeassistant/components/irish_rail_transport/sensor.py @ttroy50
# J
homeassistant/components/jewish_calendar/sensor.py @tsvi
# K # K
homeassistant/components/knx/* @Julius2342 homeassistant/components/knx/* @Julius2342
homeassistant/components/kodi/media_player.py @armills
homeassistant/components/konnected/* @heythisisnate homeassistant/components/konnected/* @heythisisnate
# L # L
homeassistant/components/lametric/notify.py @robbiet480
homeassistant/components/launch_library/sensor.py @ludeeus
homeassistant/components/lifx/* @amelchio homeassistant/components/lifx/* @amelchio
homeassistant/components/lifx_cloud/scene.py @amelchio
homeassistant/components/lifx_legacy/light.py @amelchio
homeassistant/components/linux_battery/sensor.py @fabaff
homeassistant/components/liveboxplaytv/media_player.py @pschmitt
homeassistant/components/luftdaten/* @fabaff homeassistant/components/luftdaten/* @fabaff
# M # M
homeassistant/components/matrix/* @tinloaf homeassistant/components/matrix/* @tinloaf
homeassistant/components/mediaroom/media_player.py @dgomes
homeassistant/components/melissa/* @kennedyshead homeassistant/components/melissa/* @kennedyshead
homeassistant/components/*/melissa.py @kennedyshead homeassistant/components/met/weather.py @danielhiversen
homeassistant/components/*/mystrom.py @fabaff homeassistant/components/miflora/sensor.py @danielhiversen @ChristianKuehnel
homeassistant/components/mill/climate.py @danielhiversen
homeassistant/components/min_max/sensor.py @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/mystrom/* @fabaff
# N # N
homeassistant/components/nello/lock.py @pschmitt
homeassistant/components/ness_alarm/* @nickw444 homeassistant/components/ness_alarm/* @nickw444
homeassistant/components/*/ness_alarm.py @nickw444 homeassistant/components/netdata/sensor.py @fabaff
homeassistant/components/nissan_leaf/* @filcole homeassistant/components/nissan_leaf/* @filcole
homeassistant/components/nmbs/sensor.py @thibmaek
homeassistant/components/no_ip/* @fabaff homeassistant/components/no_ip/* @fabaff
homeassistant/components/nuki/lock.py @pschmitt
homeassistant/components/nsw_fuel_station/sensor.py @nickw444
# O # O
homeassistant/components/ohmconnect/sensor.py @robbiet480
homeassistant/components/openuv/* @bachya homeassistant/components/openuv/* @bachya
homeassistant/components/openweathermap/weather.py @fabaff
homeassistant/components/owlet/* @oblogic7
# P # P
homeassistant/components/pi_hole/sensor.py @fabaff
homeassistant/components/plant/* @ChristianKuehnel homeassistant/components/plant/* @ChristianKuehnel
homeassistant/components/point/* @fredrike homeassistant/components/point/* @fredrike
homeassistant/components/pollen/sensor.py @bachya
homeassistant/components/push/camera.py @dgomes
homeassistant/components/pvoutput/sensor.py @fabaff
# Q # Q
homeassistant/components/qnap/sensor.py @colinodell
homeassistant/components/quantum_gateway/device_tracker.py @cisasteelersfan
homeassistant/components/qwikswitch/* @kellerza homeassistant/components/qwikswitch/* @kellerza
# R # R
homeassistant/components/rainmachine/* @bachya homeassistant/components/rainmachine/* @bachya
homeassistant/components/random/* @fabaff
homeassistant/components/rfxtrx/* @danielhiversen homeassistant/components/rfxtrx/* @danielhiversen
homeassistant/components/*/random.py @fabaff homeassistant/components/rmvtransport/* @cgtobi
homeassistant/components/roomba/vacuum.py @pschmitt
homeassistant/components/ruter/sensor.py @ludeeus
# S # 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/shiftr/* @fabaff homeassistant/components/shiftr/* @fabaff
homeassistant/components/shodan/sensor.py @fabaff
homeassistant/components/simplisafe/* @bachya homeassistant/components/simplisafe/* @bachya
homeassistant/components/sma/sensor.py @kellerza
homeassistant/components/smartthings/* @andrewsayre homeassistant/components/smartthings/* @andrewsayre
homeassistant/components/sonos/* @amelchio homeassistant/components/sonos/* @amelchio
homeassistant/components/spaceapi/* @fabaff homeassistant/components/spaceapi/* @fabaff
homeassistant/components/spider/* @peternijssen homeassistant/components/spider/* @peternijssen
homeassistant/components/sql/sensor.py @dgomes
homeassistant/components/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 # T
homeassistant/components/tahoma/* @philklei homeassistant/components/tahoma/* @philklei
homeassistant/components/tellduslive/*.py @fredrike homeassistant/components/tautulli/sensor.py @ludeeus
homeassistant/components/tellduslive/* @fredrike
homeassistant/components/template/cover.py @PhracturedBlue
homeassistant/components/tesla/* @zabuldon homeassistant/components/tesla/* @zabuldon
homeassistant/components/tfiac/* @fredrike @mellado
homeassistant/components/thethingsnetwork/* @fabaff homeassistant/components/thethingsnetwork/* @fabaff
homeassistant/components/threshold/binary_sensor.py @fabaff
homeassistant/components/tibber/* @danielhiversen homeassistant/components/tibber/* @danielhiversen
homeassistant/components/tplink/* @rytilahti homeassistant/components/tile/device_tracker.py @bachya
homeassistant/components/tradfri/* @ggravlingen homeassistant/components/time_date/sensor.py @fabaff
homeassistant/components/toon/* @frenck homeassistant/components/toon/* @frenck
homeassistant/components/tplink/* @rytilahti
homeassistant/components/traccar/device_tracker.py @ludeeus
homeassistant/components/tradfri/* @ggravlingen
# U # U
homeassistant/components/uber/sensor.py @robbiet480
homeassistant/components/unifi/* @kane610 homeassistant/components/unifi/* @kane610
homeassistant/components/upcloud/* @scop homeassistant/components/upcloud/* @scop
homeassistant/components/upnp/* @robbiet480
homeassistant/components/uptimerobot/binary_sensor.py @ludeeus
homeassistant/components/utility_meter/* @dgomes homeassistant/components/utility_meter/* @dgomes
# V # V
homeassistant/components/velux/* @Julius2342 homeassistant/components/velux/* @Julius2342
homeassistant/components/version/sensor.py @fabaff
# W # W
homeassistant/components/waqi/sensor.py @andrey-git
homeassistant/components/weather/__init__.py @fabaff
homeassistant/components/wemo/* @sqldiablo homeassistant/components/wemo/* @sqldiablo
homeassistant/components/worldclock/sensor.py @fabaff
# X # X
homeassistant/components/xfinity/device_tracker.py @cisasteelersfan
homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi
homeassistant/components/xiaomi_miio/* @rytilahti @syssi homeassistant/components/xiaomi_miio/* @rytilahti @syssi
homeassistant/components/xiaomi_tv/media_player.py @fattdev
# Y
homeassistant/components/yamaha_musiccast/* @jalmeroth
homeassistant/components/yeelight/* @rytilahti @zewelor
homeassistant/components/yeelightsunflower/light.py @lindsaymarkward
homeassistant/components/yi/camera.py @bachya
# Z # Z
homeassistant/components/zeroconf/* @robbiet480
homeassistant/components/zha/* @dmulcahey @adminiuga
homeassistant/components/zoneminder/* @rohankapoorcom homeassistant/components/zoneminder/* @rohankapoorcom
# Other code # Other code

View File

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

View File

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

View File

@ -1,4 +1,5 @@
"""Provide methods to bootstrap a Home Assistant instance.""" """Provide methods to bootstrap a Home Assistant instance."""
import asyncio
import logging import logging
import logging.handlers import logging.handlers
import os import os
@ -9,10 +10,10 @@ from typing import Any, Optional, Dict, Set
import voluptuous as vol import voluptuous as vol
from homeassistant import ( from homeassistant import core, config as conf_util, config_entries, loader
core, config as conf_util, config_entries, components as core_components, from homeassistant.components import (
loader) persistent_notification, homeassistant as core_component
from homeassistant.components import persistent_notification )
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.logging import AsyncHandler from homeassistant.util.logging import AsyncHandler
@ -139,7 +140,7 @@ async def async_from_config_dict(config: Dict[str, Any],
pass pass
# setup components # setup components
res = await core_components.async_setup(hass, config) res = await core_component.async_setup(hass, config)
if not res: if not res:
_LOGGER.error("Home Assistant core failed to initialize. " _LOGGER.error("Home Assistant core failed to initialize. "
"Further initialization aborted") "Further initialization aborted")
@ -157,6 +158,12 @@ async def async_from_config_dict(config: Dict[str, Any],
await hass.async_block_till_done() 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 # stage 1
for component in components: for component in components:
if component in FIRST_INIT_COMPONENT: if component in FIRST_INIT_COMPONENT:

View File

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

View File

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

View File

@ -1,10 +1,10 @@
"""Support for Abode Security System binary sensors.""" """Support for Abode Security System binary sensors."""
import logging import logging
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
DOMAIN as ABODE_DOMAIN)
from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.binary_sensor import BinarySensorDevice
from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['abode'] DEPENDENCIES = ['abode']

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +1,11 @@
"""Support for Abode Security System sensors.""" """Support for Abode Security System sensors."""
import logging import logging
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
from homeassistant.const import ( from homeassistant.const import (
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE) DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE)
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['abode'] DEPENDENCIES = ['abode']

View File

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

View File

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

View File

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

View File

@ -3,12 +3,13 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.ads import CONF_ADS_VAR, DATA_ADS
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA, BinarySensorDevice) DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA, BinarySensorDevice)
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, DATA_ADS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'ADS binary sensor' DEFAULT_NAME = 'ADS binary sensor'

View File

@ -1,13 +1,15 @@
"""Support for ADS light sources.""" """Support for ADS light sources."""
import logging import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.light import Light, ATTR_BRIGHTNESS, \
SUPPORT_BRIGHTNESS, PLATFORM_SCHEMA from homeassistant.components.light import (
ATTR_BRIGHTNESS, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, Light)
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
from homeassistant.components.ads import DATA_ADS, CONF_ADS_VAR, \
CONF_ADS_VAR_BRIGHTNESS
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ads'] DEPENDENCIES = ['ads']
DEFAULT_NAME = 'ADS Light' DEFAULT_NAME = 'ADS Light'

View File

@ -4,13 +4,13 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components import ads from homeassistant.components import ads
from homeassistant.components.ads import (
CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR)
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "ADS sensor" DEFAULT_NAME = "ADS sensor"

View File

@ -3,12 +3,13 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.ads import CONF_ADS_VAR, DATA_ADS
from homeassistant.components.switch import PLATFORM_SCHEMA from homeassistant.components.switch import PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from . import CONF_ADS_VAR, DATA_ADS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['ads'] DEPENDENCIES = ['ads']

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,8 @@
import logging import logging
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.components.alarmdecoder import (SIGNAL_PANEL_MESSAGE)
from . import SIGNAL_PANEL_MESSAGE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.tts import Provider, PLATFORM_SCHEMA from homeassistant.components.tts import PLATFORM_SCHEMA, Provider
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['boto3==1.9.16'] REQUIREMENTS = ['boto3==1.9.16']

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
"""Support for Ambient Weather Station binary sensors.""" """Support for Ambient Weather Station binary sensors."""
import logging import logging
from homeassistant.components.ambient_station import (
SENSOR_TYPES, TYPE_BATT1, TYPE_BATT10, TYPE_BATT2, TYPE_BATT3, TYPE_BATT4,
TYPE_BATT5, TYPE_BATT6, TYPE_BATT7, TYPE_BATT8, TYPE_BATT9, TYPE_BATTOUT,
AmbientWeatherEntity)
from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.const import ATTR_NAME from homeassistant.const import ATTR_NAME
from . import (
SENSOR_TYPES, TYPE_BATT1, TYPE_BATT2, TYPE_BATT3, TYPE_BATT4, TYPE_BATT5,
TYPE_BATT6, TYPE_BATT7, TYPE_BATT8, TYPE_BATT9, TYPE_BATT10, TYPE_BATTOUT,
AmbientWeatherEntity)
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_BINARY_SENSOR from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_BINARY_SENSOR
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -1,10 +1,9 @@
"""Support for Ambient Weather Station sensors.""" """Support for Ambient Weather Station sensors."""
import logging import logging
from homeassistant.components.ambient_station import (
SENSOR_TYPES, AmbientWeatherEntity)
from homeassistant.const import ATTR_NAME from homeassistant.const import ATTR_NAME
from . import SENSOR_TYPES, AmbientWeatherEntity
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_SENSOR from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_SENSOR
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -4,8 +4,6 @@ from datetime import timedelta
import aiohttp import aiohttp
import voluptuous as vol import voluptuous as vol
from requests.exceptions import HTTPError, ConnectTimeout
from requests.exceptions import ConnectionError as ConnectError
from homeassistant.const import ( from homeassistant.const import (
CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD, CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD,
@ -13,7 +11,8 @@ from homeassistant.const import (
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['amcrest==1.2.5']
REQUIREMENTS = ['amcrest==1.2.7']
DEPENDENCIES = ['ffmpeg'] DEPENDENCIES = ['ffmpeg']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -27,6 +26,7 @@ DEFAULT_NAME = 'Amcrest Camera'
DEFAULT_PORT = 80 DEFAULT_PORT = 80
DEFAULT_RESOLUTION = 'high' DEFAULT_RESOLUTION = 'high'
DEFAULT_STREAM_SOURCE = 'snapshot' DEFAULT_STREAM_SOURCE = 'snapshot'
DEFAULT_ARGUMENTS = '-pred 1'
TIMEOUT = 10 TIMEOUT = 10
DATA_AMCREST = 'amcrest' DATA_AMCREST = 'amcrest'
@ -78,7 +78,8 @@ CONFIG_SCHEMA = vol.Schema({
vol.All(vol.In(RESOLUTION_LIST)), vol.All(vol.In(RESOLUTION_LIST)),
vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE): vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE):
vol.All(vol.In(STREAM_SOURCE_LIST)), vol.All(vol.In(STREAM_SOURCE_LIST)),
vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string, vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS):
cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
cv.time_period, cv.time_period,
vol.Optional(CONF_SENSORS): vol.Optional(CONF_SENSORS):
@ -91,7 +92,7 @@ CONFIG_SCHEMA = vol.Schema({
def setup(hass, config): def setup(hass, config):
"""Set up the Amcrest IP Camera component.""" """Set up the Amcrest IP Camera component."""
from amcrest import AmcrestCamera from amcrest import AmcrestCamera, AmcrestError
hass.data[DATA_AMCREST] = {} hass.data[DATA_AMCREST] = {}
amcrest_cams = config[DOMAIN] amcrest_cams = config[DOMAIN]
@ -105,7 +106,7 @@ def setup(hass, config):
# pylint: disable=pointless-statement # pylint: disable=pointless-statement
camera.current_time camera.current_time
except (ConnectError, ConnectTimeout, HTTPError) as ex: except AmcrestError as ex:
_LOGGER.error("Unable to connect to Amcrest camera: %s", str(ex)) _LOGGER.error("Unable to connect to Amcrest camera: %s", str(ex))
hass.components.persistent_notification.create( hass.components.persistent_notification.create(
'Error: {}<br />' 'Error: {}<br />'

View File

@ -2,17 +2,15 @@
import asyncio import asyncio
import logging import logging
from requests import RequestException from homeassistant.components.camera import (
from urllib3.exceptions import ReadTimeoutError Camera, SUPPORT_STREAM)
from homeassistant.components.amcrest import (
DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT)
from homeassistant.components.camera import Camera
from homeassistant.components.ffmpeg import DATA_FFMPEG from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
from homeassistant.helpers.aiohttp_client import ( from homeassistant.helpers.aiohttp_client import (
async_get_clientsession, async_aiohttp_proxy_web, async_aiohttp_proxy_stream, async_aiohttp_proxy_web,
async_aiohttp_proxy_stream) async_get_clientsession)
from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT
DEPENDENCIES = ['amcrest', 'ffmpeg'] DEPENDENCIES = ['amcrest', 'ffmpeg']
@ -51,13 +49,15 @@ class AmcrestCam(Camera):
async def async_camera_image(self): async def async_camera_image(self):
"""Return a still image response from the camera.""" """Return a still image response from the camera."""
from amcrest import AmcrestError
async with self._snapshot_lock: async with self._snapshot_lock:
try: try:
# Send the request to snap a picture and return raw jpg data # Send the request to snap a picture and return raw jpg data
response = await self.hass.async_add_executor_job( response = await self.hass.async_add_executor_job(
self._camera.snapshot, self._resolution) self._camera.snapshot, self._resolution)
return response.data return response.data
except (RequestException, ReadTimeoutError, ValueError) as error: except AmcrestError as error:
_LOGGER.error( _LOGGER.error(
'Could not get camera image due to error %s', error) 'Could not get camera image due to error %s', error)
return None return None
@ -79,7 +79,7 @@ class AmcrestCam(Camera):
self.hass, request, stream_coro) self.hass, request, stream_coro)
# streaming via ffmpeg # streaming via ffmpeg
from haffmpeg import CameraMjpeg from haffmpeg.camera import CameraMjpeg
streaming_url = self._camera.rtsp_url(typeno=self._resolution) streaming_url = self._camera.rtsp_url(typeno=self._resolution)
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop) stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
@ -87,8 +87,9 @@ class AmcrestCam(Camera):
streaming_url, extra_cmd=self._ffmpeg_arguments) streaming_url, extra_cmd=self._ffmpeg_arguments)
try: try:
stream_reader = await stream.get_reader()
return await async_aiohttp_proxy_stream( return await async_aiohttp_proxy_stream(
self.hass, request, stream, self.hass, request, stream_reader,
self._ffmpeg.ffmpeg_stream_content_type) self._ffmpeg.ffmpeg_stream_content_type)
finally: finally:
await stream.close() await stream.close()
@ -98,6 +99,11 @@ class AmcrestCam(Camera):
"""Return the name of this camera.""" """Return the name of this camera."""
return self._name return self._name
@property
def supported_features(self):
"""Return supported features."""
return SUPPORT_STREAM
@property @property
def stream_source(self): def stream_source(self):
"""Return the source of the stream.""" """Return the source of the stream."""

View File

@ -2,9 +2,10 @@
from datetime import timedelta from datetime import timedelta
import logging import logging
from homeassistant.components.amcrest import DATA_AMCREST, SENSORS
from homeassistant.helpers.entity import Entity
from homeassistant.const import CONF_NAME, CONF_SENSORS from homeassistant.const import CONF_NAME, CONF_SENSORS
from homeassistant.helpers.entity import Entity
from . import DATA_AMCREST, SENSORS
DEPENDENCIES = ['amcrest'] DEPENDENCIES = ['amcrest']

View File

@ -1,11 +1,11 @@
"""Support for toggling Amcrest IP camera settings.""" """Support for toggling Amcrest IP camera settings."""
import logging import logging
from homeassistant.components.amcrest import DATA_AMCREST, SWITCHES from homeassistant.const import CONF_NAME, CONF_SWITCHES, STATE_OFF, STATE_ON
from homeassistant.const import (
CONF_NAME, CONF_SWITCHES, STATE_OFF, STATE_ON)
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from . import DATA_AMCREST, SWITCHES
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['amcrest'] DEPENDENCIES = ['amcrest']

View File

@ -18,7 +18,7 @@ from homeassistant.helpers.dispatcher import (
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
from homeassistant.components.camera.mjpeg import ( from homeassistant.components.mjpeg.camera import (
CONF_MJPEG_URL, CONF_STILL_IMAGE_URL) CONF_MJPEG_URL, CONF_STILL_IMAGE_URL)
REQUIREMENTS = ['pydroid-ipcam==0.8'] REQUIREMENTS = ['pydroid-ipcam==0.8']

View File

@ -1,7 +1,7 @@
"""Support for Android IP Webcam binary sensors.""" """Support for Android IP Webcam binary sensors."""
from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.android_ip_webcam import (
KEY_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST, CONF_NAME) from . import CONF_HOST, CONF_NAME, DATA_IP_WEBCAM, KEY_MAP, AndroidIPCamEntity
DEPENDENCIES = ['android_ip_webcam'] DEPENDENCIES = ['android_ip_webcam']

View File

@ -1,9 +1,10 @@
"""Support for Android IP Webcam sensors.""" """Support for Android IP Webcam sensors."""
from homeassistant.components.android_ip_webcam import (
KEY_MAP, ICON_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST,
CONF_NAME, CONF_SENSORS)
from homeassistant.helpers.icon import icon_for_battery_level from homeassistant.helpers.icon import icon_for_battery_level
from . import (
CONF_HOST, CONF_NAME, CONF_SENSORS, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
AndroidIPCamEntity)
DEPENDENCIES = ['android_ip_webcam'] DEPENDENCIES = ['android_ip_webcam']

View File

@ -1,8 +1,9 @@
"""Support for Android IP Webcam settings.""" """Support for Android IP Webcam settings."""
from homeassistant.components.switch import SwitchDevice from homeassistant.components.switch import SwitchDevice
from homeassistant.components.android_ip_webcam import (
KEY_MAP, ICON_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST, from . import (
CONF_NAME, CONF_SWITCHES) CONF_HOST, CONF_NAME, CONF_SWITCHES, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
AndroidIPCamEntity)
DEPENDENCIES = ['android_ip_webcam'] DEPENDENCIES = ['android_ip_webcam']

View File

@ -22,7 +22,7 @@ import homeassistant.helpers.config_validation as cv
ANDROIDTV_DOMAIN = 'androidtv' ANDROIDTV_DOMAIN = 'androidtv'
REQUIREMENTS = ['androidtv==0.0.12'] REQUIREMENTS = ['androidtv==0.0.14']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -40,6 +40,8 @@ CONF_ADB_SERVER_IP = 'adb_server_ip'
CONF_ADB_SERVER_PORT = 'adb_server_port' CONF_ADB_SERVER_PORT = 'adb_server_port'
CONF_APPS = 'apps' CONF_APPS = 'apps'
CONF_GET_SOURCES = 'get_sources' CONF_GET_SOURCES = 'get_sources'
CONF_TURN_ON_COMMAND = 'turn_on_command'
CONF_TURN_OFF_COMMAND = 'turn_off_command'
DEFAULT_NAME = 'Android TV' DEFAULT_NAME = 'Android TV'
DEFAULT_PORT = 5555 DEFAULT_PORT = 5555
@ -59,27 +61,21 @@ SERVICE_ADB_COMMAND_SCHEMA = vol.Schema({
}) })
def has_adb_files(value):
"""Check that ADB key files exist."""
priv_key = value
pub_key = '{}.pub'.format(value)
cv.isfile(pub_key)
return cv.isfile(priv_key)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string, vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_DEVICE_CLASS, default=DEFAULT_DEVICE_CLASS): vol.Optional(CONF_DEVICE_CLASS, default=DEFAULT_DEVICE_CLASS):
vol.In(DEVICE_CLASSES), vol.In(DEVICE_CLASSES),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_ADBKEY): has_adb_files, vol.Optional(CONF_ADBKEY): cv.isfile,
vol.Optional(CONF_ADB_SERVER_IP): cv.string, vol.Optional(CONF_ADB_SERVER_IP): cv.string,
vol.Optional(CONF_ADB_SERVER_PORT, default=DEFAULT_ADB_SERVER_PORT): vol.Optional(CONF_ADB_SERVER_PORT, default=DEFAULT_ADB_SERVER_PORT):
cv.port, cv.port,
vol.Optional(CONF_GET_SOURCES, default=DEFAULT_GET_SOURCES): cv.boolean, vol.Optional(CONF_GET_SOURCES, default=DEFAULT_GET_SOURCES): cv.boolean,
vol.Optional(CONF_APPS, default=dict()): vol.Optional(CONF_APPS, default=dict()):
vol.Schema({cv.string: cv.string}) vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_TURN_ON_COMMAND): cv.string,
vol.Optional(CONF_TURN_OFF_COMMAND): cv.string
}) })
# Translate from `AndroidTV` / `FireTV` reported state to HA state. # Translate from `AndroidTV` / `FireTV` reported state to HA state.
@ -136,12 +132,16 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
else: else:
if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV: if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV:
device = AndroidTVDevice(aftv, config[CONF_NAME], device = AndroidTVDevice(aftv, config[CONF_NAME],
config[CONF_APPS]) config[CONF_APPS],
config.get(CONF_TURN_ON_COMMAND),
config.get(CONF_TURN_OFF_COMMAND))
device_name = config[CONF_NAME] if CONF_NAME in config \ device_name = config[CONF_NAME] if CONF_NAME in config \
else 'Android TV' else 'Android TV'
else: else:
device = FireTVDevice(aftv, config[CONF_NAME], config[CONF_APPS], device = FireTVDevice(aftv, config[CONF_NAME], config[CONF_APPS],
config[CONF_GET_SOURCES]) config[CONF_GET_SOURCES],
config.get(CONF_TURN_ON_COMMAND),
config.get(CONF_TURN_OFF_COMMAND))
device_name = config[CONF_NAME] if CONF_NAME in config \ device_name = config[CONF_NAME] if CONF_NAME in config \
else 'Fire TV' else 'Fire TV'
@ -163,7 +163,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
output = target_device.adb_command(cmd) output = target_device.adb_command(cmd)
# log the output if there is any # log the output if there is any
if output: if output and (not isinstance(output, str) or output.strip()):
_LOGGER.info("Output of command '%s' from '%s': %s", _LOGGER.info("Output of command '%s' from '%s': %s",
cmd, target_device.entity_id, repr(output)) cmd, target_device.entity_id, repr(output))
@ -199,7 +199,8 @@ def adb_decorator(override_available=False):
class ADBDevice(MediaPlayerDevice): class ADBDevice(MediaPlayerDevice):
"""Representation of an Android TV or Fire TV device.""" """Representation of an Android TV or Fire TV device."""
def __init__(self, aftv, name, apps): def __init__(self, aftv, name, apps, turn_on_command,
turn_off_command):
"""Initialize the Android TV / Fire TV device.""" """Initialize the Android TV / Fire TV device."""
from androidtv.constants import APPS, KEYS from androidtv.constants import APPS, KEYS
@ -209,6 +210,9 @@ class ADBDevice(MediaPlayerDevice):
self._apps.update(apps) self._apps.update(apps)
self._keys = KEYS self._keys = KEYS
self.turn_on_command = turn_on_command
self.turn_off_command = turn_off_command
# ADB exceptions to catch # ADB exceptions to catch
if not self.aftv.adb_server_ip: if not self.aftv.adb_server_ip:
# Using "python-adb" (Python ADB implementation) # Using "python-adb" (Python ADB implementation)
@ -223,7 +227,7 @@ class ADBDevice(MediaPlayerDevice):
TcpTimeoutException) TcpTimeoutException)
else: else:
# Using "pure-python-adb" (communicate with ADB server) # Using "pure-python-adb" (communicate with ADB server)
self.exceptions = (ConnectionResetError,) self.exceptions = (ConnectionResetError, RuntimeError)
# Property attributes # Property attributes
self._available = self.aftv.available self._available = self.aftv.available
@ -278,11 +282,17 @@ class ADBDevice(MediaPlayerDevice):
@adb_decorator() @adb_decorator()
def turn_on(self): def turn_on(self):
"""Turn on the device.""" """Turn on the device."""
if self.turn_on_command:
self.aftv.adb_shell(self.turn_on_command)
else:
self.aftv.turn_on() self.aftv.turn_on()
@adb_decorator() @adb_decorator()
def turn_off(self): def turn_off(self):
"""Turn off the device.""" """Turn off the device."""
if self.turn_off_command:
self.aftv.adb_shell(self.turn_off_command)
else:
self.aftv.turn_off() self.aftv.turn_off()
@adb_decorator() @adb_decorator()
@ -311,9 +321,11 @@ class ADBDevice(MediaPlayerDevice):
class AndroidTVDevice(ADBDevice): class AndroidTVDevice(ADBDevice):
"""Representation of an Android TV device.""" """Representation of an Android TV device."""
def __init__(self, aftv, name, apps): def __init__(self, aftv, name, apps, turn_on_command,
turn_off_command):
"""Initialize the Android TV device.""" """Initialize the Android TV device."""
super().__init__(aftv, name, apps) super().__init__(aftv, name, apps, turn_on_command,
turn_off_command)
self._device = None self._device = None
self._muted = None self._muted = None
@ -392,9 +404,11 @@ class AndroidTVDevice(ADBDevice):
class FireTVDevice(ADBDevice): class FireTVDevice(ADBDevice):
"""Representation of a Fire TV device.""" """Representation of a Fire TV device."""
def __init__(self, aftv, name, apps, get_sources): def __init__(self, aftv, name, apps, get_sources,
turn_on_command, turn_off_command):
"""Initialize the Fire TV device.""" """Initialize the Fire TV device."""
super().__init__(aftv, name, apps) super().__init__(aftv, name, apps, turn_on_command,
turn_off_command)
self._get_sources = get_sources self._get_sources = get_sources
self._running_apps = None self._running_apps = None

View File

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

View File

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

View File

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

View File

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

View File

@ -9,13 +9,14 @@ import os
import voluptuous as vol import voluptuous as vol
from homeassistant.helpers.event import track_state_change
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.components.notify import ( from homeassistant.const import ATTR_NAME, CONF_NAME, CONF_PLATFORM
ATTR_TARGET, ATTR_DATA, BaseNotificationService, DOMAIN, PLATFORM_SCHEMA)
from homeassistant.const import CONF_NAME, CONF_PLATFORM, ATTR_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import template as template_helper from homeassistant.helpers import template as template_helper
import homeassistant.helpers.config_validation as cv
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'] REQUIREMENTS = ['apns2==0.3.0']

View File

@ -1,8 +1,6 @@
"""Support for Apple TV media player.""" """Support for Apple TV media player."""
import logging import logging
from homeassistant.components.apple_tv import (
ATTR_ATV, ATTR_POWER, DATA_APPLE_TV, DATA_ENTITIES)
from homeassistant.components.media_player import MediaPlayerDevice from homeassistant.components.media_player import MediaPlayerDevice
from homeassistant.components.media_player.const import ( from homeassistant.components.media_player.const import (
MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO, SUPPORT_NEXT_TRACK, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO, SUPPORT_NEXT_TRACK,
@ -14,6 +12,8 @@ from homeassistant.const import (
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from . import ATTR_ATV, ATTR_POWER, DATA_APPLE_TV, DATA_ENTITIES
DEPENDENCIES = ['apple_tv'] DEPENDENCIES = ['apple_tv']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -1,8 +1,8 @@
"""Remote control support for Apple TV.""" """Remote control support for Apple TV."""
from homeassistant.components.apple_tv import (
ATTR_ATV, ATTR_POWER, DATA_APPLE_TV)
from homeassistant.components import remote from homeassistant.components import remote
from homeassistant.const import (CONF_NAME, CONF_HOST) from homeassistant.const import CONF_HOST, CONF_NAME
from . import ATTR_ATV, ATTR_POWER, DATA_APPLE_TV
DEPENDENCIES = ['apple_tv'] DEPENDENCIES = ['apple_tv']

View File

@ -4,12 +4,13 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (CONF_MONITORED_CONDITIONS, from homeassistant.const import (
TEMP_CELSIUS, TEMP_FAHRENHEIT) CONF_MONITORED_CONDITIONS, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.entity import Entity
import homeassistant.components.aqualogic as aq
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from . import DOMAIN, UPDATE_TOPIC
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -46,7 +47,7 @@ async def async_setup_platform(
"""Set up the sensor platform.""" """Set up the sensor platform."""
sensors = [] sensors = []
processor = hass.data[aq.DOMAIN] processor = hass.data[DOMAIN]
for sensor_type in config.get(CONF_MONITORED_CONDITIONS): for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
sensors.append(AquaLogicSensor(processor, sensor_type)) sensors.append(AquaLogicSensor(processor, sensor_type))
@ -95,7 +96,7 @@ class AquaLogicSensor(Entity):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
self.hass.helpers.dispatcher.async_dispatcher_connect( self.hass.helpers.dispatcher.async_dispatcher_connect(
aq.UPDATE_TOPIC, self.async_update_callback) UPDATE_TOPIC, self.async_update_callback)
@callback @callback
def async_update_callback(self): def async_update_callback(self):

View File

@ -3,11 +3,12 @@ import logging
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchDevice
from homeassistant.const import CONF_MONITORED_CONDITIONS
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.components.aqualogic as aq import homeassistant.helpers.config_validation as cv
from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA
from homeassistant.const import (CONF_MONITORED_CONDITIONS) from . import DOMAIN, UPDATE_TOPIC
DEPENDENCIES = ['aqualogic'] DEPENDENCIES = ['aqualogic']
@ -37,7 +38,7 @@ async def async_setup_platform(
"""Set up the switch platform.""" """Set up the switch platform."""
switches = [] switches = []
processor = hass.data[aq.DOMAIN] processor = hass.data[DOMAIN]
for switch_type in config.get(CONF_MONITORED_CONDITIONS): for switch_type in config.get(CONF_MONITORED_CONDITIONS):
switches.append(AquaLogicSwitch(processor, switch_type)) switches.append(AquaLogicSwitch(processor, switch_type))
@ -101,7 +102,7 @@ class AquaLogicSwitch(SwitchDevice):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
self.hass.helpers.dispatcher.async_dispatcher_connect( self.hass.helpers.dispatcher.async_dispatcher_connect(
aq.UPDATE_TOPIC, self.async_update_callback) UPDATE_TOPIC, self.async_update_callback)
@callback @callback
def async_update_callback(self): def async_update_callback(self):

View File

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

View File

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

View File

@ -3,16 +3,16 @@ import logging
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.components.alarm_control_panel import ( from homeassistant.components.alarm_control_panel import (
AlarmControlPanel, PLATFORM_SCHEMA) PLATFORM_SCHEMA, AlarmControlPanel)
from homeassistant.components.arlo import (
DATA_ARLO, ATTRIBUTION, SIGNAL_UPDATE_ARLO)
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_NIGHT) STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED)
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import ATTRIBUTION, DATA_ARLO, SIGNAL_UPDATE_ARLO
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -3,16 +3,18 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback from homeassistant.components.camera import PLATFORM_SCHEMA, Camera
import homeassistant.helpers.config_validation as cv
from homeassistant.components.arlo import (
DEFAULT_BRAND, DATA_ARLO, SIGNAL_UPDATE_ARLO)
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
from homeassistant.components.ffmpeg import DATA_FFMPEG from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.const import ATTR_BATTERY_LEVEL
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import DATA_ARLO, DEFAULT_BRAND, SIGNAL_UPDATE_ARLO
DEPENDENCIES = ['arlo', 'ffmpeg']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ARLO_MODE_ARMED = 'armed' ARLO_MODE_ARMED = 'armed'
@ -28,8 +30,7 @@ ATTR_UNSEEN_VIDEOS = 'unseen_videos'
ATTR_LAST_REFRESH = 'last_refresh' ATTR_LAST_REFRESH = 'last_refresh'
CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
DEFAULT_ARGUMENTS = '-pred 1'
DEPENDENCIES = ['arlo', 'ffmpeg']
POWERSAVE_MODE_MAPPING = { POWERSAVE_MODE_MAPPING = {
1: 'best_battery_life', 1: 'best_battery_life',
@ -38,7 +39,7 @@ POWERSAVE_MODE_MAPPING = {
} }
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string, vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string,
}) })
@ -83,7 +84,7 @@ class ArloCam(Camera):
async def handle_async_mjpeg_stream(self, request): async def handle_async_mjpeg_stream(self, request):
"""Generate an HTTP MJPEG stream from the camera.""" """Generate an HTTP MJPEG stream from the camera."""
from haffmpeg import CameraMjpeg from haffmpeg.camera import CameraMjpeg
video = self._camera.last_video video = self._camera.last_video
if not video: if not video:
error_msg = \ error_msg = \
@ -97,8 +98,9 @@ class ArloCam(Camera):
video.video_url, extra_cmd=self._ffmpeg_arguments) video.video_url, extra_cmd=self._ffmpeg_arguments)
try: try:
stream_reader = await stream.get_reader()
return await async_aiohttp_proxy_stream( return await async_aiohttp_proxy_stream(
self.hass, request, stream, self.hass, request, stream_reader,
self._ffmpeg.ffmpeg_stream_content_type) self._ffmpeg.ffmpeg_stream_content_type)
finally: finally:
await stream.close() await stream.close()

View File

@ -3,19 +3,18 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.components.arlo import (
ATTRIBUTION, DEFAULT_BRAND, DATA_ARLO, SIGNAL_UPDATE_ARLO)
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, TEMP_CELSIUS, ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY) DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS)
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.icon import icon_for_battery_level from homeassistant.helpers.icon import icon_for_battery_level
from . import ATTRIBUTION, DATA_ARLO, DEFAULT_BRAND, SIGNAL_UPDATE_ARLO
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['arlo'] DEPENDENCIES = ['arlo']

View File

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

View File

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

View File

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

View File

@ -1,12 +1,13 @@
"""Support for the Asterisk Voicemail interface.""" """Support for the Asterisk Voicemail interface."""
import logging import logging
from homeassistant.components.asterisk_mbox import DOMAIN as ASTERISK_DOMAIN
from homeassistant.components.mailbox import ( from homeassistant.components.mailbox import (
CONTENT_TYPE_MPEG, Mailbox, StreamError) CONTENT_TYPE_MPEG, Mailbox, StreamError)
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import DOMAIN as ASTERISK_DOMAIN
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['asterisk_mbox'] DEPENDENCIES = ['asterisk_mbox']

View File

@ -6,9 +6,10 @@ https://home-assistant.io/components/device_tracker.asuswrt/
""" """
import logging import logging
from homeassistant.components.asuswrt import DATA_ASUSWRT
from homeassistant.components.device_tracker import DeviceScanner from homeassistant.components.device_tracker import DeviceScanner
from . import DATA_ASUSWRT
DEPENDENCIES = ['asuswrt'] DEPENDENCIES = ['asuswrt']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -7,7 +7,8 @@ https://home-assistant.io/components/sensor.asuswrt/
import logging import logging
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.components.asuswrt import DATA_ASUSWRT
from . import DATA_ASUSWRT
DEPENDENCIES = ['asuswrt'] DEPENDENCIES = ['asuswrt']

View File

@ -1,9 +1,10 @@
"""Support for August binary sensors.""" """Support for August binary sensors."""
from datetime import datetime, timedelta
import logging import logging
from datetime import timedelta, datetime
from homeassistant.components.august import DATA_AUGUST from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.binary_sensor import (BinarySensorDevice)
from . import DATA_AUGUST
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -3,9 +3,10 @@ from datetime import timedelta
import requests import requests
from homeassistant.components.august import DATA_AUGUST, DEFAULT_TIMEOUT
from homeassistant.components.camera import Camera from homeassistant.components.camera import Camera
from . import DATA_AUGUST, DEFAULT_TIMEOUT
DEPENDENCIES = ['august'] DEPENDENCIES = ['august']
SCAN_INTERVAL = timedelta(seconds=5) SCAN_INTERVAL = timedelta(seconds=5)

View File

@ -1,11 +1,12 @@
"""Support for August lock.""" """Support for August lock."""
import logging
from datetime import timedelta from datetime import timedelta
import logging
from homeassistant.components.august import DATA_AUGUST
from homeassistant.components.lock import LockDevice from homeassistant.components.lock import LockDevice
from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.const import ATTR_BATTERY_LEVEL
from . import DATA_AUGUST
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['august'] DEPENDENCIES = ['august']

View File

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

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d \u043a\u043e\u0434, \u043c\u043e\u043b\u044f \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e. \u0410\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430\u0442\u0435 \u0442\u0430\u0437\u0438 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e, \u043c\u043e\u043b\u044f, \u0443\u0432\u0435\u0440\u0435\u0442\u0435 \u0441\u0435, \u0447\u0435 \u0447\u0430\u0441\u043e\u0432\u043d\u0438\u043a\u044a\u0442 \u043d\u0430 Home Assistant \u0435 \u0441\u0432\u0435\u0440\u0435\u043d."
},
"step": {
"init": {
"description": "\u0417\u0430 \u0434\u0430 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0430\u0442\u0435 \u0434\u0432\u0443\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u0432\u043e-\u0431\u0430\u0437\u0438\u0440\u0430\u043d\u0438 \u0435\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u0438 \u043f\u0430\u0440\u043e\u043b\u0438, \u0441\u043a\u0430\u043d\u0438\u0440\u0430\u0439\u0442\u0435 QR \u043a\u043e\u0434\u0430 \u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0442\u043e\u0440\u0430. \u0410\u043a\u043e \u043d\u044f\u043c\u0430\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0412\u0438 \u043f\u0440\u0435\u043f\u043e\u0440\u044a\u0447\u0432\u0430\u043c\u0435 \u0438\u043b\u0438 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \u0438\u043b\u0438 [Authy](https://authy.com/).\n\n{qr_code}\n\n\u0421\u043b\u0435\u0434 \u0441\u043a\u0430\u043d\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434\u0430, \u0432\u044a\u0432\u0435\u0434\u0435\u0442\u0435 6-\u0442\u0435 \u0446\u0438\u0444\u0440\u0438 \u043e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e \u0437\u0430 \u0434\u0430 \u043f\u043e\u0442\u0432\u044a\u0440\u0434\u0438\u0442\u0435 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0430\u043d\u0435\u0442\u043e. \u0410\u043a\u043e \u0438\u043c\u0430\u0442\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0438 \u043f\u0440\u0438 \u0441\u043a\u0430\u043d\u0438\u0440\u0430\u043d\u0435\u0442\u043e \u043d\u0430 QR \u043a\u043e\u0434\u0430, \u043d\u0430\u043f\u0440\u0430\u0432\u0435\u0442\u0435 \u0440\u044a\u0447\u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441 \u043a\u043e\u0434 **`{code}`**.",
"title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u0430 \u0434\u0432\u0443\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0446\u0438\u044f \u0447\u0440\u0435\u0437 TOTP"
}
},
"title": "TOTP"
}
}
}

View File

@ -9,13 +9,15 @@
}, },
"step": { "step": {
"init": { "init": {
"description": "V\u00e1lassz \u00e9rtes\u00edt\u00e9si szolg\u00e1ltat\u00e1st:", "description": "K\u00e9rlek, v\u00e1lassz egyet az \u00e9rtes\u00edt\u00e9si szolg\u00e1ltat\u00e1sok k\u00f6z\u00fcl:",
"title": "\u00c1ll\u00edtsa be az \u00e9rtes\u00edt\u00e9si \u00f6sszetev\u0151 \u00e1ltal megadott egyszeri jelsz\u00f3t" "title": "\u00c1ll\u00edtsa be az \u00e9rtes\u00edt\u00e9si \u00f6sszetev\u0151 \u00e1ltal megadott egyszeri jelsz\u00f3t"
}, },
"setup": { "setup": {
"description": "Az egyszeri jelsz\u00f3 el lett k\u00fcldve a(z) **notify.{notify_service}** szolg\u00e1ltat\u00e1ssal. K\u00e9rlek, add meg al\u00e1bb:",
"title": "Be\u00e1ll\u00edt\u00e1s ellen\u0151rz\u00e9se" "title": "Be\u00e1ll\u00edt\u00e1s ellen\u0151rz\u00e9se"
} }
} },
"title": "Egyszeri Jelsz\u00f3 \u00c9rtes\u00edt\u00e9s"
}, },
"totp": { "totp": {
"error": { "error": {

View File

@ -81,7 +81,8 @@ from . import indieauth
async def async_setup(hass, store_result): async def async_setup(hass, store_result):
"""Component to allow users to login.""" """Component to allow users to login."""
hass.http.register_view(AuthProvidersView) hass.http.register_view(AuthProvidersView)
hass.http.register_view(LoginFlowIndexView(hass.auth.login_flow)) hass.http.register_view(
LoginFlowIndexView(hass.auth.login_flow, store_result))
hass.http.register_view( hass.http.register_view(
LoginFlowResourceView(hass.auth.login_flow, store_result)) LoginFlowResourceView(hass.auth.login_flow, store_result))
@ -142,9 +143,10 @@ class LoginFlowIndexView(HomeAssistantView):
name = 'api:auth:login_flow' name = 'api:auth:login_flow'
requires_auth = False requires_auth = False
def __init__(self, flow_mgr): def __init__(self, flow_mgr, store_result):
"""Initialize the flow manager index view.""" """Initialize the flow manager index view."""
self._flow_mgr = flow_mgr self._flow_mgr = flow_mgr
self._store_result = store_result
async def get(self, request): async def get(self, request):
"""Do not allow index of flows in progress.""" """Do not allow index of flows in progress."""
@ -179,6 +181,12 @@ class LoginFlowIndexView(HomeAssistantView):
except data_entry_flow.UnknownStep: except data_entry_flow.UnknownStep:
return self.json_message('Handler does not support init', 400) return self.json_message('Handler does not support init', 400)
if result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
result.pop('data')
result['result'] = self._store_result(
data['client_id'], result['result'])
return self.json(result)
return self.json(_prepare_result_json(result)) return self.json(_prepare_result_json(result))

View File

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

View File

@ -6,20 +6,20 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.setup import async_prepare_setup_platform
from homeassistant.core import CoreState, Context
from homeassistant.loader import bind_hass
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID, ATTR_NAME, CONF_ID, CONF_PLATFORM,
SERVICE_TOGGLE, SERVICE_RELOAD, EVENT_HOMEASSISTANT_START, CONF_ID, EVENT_AUTOMATION_TRIGGERED, EVENT_HOMEASSISTANT_START, SERVICE_RELOAD,
EVENT_AUTOMATION_TRIGGERED, ATTR_NAME) SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON)
from homeassistant.core import Context, CoreState
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import extract_domain_configs, script, condition from homeassistant.helpers import condition, extract_domain_configs, script
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.loader import bind_hass
from homeassistant.setup import async_prepare_setup_platform
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
import homeassistant.helpers.config_validation as cv
DOMAIN = 'automation' DOMAIN = 'automation'
DEPENDENCIES = ['group'] DEPENDENCIES = ['group']
@ -54,9 +54,8 @@ _LOGGER = logging.getLogger(__name__)
def _platform_validator(config): def _platform_validator(config):
"""Validate it is a valid platform.""" """Validate it is a valid platform."""
try: try:
platform = importlib.import_module( platform = importlib.import_module('.{}'.format(config[CONF_PLATFORM]),
'homeassistant.components.automation.{}'.format( __name__)
config[CONF_PLATFORM]))
except ImportError: except ImportError:
raise vol.Invalid('Invalid platform specified') from None raise vol.Invalid('Invalid platform specified') from None

View File

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

View File

@ -4,6 +4,7 @@ Support for Avion dimmers.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.avion/ https://home-assistant.io/components/light.avion/
""" """
import importlib
import logging import logging
import time import time
@ -38,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up an Avion switch.""" """Set up an Avion switch."""
# pylint: disable=no-member # pylint: disable=no-member
import avion avion = importlib.import_module('avion')
lights = [] lights = []
if CONF_USERNAME in config and CONF_PASSWORD in config: if CONF_USERNAME in config and CONF_PASSWORD in config:
@ -108,7 +109,7 @@ class AvionLight(Light):
def set_state(self, brightness): def set_state(self, brightness):
"""Set the state of this lamp to the provided brightness.""" """Set the state of this lamp to the provided brightness."""
# pylint: disable=no-member # pylint: disable=no-member
import avion avion = importlib.import_module('avion')
# Bluetooth LE is unreliable, and the connection may drop at any # Bluetooth LE is unreliable, and the connection may drop at any
# time. Make an effort to re-establish the link. # time. Make an effort to re-establish the link.

View File

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

View File

@ -0,0 +1,176 @@
"""Support for Amazon Web Services (AWS)."""
import asyncio
import logging
from collections import OrderedDict
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import ATTR_CREDENTIALS, CONF_NAME, CONF_PROFILE_NAME
from homeassistant.helpers import config_validation as cv, discovery
# Loading the config flow file will register the flow
from . import config_flow # noqa
from .const import (
CONF_ACCESS_KEY_ID,
CONF_CONTEXT,
CONF_CREDENTIAL_NAME,
CONF_CREDENTIALS,
CONF_NOTIFY,
CONF_REGION,
CONF_SECRET_ACCESS_KEY,
CONF_SERVICE,
DATA_CONFIG,
DATA_HASS_CONFIG,
DATA_SESSIONS,
DOMAIN,
)
REQUIREMENTS = ["aiobotocore==0.10.2"]
_LOGGER = logging.getLogger(__name__)
AWS_CREDENTIAL_SCHEMA = vol.Schema(
{
vol.Required(CONF_NAME): cv.string,
vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
}
)
DEFAULT_CREDENTIAL = [{CONF_NAME: "default", CONF_PROFILE_NAME: "default"}]
SUPPORTED_SERVICES = ["lambda", "sns", "sqs"]
NOTIFY_PLATFORM_SCHEMA = vol.Schema(
{
vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_SERVICE): vol.All(
cv.string, vol.Lower, vol.In(SUPPORTED_SERVICES)
),
vol.Required(CONF_REGION): vol.All(cv.string, vol.Lower),
vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
vol.Exclusive(CONF_CREDENTIAL_NAME, ATTR_CREDENTIALS): cv.string,
vol.Optional(CONF_CONTEXT): vol.Coerce(dict),
}
)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Optional(
CONF_CREDENTIALS, default=DEFAULT_CREDENTIAL
): vol.All(cv.ensure_list, [AWS_CREDENTIAL_SCHEMA]),
vol.Optional(CONF_NOTIFY, default=[]): vol.All(
cv.ensure_list, [NOTIFY_PLATFORM_SCHEMA]
),
}
)
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass, config):
"""Set up AWS component."""
hass.data[DATA_HASS_CONFIG] = config
conf = config.get(DOMAIN)
if conf is None:
# create a default conf using default profile
conf = CONFIG_SCHEMA({ATTR_CREDENTIALS: DEFAULT_CREDENTIAL})
hass.data[DATA_CONFIG] = conf
hass.data[DATA_SESSIONS] = OrderedDict()
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=conf
)
)
return True
async def async_setup_entry(hass, entry):
"""Load a config entry.
Validate and save sessions per aws credential.
"""
config = hass.data.get(DATA_HASS_CONFIG)
conf = hass.data.get(DATA_CONFIG)
if entry.source == config_entries.SOURCE_IMPORT:
if conf is None:
# user removed config from configuration.yaml, abort setup
hass.async_create_task(
hass.config_entries.async_remove(entry.entry_id)
)
return False
if conf != entry.data:
# user changed config from configuration.yaml, use conf to setup
hass.config_entries.async_update_entry(entry, data=conf)
if conf is None:
conf = CONFIG_SCHEMA({DOMAIN: entry.data})[DOMAIN]
# validate credentials and create sessions
validation = True
tasks = []
for cred in conf[ATTR_CREDENTIALS]:
tasks.append(_validate_aws_credentials(hass, cred))
if tasks:
results = await asyncio.gather(*tasks, return_exceptions=True)
for index, result in enumerate(results):
name = conf[ATTR_CREDENTIALS][index][CONF_NAME]
if isinstance(result, Exception):
_LOGGER.error(
"Validating credential [%s] failed: %s",
name,
result,
exc_info=result,
)
validation = False
else:
hass.data[DATA_SESSIONS][name] = result
# set up notify platform, no entry support for notify component yet,
# have to use discovery to load platform.
for notify_config in conf[CONF_NOTIFY]:
hass.async_create_task(
discovery.async_load_platform(
hass, "notify", DOMAIN, notify_config, config
)
)
return validation
async def _validate_aws_credentials(hass, credential):
"""Validate AWS credential config."""
import aiobotocore
aws_config = credential.copy()
del aws_config[CONF_NAME]
profile = aws_config.get(CONF_PROFILE_NAME)
if profile is not None:
session = aiobotocore.AioSession(profile=profile, loop=hass.loop)
del aws_config[CONF_PROFILE_NAME]
if CONF_ACCESS_KEY_ID in aws_config:
del aws_config[CONF_ACCESS_KEY_ID]
if CONF_SECRET_ACCESS_KEY in aws_config:
del aws_config[CONF_SECRET_ACCESS_KEY]
else:
session = aiobotocore.AioSession(loop=hass.loop)
async with session.create_client("iam", **aws_config) as client:
await client.get_user()
return session

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