mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
commit
360caa3b1f
262
.circleci/config.yml
Normal file
262
.circleci/config.yml
Normal 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
|
919
.coveragerc
919
.coveragerc
File diff suppressed because it is too large
Load Diff
1
.gitignore
vendored
1
.gitignore
vendored
@ -55,6 +55,7 @@ pip-log.txt
|
||||
.tox
|
||||
nosetests.xml
|
||||
htmlcov/
|
||||
test-reports/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
232
CODEOWNERS
232
CODEOWNERS
@ -18,7 +18,7 @@ homeassistant/components/frontend/* @home-assistant/core
|
||||
homeassistant/components/group/* @home-assistant/core
|
||||
homeassistant/components/history/* @home-assistant/core
|
||||
homeassistant/components/http/* @home-assistant/core
|
||||
homeassistant/components/input_*.py @home-assistant/core
|
||||
homeassistant/components/input_*/* @home-assistant/core
|
||||
homeassistant/components/introduction/* @home-assistant/core
|
||||
homeassistant/components/logger/* @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
|
||||
|
||||
# Individual platforms
|
||||
homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell
|
||||
homeassistant/components/binary_sensor/hikvision.py @mezz64
|
||||
homeassistant/components/binary_sensor/threshold.py @fabaff
|
||||
homeassistant/components/binary_sensor/uptimerobot.py @ludeeus
|
||||
homeassistant/components/camera/push.py @dgomes
|
||||
homeassistant/components/camera/yi.py @bachya
|
||||
homeassistant/components/climate/coolmaster.py @OnFreund
|
||||
homeassistant/components/climate/ephember.py @ttroy50
|
||||
homeassistant/components/climate/eq3btsmart.py @rytilahti
|
||||
homeassistant/components/climate/mill.py @danielhiversen
|
||||
homeassistant/components/climate/sensibo.py @andrey-git
|
||||
homeassistant/components/cover/brunt.py @eavanvalkenburg
|
||||
homeassistant/components/cover/group.py @cdce8p
|
||||
homeassistant/components/cover/template.py @PhracturedBlue
|
||||
homeassistant/components/device_tracker/asuswrt.py @kennedyshead
|
||||
homeassistant/components/device_tracker/automatic.py @armills
|
||||
homeassistant/components/device_tracker/bt_smarthub.py @jxwolstenholme
|
||||
homeassistant/components/device_tracker/huawei_router.py @abmantis
|
||||
homeassistant/components/device_tracker/quantum_gateway.py @cisasteelersfan
|
||||
homeassistant/components/device_tracker/tile.py @bachya
|
||||
homeassistant/components/device_tracker/traccar.py @ludeeus
|
||||
homeassistant/components/device_tracker/synology_srm.py @aerialls
|
||||
homeassistant/components/device_tracker/xfinity.py @cisasteelersfan
|
||||
homeassistant/components/light/lifx_legacy.py @amelchio
|
||||
homeassistant/components/light/yeelight.py @rytilahti
|
||||
homeassistant/components/light/yeelightsunflower.py @lindsaymarkward
|
||||
homeassistant/components/lock/nello.py @pschmitt
|
||||
homeassistant/components/lock/nuki.py @pschmitt
|
||||
homeassistant/components/media_player/emby.py @mezz64
|
||||
homeassistant/components/media_player/kodi.py @armills
|
||||
homeassistant/components/media_player/liveboxplaytv.py @pschmitt
|
||||
homeassistant/components/media_player/mediaroom.py @dgomes
|
||||
homeassistant/components/media_player/monoprice.py @etsinko
|
||||
homeassistant/components/media_player/mpd.py @fabaff
|
||||
homeassistant/components/media_player/xiaomi_tv.py @fattdev
|
||||
homeassistant/components/media_player/yamaha_musiccast.py @jalmeroth
|
||||
homeassistant/components/notify/aws_lambda.py @robbiet480
|
||||
homeassistant/components/notify/aws_sns.py @robbiet480
|
||||
homeassistant/components/notify/aws_sqs.py @robbiet480
|
||||
homeassistant/components/notify/file.py @fabaff
|
||||
homeassistant/components/notify/flock.py @fabaff
|
||||
homeassistant/components/notify/gntp.py @robbiet480
|
||||
homeassistant/components/notify/html5.py @robbiet480
|
||||
homeassistant/components/notify/mastodon.py @fabaff
|
||||
homeassistant/components/notify/smtp.py @fabaff
|
||||
homeassistant/components/notify/syslog.py @fabaff
|
||||
homeassistant/components/notify/twilio_call.py @robbiet480
|
||||
homeassistant/components/notify/twilio_sms.py @robbiet480
|
||||
homeassistant/components/notify/xmpp.py @fabaff
|
||||
homeassistant/components/notify/yessssms.py @flowolf
|
||||
homeassistant/components/scene/lifx_cloud.py @amelchio
|
||||
homeassistant/components/sensor/airvisual.py @bachya
|
||||
homeassistant/components/sensor/alpha_vantage.py @fabaff
|
||||
homeassistant/components/sensor/bitcoin.py @fabaff
|
||||
homeassistant/components/sensor/cpuspeed.py @fabaff
|
||||
homeassistant/components/sensor/cups.py @fabaff
|
||||
homeassistant/components/sensor/darksky.py @fabaff
|
||||
homeassistant/components/sensor/discogs.py @thibmaek
|
||||
homeassistant/components/sensor/file.py @fabaff
|
||||
homeassistant/components/sensor/filter.py @dgomes
|
||||
homeassistant/components/sensor/fixer.py @fabaff
|
||||
homeassistant/components/sensor/flunearyou.py @bachya
|
||||
homeassistant/components/sensor/gearbest.py @HerrHofrat
|
||||
homeassistant/components/sensor/gitter.py @fabaff
|
||||
homeassistant/components/sensor/glances.py @fabaff
|
||||
homeassistant/components/sensor/gpsd.py @fabaff
|
||||
homeassistant/components/sensor/integration.py @dgomes
|
||||
homeassistant/components/sensor/irish_rail_transport.py @ttroy50
|
||||
homeassistant/components/sensor/jewish_calendar.py @tsvi
|
||||
homeassistant/components/sensor/launch_library.py @ludeeus
|
||||
homeassistant/components/sensor/linux_battery.py @fabaff
|
||||
homeassistant/components/sensor/miflora.py @danielhiversen @ChristianKuehnel
|
||||
homeassistant/components/sensor/min_max.py @fabaff
|
||||
homeassistant/components/sensor/moon.py @fabaff
|
||||
homeassistant/components/sensor/netdata.py @fabaff
|
||||
homeassistant/components/sensor/nmbs.py @thibmaek
|
||||
homeassistant/components/sensor/nsw_fuel_station.py @nickw444
|
||||
homeassistant/components/sensor/pi_hole.py @fabaff
|
||||
homeassistant/components/sensor/pollen.py @bachya
|
||||
homeassistant/components/sensor/pvoutput.py @fabaff
|
||||
homeassistant/components/sensor/qnap.py @colinodell
|
||||
homeassistant/components/sensor/ruter.py @ludeeus
|
||||
homeassistant/components/sensor/scrape.py @fabaff
|
||||
homeassistant/components/sensor/serial.py @fabaff
|
||||
homeassistant/components/sensor/seventeentrack.py @bachya
|
||||
homeassistant/components/sensor/shodan.py @fabaff
|
||||
homeassistant/components/sensor/sma.py @kellerza
|
||||
homeassistant/components/sensor/sql.py @dgomes
|
||||
homeassistant/components/sensor/statistics.py @fabaff
|
||||
homeassistant/components/sensor/swiss*.py @fabaff
|
||||
homeassistant/components/sensor/sytadin.py @gautric
|
||||
homeassistant/components/sensor/tautulli.py @ludeeus
|
||||
homeassistant/components/sensor/time_date.py @fabaff
|
||||
homeassistant/components/sensor/version.py @fabaff
|
||||
homeassistant/components/sensor/waqi.py @andrey-git
|
||||
homeassistant/components/sensor/worldclock.py @fabaff
|
||||
homeassistant/components/switch/switchbot.py @danielhiversen
|
||||
homeassistant/components/switch/switchmate.py @danielhiversen
|
||||
homeassistant/components/vacuum/roomba.py @pschmitt
|
||||
homeassistant/components/weather/__init__.py @fabaff
|
||||
homeassistant/components/weather/darksky.py @fabaff
|
||||
homeassistant/components/weather/demo.py @fabaff
|
||||
homeassistant/components/weather/met.py @danielhiversen
|
||||
homeassistant/components/weather/openweathermap.py @fabaff
|
||||
homeassistant/components/tts/amazon_polly.py @robbiet480
|
||||
|
||||
# A
|
||||
homeassistant/components/airvisual/sensor.py @bachya
|
||||
homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell
|
||||
homeassistant/components/alpha_vantage/sensor.py @fabaff
|
||||
homeassistant/components/ambient_station/* @bachya
|
||||
homeassistant/components/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/*/arest.py @fabaff
|
||||
|
||||
# B
|
||||
homeassistant/components/bitcoin/sensor.py @fabaff
|
||||
homeassistant/components/blink/* @fronzbot
|
||||
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
|
||||
homeassistant/components/cloudflare/* @ludeeus
|
||||
homeassistant/components/coolmaster/climate.py @OnFreund
|
||||
homeassistant/components/counter/* @fabaff
|
||||
homeassistant/components/cover/group.py @cdce8p
|
||||
homeassistant/components/cpuspeed/sensor.py @fabaff
|
||||
homeassistant/components/cups/sensor.py @fabaff
|
||||
|
||||
# D
|
||||
homeassistant/components/daikin/* @fredrike @rofrantz
|
||||
homeassistant/components/darksky/* @fabaff
|
||||
homeassistant/components/discogs/sensor.py @thibmaek
|
||||
homeassistant/components/deconz/* @kane610
|
||||
homeassistant/components/demo/weather.py @fabaff
|
||||
homeassistant/components/digital_ocean/* @fabaff
|
||||
homeassistant/components/doorbird/* @oblogic7
|
||||
homeassistant/components/dweet/* @fabaff
|
||||
|
||||
# E
|
||||
@ -171,94 +106,185 @@ homeassistant/components/ecovacs/* @OverloadUT
|
||||
homeassistant/components/edp_redy/* @abmantis
|
||||
homeassistant/components/eight_sleep/* @mezz64
|
||||
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
|
||||
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
|
||||
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/gpsd/sensor.py @fabaff
|
||||
homeassistant/components/gtfs/sensor.py @robbiet480
|
||||
|
||||
# H
|
||||
homeassistant/components/harmony/* @ehendrix23
|
||||
homeassistant/components/hikvision/binary_sensor.py @mezz64
|
||||
homeassistant/components/history_graph/* @andrey-git
|
||||
homeassistant/components/hive/* @Rendili @KJonline
|
||||
homeassistant/components/homekit/* @cdce8p
|
||||
homeassistant/components/huawei_lte/* @scop
|
||||
homeassistant/components/huawei_router/device_tracker.py @abmantis
|
||||
|
||||
# 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/irish_rail_transport/sensor.py @ttroy50
|
||||
|
||||
# J
|
||||
homeassistant/components/jewish_calendar/sensor.py @tsvi
|
||||
|
||||
# K
|
||||
homeassistant/components/knx/* @Julius2342
|
||||
homeassistant/components/kodi/media_player.py @armills
|
||||
homeassistant/components/konnected/* @heythisisnate
|
||||
|
||||
# L
|
||||
homeassistant/components/lametric/notify.py @robbiet480
|
||||
homeassistant/components/launch_library/sensor.py @ludeeus
|
||||
homeassistant/components/lifx/* @amelchio
|
||||
homeassistant/components/lifx_cloud/scene.py @amelchio
|
||||
homeassistant/components/lifx_legacy/light.py @amelchio
|
||||
homeassistant/components/linux_battery/sensor.py @fabaff
|
||||
homeassistant/components/liveboxplaytv/media_player.py @pschmitt
|
||||
homeassistant/components/luftdaten/* @fabaff
|
||||
|
||||
# M
|
||||
homeassistant/components/matrix/* @tinloaf
|
||||
homeassistant/components/mediaroom/media_player.py @dgomes
|
||||
homeassistant/components/melissa/* @kennedyshead
|
||||
homeassistant/components/*/melissa.py @kennedyshead
|
||||
homeassistant/components/*/mystrom.py @fabaff
|
||||
homeassistant/components/met/weather.py @danielhiversen
|
||||
homeassistant/components/miflora/sensor.py @danielhiversen @ChristianKuehnel
|
||||
homeassistant/components/mill/climate.py @danielhiversen
|
||||
homeassistant/components/min_max/sensor.py @fabaff
|
||||
homeassistant/components/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
|
||||
homeassistant/components/nello/lock.py @pschmitt
|
||||
homeassistant/components/ness_alarm/* @nickw444
|
||||
homeassistant/components/*/ness_alarm.py @nickw444
|
||||
homeassistant/components/netdata/sensor.py @fabaff
|
||||
homeassistant/components/nissan_leaf/* @filcole
|
||||
homeassistant/components/nmbs/sensor.py @thibmaek
|
||||
homeassistant/components/no_ip/* @fabaff
|
||||
homeassistant/components/nuki/lock.py @pschmitt
|
||||
homeassistant/components/nsw_fuel_station/sensor.py @nickw444
|
||||
|
||||
# O
|
||||
homeassistant/components/ohmconnect/sensor.py @robbiet480
|
||||
homeassistant/components/openuv/* @bachya
|
||||
homeassistant/components/openweathermap/weather.py @fabaff
|
||||
homeassistant/components/owlet/* @oblogic7
|
||||
|
||||
# P
|
||||
homeassistant/components/pi_hole/sensor.py @fabaff
|
||||
homeassistant/components/plant/* @ChristianKuehnel
|
||||
homeassistant/components/point/* @fredrike
|
||||
homeassistant/components/pollen/sensor.py @bachya
|
||||
homeassistant/components/push/camera.py @dgomes
|
||||
homeassistant/components/pvoutput/sensor.py @fabaff
|
||||
|
||||
# Q
|
||||
homeassistant/components/qnap/sensor.py @colinodell
|
||||
homeassistant/components/quantum_gateway/device_tracker.py @cisasteelersfan
|
||||
homeassistant/components/qwikswitch/* @kellerza
|
||||
|
||||
# R
|
||||
homeassistant/components/rainmachine/* @bachya
|
||||
homeassistant/components/random/* @fabaff
|
||||
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
|
||||
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/shodan/sensor.py @fabaff
|
||||
homeassistant/components/simplisafe/* @bachya
|
||||
homeassistant/components/sma/sensor.py @kellerza
|
||||
homeassistant/components/smartthings/* @andrewsayre
|
||||
homeassistant/components/sonos/* @amelchio
|
||||
homeassistant/components/spaceapi/* @fabaff
|
||||
homeassistant/components/spider/* @peternijssen
|
||||
homeassistant/components/sql/sensor.py @dgomes
|
||||
homeassistant/components/statistics/sensor.py @fabaff
|
||||
homeassistant/components/swiss_*/* @fabaff
|
||||
homeassistant/components/switchbot/switch.py @danielhiversen
|
||||
homeassistant/components/switchmate/switch.py @danielhiversen
|
||||
homeassistant/components/synology_srm/device_tracker.py @aerialls
|
||||
homeassistant/components/sytadin/sensor.py @gautric
|
||||
|
||||
# T
|
||||
homeassistant/components/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/tfiac/* @fredrike @mellado
|
||||
homeassistant/components/thethingsnetwork/* @fabaff
|
||||
homeassistant/components/threshold/binary_sensor.py @fabaff
|
||||
homeassistant/components/tibber/* @danielhiversen
|
||||
homeassistant/components/tplink/* @rytilahti
|
||||
homeassistant/components/tradfri/* @ggravlingen
|
||||
homeassistant/components/tile/device_tracker.py @bachya
|
||||
homeassistant/components/time_date/sensor.py @fabaff
|
||||
homeassistant/components/toon/* @frenck
|
||||
homeassistant/components/tplink/* @rytilahti
|
||||
homeassistant/components/traccar/device_tracker.py @ludeeus
|
||||
homeassistant/components/tradfri/* @ggravlingen
|
||||
|
||||
# U
|
||||
homeassistant/components/uber/sensor.py @robbiet480
|
||||
homeassistant/components/unifi/* @kane610
|
||||
homeassistant/components/upcloud/* @scop
|
||||
homeassistant/components/upnp/* @robbiet480
|
||||
homeassistant/components/uptimerobot/binary_sensor.py @ludeeus
|
||||
homeassistant/components/utility_meter/* @dgomes
|
||||
|
||||
# V
|
||||
homeassistant/components/velux/* @Julius2342
|
||||
homeassistant/components/version/sensor.py @fabaff
|
||||
|
||||
# W
|
||||
homeassistant/components/waqi/sensor.py @andrey-git
|
||||
homeassistant/components/weather/__init__.py @fabaff
|
||||
homeassistant/components/wemo/* @sqldiablo
|
||||
homeassistant/components/worldclock/sensor.py @fabaff
|
||||
|
||||
# X
|
||||
homeassistant/components/xfinity/device_tracker.py @cisasteelersfan
|
||||
homeassistant/components/xiaomi_aqara/* @danielhiversen @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
|
||||
homeassistant/components/zeroconf/* @robbiet480
|
||||
homeassistant/components/zha/* @dmulcahey @adminiuga
|
||||
homeassistant/components/zoneminder/* @rohankapoorcom
|
||||
|
||||
# Other code
|
||||
|
@ -1,4 +1,4 @@
|
||||
Home Assistant |Build Status| |Coverage Status| |Chat Status|
|
||||
Home Assistant |Build Status| |CI Status| |Coverage Status| |Chat Status|
|
||||
=================================================================================
|
||||
|
||||
Home Assistant is a home automation platform running on Python 3. It is able to track and control all devices at home and offer a platform for automating control.
|
||||
@ -27,8 +27,10 @@ components <https://developers.home-assistant.io/docs/en/creating_component_inde
|
||||
If you run into issues while using Home Assistant or during development
|
||||
of a component, check the `Home Assistant help section <https://home-assistant.io/help/>`__ of our website for further help and information.
|
||||
|
||||
.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=master
|
||||
.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=dev
|
||||
:target: https://travis-ci.org/home-assistant/home-assistant
|
||||
.. |CI Status| image:: https://circleci.com/gh/home-assistant/home-assistant.svg?style=shield
|
||||
:target: https://circleci.com/gh/home-assistant/home-assistant
|
||||
.. |Coverage Status| image:: https://img.shields.io/coveralls/home-assistant/home-assistant.svg
|
||||
:target: https://coveralls.io/r/home-assistant/home-assistant?branch=master
|
||||
.. |Chat Status| image:: https://img.shields.io/discord/330944238910963714.svg
|
||||
|
@ -18,8 +18,26 @@ from ..models import Credentials, UserMeta
|
||||
IPAddress = Union[IPv4Address, IPv6Address]
|
||||
IPNetwork = Union[IPv4Network, IPv6Network]
|
||||
|
||||
CONF_TRUSTED_NETWORKS = 'trusted_networks'
|
||||
CONF_TRUSTED_USERS = 'trusted_users'
|
||||
CONF_GROUP = 'group'
|
||||
CONF_ALLOW_BYPASS_LOGIN = 'allow_bypass_login'
|
||||
|
||||
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend({
|
||||
vol.Required('trusted_networks'): vol.All(cv.ensure_list, [ip_network])
|
||||
vol.Required(CONF_TRUSTED_NETWORKS): vol.All(
|
||||
cv.ensure_list, [ip_network]
|
||||
),
|
||||
vol.Optional(CONF_TRUSTED_USERS, default={}): vol.Schema(
|
||||
# we only validate the format of user_id or group_id
|
||||
{ip_network: vol.All(
|
||||
cv.ensure_list,
|
||||
[vol.Or(
|
||||
cv.uuid4_hex,
|
||||
vol.Schema({vol.Required(CONF_GROUP): cv.uuid4_hex}),
|
||||
)],
|
||||
)}
|
||||
),
|
||||
vol.Optional(CONF_ALLOW_BYPASS_LOGIN, default=False): cv.boolean,
|
||||
}, extra=vol.PREVENT_EXTRA)
|
||||
|
||||
|
||||
@ -43,7 +61,12 @@ class TrustedNetworksAuthProvider(AuthProvider):
|
||||
@property
|
||||
def trusted_networks(self) -> List[IPNetwork]:
|
||||
"""Return trusted networks."""
|
||||
return cast(List[IPNetwork], self.config['trusted_networks'])
|
||||
return cast(List[IPNetwork], self.config[CONF_TRUSTED_NETWORKS])
|
||||
|
||||
@property
|
||||
def trusted_users(self) -> Dict[IPNetwork, Any]:
|
||||
"""Return trusted users per network."""
|
||||
return cast(Dict[IPNetwork, Any], self.config[CONF_TRUSTED_USERS])
|
||||
|
||||
@property
|
||||
def support_mfa(self) -> bool:
|
||||
@ -53,13 +76,34 @@ class TrustedNetworksAuthProvider(AuthProvider):
|
||||
async def async_login_flow(self, context: Optional[Dict]) -> LoginFlow:
|
||||
"""Return a flow to login."""
|
||||
assert context is not None
|
||||
ip_addr = cast(IPAddress, context.get('ip_address'))
|
||||
users = await self.store.async_get_users()
|
||||
available_users = {user.id: user.name
|
||||
for user in users
|
||||
if not user.system_generated and user.is_active}
|
||||
available_users = [user for user in users
|
||||
if not user.system_generated and user.is_active]
|
||||
for ip_net, user_or_group_list in self.trusted_users.items():
|
||||
if ip_addr in ip_net:
|
||||
user_list = [user_id for user_id in user_or_group_list
|
||||
if isinstance(user_id, str)]
|
||||
group_list = [group[CONF_GROUP] for group in user_or_group_list
|
||||
if isinstance(group, dict)]
|
||||
flattened_group_list = [group for sublist in group_list
|
||||
for group in sublist]
|
||||
available_users = [
|
||||
user for user in available_users
|
||||
if (user.id in user_list or
|
||||
any([group.id in flattened_group_list
|
||||
for group in user.groups]))
|
||||
]
|
||||
break
|
||||
|
||||
return TrustedNetworksLoginFlow(
|
||||
self, cast(IPAddress, context.get('ip_address')), available_users)
|
||||
self,
|
||||
ip_addr,
|
||||
{
|
||||
user.id: user.name for user in available_users
|
||||
},
|
||||
self.config[CONF_ALLOW_BYPASS_LOGIN],
|
||||
)
|
||||
|
||||
async def async_get_or_create_credentials(
|
||||
self, flow_result: Dict[str, str]) -> Credentials:
|
||||
@ -109,11 +153,13 @@ class TrustedNetworksLoginFlow(LoginFlow):
|
||||
|
||||
def __init__(self, auth_provider: TrustedNetworksAuthProvider,
|
||||
ip_addr: IPAddress,
|
||||
available_users: Dict[str, Optional[str]]) -> None:
|
||||
available_users: Dict[str, Optional[str]],
|
||||
allow_bypass_login: bool) -> None:
|
||||
"""Initialize the login flow."""
|
||||
super().__init__(auth_provider)
|
||||
self._available_users = available_users
|
||||
self._ip_address = ip_addr
|
||||
self._allow_bypass_login = allow_bypass_login
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: Optional[Dict[str, str]] = None) \
|
||||
@ -131,6 +177,11 @@ class TrustedNetworksLoginFlow(LoginFlow):
|
||||
if user_input is not None:
|
||||
return await self.async_finish(user_input)
|
||||
|
||||
if self._allow_bypass_login and len(self._available_users) == 1:
|
||||
return await self.async_finish({
|
||||
'user': next(iter(self._available_users.keys()))
|
||||
})
|
||||
|
||||
return self.async_show_form(
|
||||
step_id='init',
|
||||
data_schema=vol.Schema({'user': vol.In(self._available_users)}),
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Provide methods to bootstrap a Home Assistant instance."""
|
||||
import asyncio
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
@ -9,10 +10,10 @@ from typing import Any, Optional, Dict, Set
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import (
|
||||
core, config as conf_util, config_entries, components as core_components,
|
||||
loader)
|
||||
from homeassistant.components import persistent_notification
|
||||
from homeassistant import core, config as conf_util, config_entries, loader
|
||||
from homeassistant.components import (
|
||||
persistent_notification, homeassistant as core_component
|
||||
)
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.logging import AsyncHandler
|
||||
@ -139,7 +140,7 @@ async def async_from_config_dict(config: Dict[str, Any],
|
||||
pass
|
||||
|
||||
# setup components
|
||||
res = await core_components.async_setup(hass, config)
|
||||
res = await core_component.async_setup(hass, config)
|
||||
if not res:
|
||||
_LOGGER.error("Home Assistant core failed to initialize. "
|
||||
"Further initialization aborted")
|
||||
@ -157,6 +158,12 @@ async def async_from_config_dict(config: Dict[str, Any],
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Kick off loading the registries. They don't need to be awaited.
|
||||
asyncio.gather(
|
||||
hass.helpers.device_registry.async_get_registry(),
|
||||
hass.helpers.entity_registry.async_get_registry(),
|
||||
hass.helpers.area_registry.async_get_registry())
|
||||
|
||||
# stage 1
|
||||
for component in components:
|
||||
if component in FIRST_INIT_COMPONENT:
|
||||
|
@ -7,33 +7,12 @@ Component design guidelines:
|
||||
format "<DOMAIN>.<OBJECT_ID>".
|
||||
- Each component should publish services only under its own domain.
|
||||
"""
|
||||
import asyncio
|
||||
import itertools as it
|
||||
import logging
|
||||
from typing import Awaitable
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.config as conf_util
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.service import async_extract_entity_ids
|
||||
from homeassistant.helpers import intent
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
||||
SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART,
|
||||
RESTART_EXIT_CODE)
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.core import split_entity_id
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SERVICE_RELOAD_CORE_CONFIG = 'reload_core_config'
|
||||
SERVICE_CHECK_CONFIG = 'check_config'
|
||||
SERVICE_UPDATE_ENTITY = 'update_entity'
|
||||
SCHEMA_UPDATE_ENTITY = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.entity_ids
|
||||
})
|
||||
|
||||
|
||||
def is_on(hass, entity_id=None):
|
||||
"""Load up the module to call the is_on method.
|
||||
@ -46,7 +25,7 @@ def is_on(hass, entity_id=None):
|
||||
entity_ids = hass.states.entity_ids()
|
||||
|
||||
for ent_id in entity_ids:
|
||||
domain = ha.split_entity_id(ent_id)[0]
|
||||
domain = split_entity_id(ent_id)[0]
|
||||
|
||||
try:
|
||||
component = getattr(hass.components, domain)
|
||||
@ -64,113 +43,3 @@ def is_on(hass, entity_id=None):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
|
||||
"""Set up general services related to Home Assistant."""
|
||||
async def async_handle_turn_service(service):
|
||||
"""Handle calls to homeassistant.turn_on/off."""
|
||||
entity_ids = await async_extract_entity_ids(hass, service)
|
||||
|
||||
# Generic turn on/off method requires entity id
|
||||
if not entity_ids:
|
||||
_LOGGER.error(
|
||||
"homeassistant/%s cannot be called without entity_id",
|
||||
service.service)
|
||||
return
|
||||
|
||||
# Group entity_ids by domain. groupby requires sorted data.
|
||||
by_domain = it.groupby(sorted(entity_ids),
|
||||
lambda item: ha.split_entity_id(item)[0])
|
||||
|
||||
tasks = []
|
||||
|
||||
for domain, ent_ids in by_domain:
|
||||
# We want to block for all calls and only return when all calls
|
||||
# have been processed. If a service does not exist it causes a 10
|
||||
# second delay while we're blocking waiting for a response.
|
||||
# But services can be registered on other HA instances that are
|
||||
# listening to the bus too. So as an in between solution, we'll
|
||||
# block only if the service is defined in the current HA instance.
|
||||
blocking = hass.services.has_service(domain, service.service)
|
||||
|
||||
# Create a new dict for this call
|
||||
data = dict(service.data)
|
||||
|
||||
# ent_ids is a generator, convert it to a list.
|
||||
data[ATTR_ENTITY_ID] = list(ent_ids)
|
||||
|
||||
tasks.append(hass.services.async_call(
|
||||
domain, service.service, data, blocking))
|
||||
|
||||
await asyncio.wait(tasks, loop=hass.loop)
|
||||
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_TURN_OFF, async_handle_turn_service)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_TURN_ON, async_handle_turn_service)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_TOGGLE, async_handle_turn_service)
|
||||
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
|
||||
intent.INTENT_TURN_ON, ha.DOMAIN, SERVICE_TURN_ON, "Turned {} on"))
|
||||
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
|
||||
intent.INTENT_TURN_OFF, ha.DOMAIN, SERVICE_TURN_OFF,
|
||||
"Turned {} off"))
|
||||
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
|
||||
intent.INTENT_TOGGLE, ha.DOMAIN, SERVICE_TOGGLE, "Toggled {}"))
|
||||
|
||||
async def async_handle_core_service(call):
|
||||
"""Service handler for handling core services."""
|
||||
if call.service == SERVICE_HOMEASSISTANT_STOP:
|
||||
hass.async_create_task(hass.async_stop())
|
||||
return
|
||||
|
||||
try:
|
||||
errors = await conf_util.async_check_ha_config_file(hass)
|
||||
except HomeAssistantError:
|
||||
return
|
||||
|
||||
if errors:
|
||||
_LOGGER.error(errors)
|
||||
hass.components.persistent_notification.async_create(
|
||||
"Config error. See dev-info panel for details.",
|
||||
"Config validating", "{0}.check_config".format(ha.DOMAIN))
|
||||
return
|
||||
|
||||
if call.service == SERVICE_HOMEASSISTANT_RESTART:
|
||||
hass.async_create_task(hass.async_stop(RESTART_EXIT_CODE))
|
||||
|
||||
async def async_handle_update_service(call):
|
||||
"""Service handler for updating an entity."""
|
||||
tasks = [hass.helpers.entity_component.async_update_entity(entity)
|
||||
for entity in call.data[ATTR_ENTITY_ID]]
|
||||
|
||||
if tasks:
|
||||
await asyncio.wait(tasks)
|
||||
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP, async_handle_core_service)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART, async_handle_core_service)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_CHECK_CONFIG, async_handle_core_service)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_UPDATE_ENTITY, async_handle_update_service,
|
||||
schema=SCHEMA_UPDATE_ENTITY)
|
||||
|
||||
async def async_handle_reload_config(call):
|
||||
"""Service handler for reloading core config."""
|
||||
try:
|
||||
conf = await conf_util.async_hass_config_yaml(hass)
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error(err)
|
||||
return
|
||||
|
||||
# auth only processed during startup
|
||||
await conf_util.async_process_ha_core_config(
|
||||
hass, conf.get(ha.DOMAIN) or {})
|
||||
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, async_handle_reload_config)
|
||||
|
||||
return True
|
||||
|
@ -2,12 +2,12 @@
|
||||
import logging
|
||||
|
||||
import homeassistant.components.alarm_control_panel as alarm
|
||||
from homeassistant.components.abode import ATTRIBUTION, AbodeDevice
|
||||
from homeassistant.components.abode import DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
|
||||
STATE_ALARM_DISARMED)
|
||||
|
||||
from . import ATTRIBUTION, DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -1,10 +1,10 @@
|
||||
"""Support for Abode Security System binary sensors."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
|
||||
DOMAIN as ABODE_DOMAIN)
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
@ -1,13 +1,14 @@
|
||||
"""Support for Abode Security System cameras."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from datetime import timedelta
|
||||
import requests
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.camera import Camera
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
|
||||
|
@ -1,9 +1,10 @@
|
||||
"""Support for Abode Security System covers."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.cover import CoverDevice
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -1,13 +1,14 @@
|
||||
"""Support for Abode Security System lights."""
|
||||
import logging
|
||||
from math import ceil
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS, ATTR_HS_COLOR, ATTR_COLOR_TEMP,
|
||||
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, Light)
|
||||
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR, SUPPORT_COLOR_TEMP, Light)
|
||||
from homeassistant.util.color import (
|
||||
color_temperature_kelvin_to_mired, color_temperature_mired_to_kelvin)
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
"""Support for Abode Security System locks."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.lock import LockDevice
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -1,10 +1,11 @@
|
||||
"""Support for Abode Security System sensors."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.const import (
|
||||
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE)
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
@ -1,10 +1,10 @@
|
||||
"""Support for Abode Security System switches."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
|
||||
DOMAIN as ABODE_DOMAIN)
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
from . import DOMAIN as ABODE_DOMAIN, AbodeAutomation, AbodeDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
1
homeassistant/components/acer_projector/__init__.py
Normal file
1
homeassistant/components/acer_projector/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The acer_projector component."""
|
1
homeassistant/components/actiontec/__init__.py
Normal file
1
homeassistant/components/actiontec/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The actiontec component."""
|
@ -3,12 +3,13 @@ import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.ads import CONF_ADS_VAR, DATA_ADS
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA, BinarySensorDevice)
|
||||
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import CONF_ADS_VAR, DATA_ADS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_NAME = 'ADS binary sensor'
|
||||
|
@ -1,13 +1,15 @@
|
||||
"""Support for ADS light sources."""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
from homeassistant.components.light import Light, ATTR_BRIGHTNESS, \
|
||||
SUPPORT_BRIGHTNESS, PLATFORM_SCHEMA
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, Light)
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.components.ads import DATA_ADS, CONF_ADS_VAR, \
|
||||
CONF_ADS_VAR_BRIGHTNESS
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
DEPENDENCIES = ['ads']
|
||||
DEFAULT_NAME = 'ADS Light'
|
||||
|
@ -4,13 +4,13 @@ import logging
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import ads
|
||||
from homeassistant.components.ads import (
|
||||
CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR)
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_NAME = "ADS sensor"
|
||||
|
@ -3,12 +3,13 @@ import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.ads import CONF_ADS_VAR, DATA_ADS
|
||||
from homeassistant.components.switch import PLATFORM_SCHEMA
|
||||
from homeassistant.const import CONF_NAME
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
|
||||
from . import CONF_ADS_VAR, DATA_ADS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['ads']
|
||||
|
1
homeassistant/components/aftership/__init__.py
Normal file
1
homeassistant/components/aftership/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The aftership component."""
|
1
homeassistant/components/airvisual/__init__.py
Normal file
1
homeassistant/components/airvisual/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The airvisual component."""
|
1
homeassistant/components/aladdin_connect/__init__.py
Normal file
1
homeassistant/components/aladdin_connect/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The aladdin_connect component."""
|
@ -5,7 +5,7 @@ from datetime import timedelta
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, CONF_HOST
|
||||
from homeassistant.helpers.discovery import load_platform
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA
|
||||
@ -20,7 +20,6 @@ DATA_AD = 'alarmdecoder'
|
||||
|
||||
CONF_DEVICE = 'device'
|
||||
CONF_DEVICE_BAUD = 'baudrate'
|
||||
CONF_DEVICE_HOST = 'host'
|
||||
CONF_DEVICE_PATH = 'path'
|
||||
CONF_DEVICE_PORT = 'port'
|
||||
CONF_DEVICE_TYPE = 'type'
|
||||
@ -55,7 +54,7 @@ SIGNAL_REL_MESSAGE = 'alarmdecoder.rel_message'
|
||||
|
||||
DEVICE_SOCKET_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_DEVICE_TYPE): 'socket',
|
||||
vol.Optional(CONF_DEVICE_HOST, default=DEFAULT_DEVICE_HOST): cv.string,
|
||||
vol.Optional(CONF_HOST, default=DEFAULT_DEVICE_HOST): cv.string,
|
||||
vol.Optional(CONF_DEVICE_PORT, default=DEFAULT_DEVICE_PORT): cv.port})
|
||||
|
||||
DEVICE_SERIAL_SCHEMA = vol.Schema({
|
||||
@ -165,7 +164,7 @@ def setup(hass, config):
|
||||
|
||||
controller = False
|
||||
if device_type == 'socket':
|
||||
host = device.get(CONF_DEVICE_HOST)
|
||||
host = device.get(CONF_HOST)
|
||||
port = device.get(CONF_DEVICE_PORT)
|
||||
controller = AlarmDecoder(SocketDevice(interface=(host, port)))
|
||||
elif device_type == 'serial':
|
||||
|
@ -4,12 +4,13 @@ import logging
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.components.alarm_control_panel as alarm
|
||||
from homeassistant.components.alarmdecoder import DATA_AD, SIGNAL_PANEL_MESSAGE
|
||||
from homeassistant.const import (
|
||||
ATTR_CODE, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
|
||||
STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import DATA_AD, SIGNAL_PANEL_MESSAGE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['alarmdecoder']
|
||||
|
@ -2,11 +2,11 @@
|
||||
import logging
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.components.alarmdecoder import (
|
||||
ZONE_SCHEMA, CONF_ZONES, CONF_ZONE_NAME, CONF_ZONE_TYPE,
|
||||
CONF_ZONE_RFID, CONF_ZONE_LOOP, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE,
|
||||
SIGNAL_RFX_MESSAGE, SIGNAL_REL_MESSAGE, CONF_RELAY_ADDR,
|
||||
CONF_RELAY_CHAN)
|
||||
|
||||
from . import (
|
||||
CONF_RELAY_ADDR, CONF_RELAY_CHAN, CONF_ZONE_LOOP, CONF_ZONE_NAME,
|
||||
CONF_ZONE_RFID, CONF_ZONE_TYPE, CONF_ZONES, SIGNAL_REL_MESSAGE,
|
||||
SIGNAL_RFX_MESSAGE, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE, ZONE_SCHEMA)
|
||||
|
||||
DEPENDENCIES = ['alarmdecoder']
|
||||
|
||||
|
@ -2,7 +2,8 @@
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.components.alarmdecoder import (SIGNAL_PANEL_MESSAGE)
|
||||
|
||||
from . import SIGNAL_PANEL_MESSAGE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
1
homeassistant/components/alarmdotcom/__init__.py
Normal file
1
homeassistant/components/alarmdotcom/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The alarmdotcom component."""
|
@ -65,6 +65,12 @@ API_THERMOSTAT_MODES = OrderedDict([
|
||||
(climate.STATE_DRY, 'OFF'),
|
||||
])
|
||||
|
||||
PERCENTAGE_FAN_MAP = {
|
||||
fan.SPEED_LOW: 33,
|
||||
fan.SPEED_MEDIUM: 66,
|
||||
fan.SPEED_HIGH: 100,
|
||||
}
|
||||
|
||||
SMART_HOME_HTTP_ENDPOINT = '/api/alexa/smart_home'
|
||||
|
||||
CONF_DESCRIPTION = 'description'
|
||||
@ -580,6 +586,26 @@ class _AlexaPercentageController(_AlexaInterface):
|
||||
def name(self):
|
||||
return 'Alexa.PercentageController'
|
||||
|
||||
def properties_supported(self):
|
||||
return [{'name': 'percentage'}]
|
||||
|
||||
def properties_retrievable(self):
|
||||
return True
|
||||
|
||||
def get_property(self, name):
|
||||
if name != 'percentage':
|
||||
raise _UnsupportedProperty(name)
|
||||
|
||||
if self.entity.domain == fan.DOMAIN:
|
||||
speed = self.entity.attributes.get(fan.ATTR_SPEED)
|
||||
|
||||
return PERCENTAGE_FAN_MAP.get(speed, 0)
|
||||
|
||||
if self.entity.domain == cover.DOMAIN:
|
||||
return self.entity.attributes.get(cover.ATTR_CURRENT_POSITION, 0)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class _AlexaSpeaker(_AlexaInterface):
|
||||
"""Implements Alexa.Speaker.
|
||||
|
1
homeassistant/components/alpha_vantage/__init__.py
Normal file
1
homeassistant/components/alpha_vantage/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The alpha_vantage component."""
|
1
homeassistant/components/amazon_polly/__init__.py
Normal file
1
homeassistant/components/amazon_polly/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Support for Amazon Polly integration."""
|
@ -8,7 +8,7 @@ import logging
|
||||
|
||||
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
|
||||
|
||||
REQUIREMENTS = ['boto3==1.9.16']
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -304,15 +304,26 @@ class AmbientStation:
|
||||
self.monitored_conditions = monitored_conditions
|
||||
self.stations = {}
|
||||
|
||||
async def ws_connect(self):
|
||||
"""Register handlers and connect to the websocket."""
|
||||
async def _attempt_connect(self):
|
||||
"""Attempt to connect to the socket (retrying later on fail)."""
|
||||
from aioambient.errors import WebsocketError
|
||||
|
||||
try:
|
||||
await self.client.websocket.connect()
|
||||
except WebsocketError as err:
|
||||
_LOGGER.error("Error with the websocket connection: %s", err)
|
||||
self._ws_reconnect_delay = min(
|
||||
2 * self._ws_reconnect_delay, 480)
|
||||
async_call_later(
|
||||
self._hass, self._ws_reconnect_delay, self.ws_connect)
|
||||
|
||||
async def ws_connect(self):
|
||||
"""Register handlers and connect to the websocket."""
|
||||
async def _ws_reconnect(event_time):
|
||||
"""Forcibly disconnect from and reconnect to the websocket."""
|
||||
_LOGGER.debug('Watchdog expired; forcing socket reconnection')
|
||||
await self.client.websocket.disconnect()
|
||||
await self.client.websocket.connect()
|
||||
await self._attempt_connect()
|
||||
|
||||
def on_connect():
|
||||
"""Define a handler to fire when the websocket is connected."""
|
||||
@ -381,15 +392,7 @@ class AmbientStation:
|
||||
self.client.websocket.on_disconnect(on_disconnect)
|
||||
self.client.websocket.on_subscribed(on_subscribed)
|
||||
|
||||
try:
|
||||
await self.client.websocket.connect()
|
||||
except WebsocketError as err:
|
||||
_LOGGER.error("Error with the websocket connection: %s", err)
|
||||
|
||||
self._ws_reconnect_delay = min(2 * self._ws_reconnect_delay, 480)
|
||||
|
||||
async_call_later(
|
||||
self._hass, self._ws_reconnect_delay, self.ws_connect)
|
||||
await self._attempt_connect()
|
||||
|
||||
async def ws_disconnect(self):
|
||||
"""Disconnect from the websocket."""
|
||||
@ -411,6 +414,13 @@ class AmbientWeatherEntity(Entity):
|
||||
self._state = None
|
||||
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
|
||||
def device_info(self):
|
||||
"""Return device registry information for this entity."""
|
||||
|
@ -1,13 +1,13 @@
|
||||
"""Support for Ambient Weather Station binary sensors."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.ambient_station import (
|
||||
SENSOR_TYPES, TYPE_BATT1, TYPE_BATT10, TYPE_BATT2, TYPE_BATT3, TYPE_BATT4,
|
||||
TYPE_BATT5, TYPE_BATT6, TYPE_BATT7, TYPE_BATT8, TYPE_BATT9, TYPE_BATTOUT,
|
||||
AmbientWeatherEntity)
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.const import ATTR_NAME
|
||||
|
||||
from . import (
|
||||
SENSOR_TYPES, TYPE_BATT1, TYPE_BATT2, TYPE_BATT3, TYPE_BATT4, TYPE_BATT5,
|
||||
TYPE_BATT6, TYPE_BATT7, TYPE_BATT8, TYPE_BATT9, TYPE_BATT10, TYPE_BATTOUT,
|
||||
AmbientWeatherEntity)
|
||||
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_BINARY_SENSOR
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -1,10 +1,9 @@
|
||||
"""Support for Ambient Weather Station sensors."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.ambient_station import (
|
||||
SENSOR_TYPES, AmbientWeatherEntity)
|
||||
from homeassistant.const import ATTR_NAME
|
||||
|
||||
from . import SENSOR_TYPES, AmbientWeatherEntity
|
||||
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN, TYPE_SENSOR
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -4,8 +4,6 @@ from datetime import timedelta
|
||||
|
||||
import aiohttp
|
||||
import voluptuous as vol
|
||||
from requests.exceptions import HTTPError, ConnectTimeout
|
||||
from requests.exceptions import ConnectionError as ConnectError
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD,
|
||||
@ -13,7 +11,8 @@ from homeassistant.const import (
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['amcrest==1.2.5']
|
||||
|
||||
REQUIREMENTS = ['amcrest==1.2.7']
|
||||
DEPENDENCIES = ['ffmpeg']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -27,6 +26,7 @@ DEFAULT_NAME = 'Amcrest Camera'
|
||||
DEFAULT_PORT = 80
|
||||
DEFAULT_RESOLUTION = 'high'
|
||||
DEFAULT_STREAM_SOURCE = 'snapshot'
|
||||
DEFAULT_ARGUMENTS = '-pred 1'
|
||||
TIMEOUT = 10
|
||||
|
||||
DATA_AMCREST = 'amcrest'
|
||||
@ -78,7 +78,8 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
vol.All(vol.In(RESOLUTION_LIST)),
|
||||
vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE):
|
||||
vol.All(vol.In(STREAM_SOURCE_LIST)),
|
||||
vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string,
|
||||
vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS):
|
||||
cv.string,
|
||||
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
|
||||
cv.time_period,
|
||||
vol.Optional(CONF_SENSORS):
|
||||
@ -91,7 +92,7 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up the Amcrest IP Camera component."""
|
||||
from amcrest import AmcrestCamera
|
||||
from amcrest import AmcrestCamera, AmcrestError
|
||||
|
||||
hass.data[DATA_AMCREST] = {}
|
||||
amcrest_cams = config[DOMAIN]
|
||||
@ -105,7 +106,7 @@ def setup(hass, config):
|
||||
# pylint: disable=pointless-statement
|
||||
camera.current_time
|
||||
|
||||
except (ConnectError, ConnectTimeout, HTTPError) as ex:
|
||||
except AmcrestError as ex:
|
||||
_LOGGER.error("Unable to connect to Amcrest camera: %s", str(ex))
|
||||
hass.components.persistent_notification.create(
|
||||
'Error: {}<br />'
|
||||
|
@ -2,17 +2,15 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from requests import RequestException
|
||||
from urllib3.exceptions import ReadTimeoutError
|
||||
|
||||
from homeassistant.components.amcrest import (
|
||||
DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT)
|
||||
from homeassistant.components.camera import Camera
|
||||
from homeassistant.components.camera import (
|
||||
Camera, SUPPORT_STREAM)
|
||||
from homeassistant.components.ffmpeg import DATA_FFMPEG
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.helpers.aiohttp_client import (
|
||||
async_get_clientsession, async_aiohttp_proxy_web,
|
||||
async_aiohttp_proxy_stream)
|
||||
async_aiohttp_proxy_stream, async_aiohttp_proxy_web,
|
||||
async_get_clientsession)
|
||||
|
||||
from . import DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT
|
||||
|
||||
DEPENDENCIES = ['amcrest', 'ffmpeg']
|
||||
|
||||
@ -51,13 +49,15 @@ class AmcrestCam(Camera):
|
||||
|
||||
async def async_camera_image(self):
|
||||
"""Return a still image response from the camera."""
|
||||
from amcrest import AmcrestError
|
||||
|
||||
async with self._snapshot_lock:
|
||||
try:
|
||||
# Send the request to snap a picture and return raw jpg data
|
||||
response = await self.hass.async_add_executor_job(
|
||||
self._camera.snapshot, self._resolution)
|
||||
return response.data
|
||||
except (RequestException, ReadTimeoutError, ValueError) as error:
|
||||
except AmcrestError as error:
|
||||
_LOGGER.error(
|
||||
'Could not get camera image due to error %s', error)
|
||||
return None
|
||||
@ -79,7 +79,7 @@ class AmcrestCam(Camera):
|
||||
self.hass, request, stream_coro)
|
||||
|
||||
# streaming via ffmpeg
|
||||
from haffmpeg import CameraMjpeg
|
||||
from haffmpeg.camera import CameraMjpeg
|
||||
|
||||
streaming_url = self._camera.rtsp_url(typeno=self._resolution)
|
||||
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
|
||||
@ -87,8 +87,9 @@ class AmcrestCam(Camera):
|
||||
streaming_url, extra_cmd=self._ffmpeg_arguments)
|
||||
|
||||
try:
|
||||
stream_reader = await stream.get_reader()
|
||||
return await async_aiohttp_proxy_stream(
|
||||
self.hass, request, stream,
|
||||
self.hass, request, stream_reader,
|
||||
self._ffmpeg.ffmpeg_stream_content_type)
|
||||
finally:
|
||||
await stream.close()
|
||||
@ -98,6 +99,11 @@ class AmcrestCam(Camera):
|
||||
"""Return the name of this camera."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return supported features."""
|
||||
return SUPPORT_STREAM
|
||||
|
||||
@property
|
||||
def stream_source(self):
|
||||
"""Return the source of the stream."""
|
||||
|
@ -2,9 +2,10 @@
|
||||
from datetime import timedelta
|
||||
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.helpers.entity import Entity
|
||||
|
||||
from . import DATA_AMCREST, SENSORS
|
||||
|
||||
DEPENDENCIES = ['amcrest']
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
"""Support for toggling Amcrest IP camera settings."""
|
||||
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 . import DATA_AMCREST, SWITCHES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['amcrest']
|
||||
|
@ -18,7 +18,7 @@ from homeassistant.helpers.dispatcher import (
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||
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)
|
||||
|
||||
REQUIREMENTS = ['pydroid-ipcam==0.8']
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Support for Android IP Webcam binary sensors."""
|
||||
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']
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
"""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 . import (
|
||||
CONF_HOST, CONF_NAME, CONF_SENSORS, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
|
||||
AndroidIPCamEntity)
|
||||
|
||||
DEPENDENCIES = ['android_ip_webcam']
|
||||
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
"""Support for Android IP Webcam settings."""
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
from homeassistant.components.android_ip_webcam import (
|
||||
KEY_MAP, ICON_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST,
|
||||
CONF_NAME, CONF_SWITCHES)
|
||||
|
||||
from . import (
|
||||
CONF_HOST, CONF_NAME, CONF_SWITCHES, DATA_IP_WEBCAM, ICON_MAP, KEY_MAP,
|
||||
AndroidIPCamEntity)
|
||||
|
||||
DEPENDENCIES = ['android_ip_webcam']
|
||||
|
||||
|
@ -22,7 +22,7 @@ import homeassistant.helpers.config_validation as cv
|
||||
|
||||
ANDROIDTV_DOMAIN = 'androidtv'
|
||||
|
||||
REQUIREMENTS = ['androidtv==0.0.12']
|
||||
REQUIREMENTS = ['androidtv==0.0.14']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -40,6 +40,8 @@ CONF_ADB_SERVER_IP = 'adb_server_ip'
|
||||
CONF_ADB_SERVER_PORT = 'adb_server_port'
|
||||
CONF_APPS = 'apps'
|
||||
CONF_GET_SOURCES = 'get_sources'
|
||||
CONF_TURN_ON_COMMAND = 'turn_on_command'
|
||||
CONF_TURN_OFF_COMMAND = 'turn_off_command'
|
||||
|
||||
DEFAULT_NAME = 'Android TV'
|
||||
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({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_DEVICE_CLASS, default=DEFAULT_DEVICE_CLASS):
|
||||
vol.In(DEVICE_CLASSES),
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
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_PORT, default=DEFAULT_ADB_SERVER_PORT):
|
||||
cv.port,
|
||||
vol.Optional(CONF_GET_SOURCES, default=DEFAULT_GET_SOURCES): cv.boolean,
|
||||
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.
|
||||
@ -136,12 +132,16 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
else:
|
||||
if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV:
|
||||
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 \
|
||||
else 'Android TV'
|
||||
else:
|
||||
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 \
|
||||
else 'Fire TV'
|
||||
|
||||
@ -163,7 +163,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
output = target_device.adb_command(cmd)
|
||||
|
||||
# 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",
|
||||
cmd, target_device.entity_id, repr(output))
|
||||
|
||||
@ -199,7 +199,8 @@ def adb_decorator(override_available=False):
|
||||
class ADBDevice(MediaPlayerDevice):
|
||||
"""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."""
|
||||
from androidtv.constants import APPS, KEYS
|
||||
|
||||
@ -209,6 +210,9 @@ class ADBDevice(MediaPlayerDevice):
|
||||
self._apps.update(apps)
|
||||
self._keys = KEYS
|
||||
|
||||
self.turn_on_command = turn_on_command
|
||||
self.turn_off_command = turn_off_command
|
||||
|
||||
# ADB exceptions to catch
|
||||
if not self.aftv.adb_server_ip:
|
||||
# Using "python-adb" (Python ADB implementation)
|
||||
@ -223,7 +227,7 @@ class ADBDevice(MediaPlayerDevice):
|
||||
TcpTimeoutException)
|
||||
else:
|
||||
# Using "pure-python-adb" (communicate with ADB server)
|
||||
self.exceptions = (ConnectionResetError,)
|
||||
self.exceptions = (ConnectionResetError, RuntimeError)
|
||||
|
||||
# Property attributes
|
||||
self._available = self.aftv.available
|
||||
@ -278,12 +282,18 @@ class ADBDevice(MediaPlayerDevice):
|
||||
@adb_decorator()
|
||||
def turn_on(self):
|
||||
"""Turn on the device."""
|
||||
self.aftv.turn_on()
|
||||
if self.turn_on_command:
|
||||
self.aftv.adb_shell(self.turn_on_command)
|
||||
else:
|
||||
self.aftv.turn_on()
|
||||
|
||||
@adb_decorator()
|
||||
def turn_off(self):
|
||||
"""Turn off the device."""
|
||||
self.aftv.turn_off()
|
||||
if self.turn_off_command:
|
||||
self.aftv.adb_shell(self.turn_off_command)
|
||||
else:
|
||||
self.aftv.turn_off()
|
||||
|
||||
@adb_decorator()
|
||||
def media_previous_track(self):
|
||||
@ -311,9 +321,11 @@ class ADBDevice(MediaPlayerDevice):
|
||||
class AndroidTVDevice(ADBDevice):
|
||||
"""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."""
|
||||
super().__init__(aftv, name, apps)
|
||||
super().__init__(aftv, name, apps, turn_on_command,
|
||||
turn_off_command)
|
||||
|
||||
self._device = None
|
||||
self._muted = None
|
||||
@ -392,9 +404,11 @@ class AndroidTVDevice(ADBDevice):
|
||||
class FireTVDevice(ADBDevice):
|
||||
"""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."""
|
||||
super().__init__(aftv, name, apps)
|
||||
super().__init__(aftv, name, apps, turn_on_command,
|
||||
turn_off_command)
|
||||
|
||||
self._get_sources = get_sources
|
||||
self._running_apps = None
|
||||
|
1
homeassistant/components/anel_pwrctrl/__init__.py
Normal file
1
homeassistant/components/anel_pwrctrl/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The anel_pwrctrl component."""
|
1
homeassistant/components/anthemav/__init__.py
Normal file
1
homeassistant/components/anthemav/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The anthemav component."""
|
1
homeassistant/components/api_streams/__init__.py
Normal file
1
homeassistant/components/api_streams/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The api_streams component."""
|
1
homeassistant/components/apns/__init__.py
Normal file
1
homeassistant/components/apns/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The apns component."""
|
@ -9,13 +9,14 @@ import os
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.helpers.event import track_state_change
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.components.notify import (
|
||||
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.const import ATTR_NAME, CONF_NAME, CONF_PLATFORM
|
||||
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']
|
||||
|
@ -1,8 +1,6 @@
|
||||
"""Support for Apple TV media player."""
|
||||
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.const import (
|
||||
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
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from . import ATTR_ATV, ATTR_POWER, DATA_APPLE_TV, DATA_ENTITIES
|
||||
|
||||
DEPENDENCIES = ['apple_tv']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""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.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']
|
||||
|
||||
|
@ -4,12 +4,13 @@ import logging
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||
from homeassistant.const import (CONF_MONITORED_CONDITIONS,
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||
from homeassistant.const import (
|
||||
CONF_MONITORED_CONDITIONS, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.entity import Entity
|
||||
import homeassistant.components.aqualogic as aq
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import DOMAIN, UPDATE_TOPIC
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -46,7 +47,7 @@ async def async_setup_platform(
|
||||
"""Set up the sensor platform."""
|
||||
sensors = []
|
||||
|
||||
processor = hass.data[aq.DOMAIN]
|
||||
processor = hass.data[DOMAIN]
|
||||
for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
|
||||
sensors.append(AquaLogicSensor(processor, sensor_type))
|
||||
|
||||
@ -95,7 +96,7 @@ class AquaLogicSensor(Entity):
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||
aq.UPDATE_TOPIC, self.async_update_callback)
|
||||
UPDATE_TOPIC, self.async_update_callback)
|
||||
|
||||
@callback
|
||||
def async_update_callback(self):
|
||||
|
@ -3,11 +3,12 @@ import logging
|
||||
|
||||
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
|
||||
import homeassistant.components.aqualogic as aq
|
||||
from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA
|
||||
from homeassistant.const import (CONF_MONITORED_CONDITIONS)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import DOMAIN, UPDATE_TOPIC
|
||||
|
||||
DEPENDENCIES = ['aqualogic']
|
||||
|
||||
@ -37,7 +38,7 @@ async def async_setup_platform(
|
||||
"""Set up the switch platform."""
|
||||
switches = []
|
||||
|
||||
processor = hass.data[aq.DOMAIN]
|
||||
processor = hass.data[DOMAIN]
|
||||
for switch_type in config.get(CONF_MONITORED_CONDITIONS):
|
||||
switches.append(AquaLogicSwitch(processor, switch_type))
|
||||
|
||||
@ -101,7 +102,7 @@ class AquaLogicSwitch(SwitchDevice):
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||
aq.UPDATE_TOPIC, self.async_update_callback)
|
||||
UPDATE_TOPIC, self.async_update_callback)
|
||||
|
||||
@callback
|
||||
def async_update_callback(self):
|
||||
|
1
homeassistant/components/aquostv/__init__.py
Normal file
1
homeassistant/components/aquostv/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The aquostv component."""
|
1
homeassistant/components/arest/__init__.py
Normal file
1
homeassistant/components/arest/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The arest component."""
|
@ -3,16 +3,16 @@ import logging
|
||||
|
||||
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 (
|
||||
AlarmControlPanel, PLATFORM_SCHEMA)
|
||||
from homeassistant.components.arlo import (
|
||||
DATA_ARLO, ATTRIBUTION, SIGNAL_UPDATE_ARLO)
|
||||
PLATFORM_SCHEMA, AlarmControlPanel)
|
||||
from homeassistant.const import (
|
||||
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__)
|
||||
|
||||
|
@ -3,16 +3,18 @@ import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
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.camera import PLATFORM_SCHEMA, Camera
|
||||
from homeassistant.components.ffmpeg import DATA_FFMPEG
|
||||
from homeassistant.const import ATTR_BATTERY_LEVEL
|
||||
from homeassistant.core import callback
|
||||
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 . import DATA_ARLO, DEFAULT_BRAND, SIGNAL_UPDATE_ARLO
|
||||
|
||||
DEPENDENCIES = ['arlo', 'ffmpeg']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARLO_MODE_ARMED = 'armed'
|
||||
@ -28,8 +30,7 @@ ATTR_UNSEEN_VIDEOS = 'unseen_videos'
|
||||
ATTR_LAST_REFRESH = 'last_refresh'
|
||||
|
||||
CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
|
||||
|
||||
DEPENDENCIES = ['arlo', 'ffmpeg']
|
||||
DEFAULT_ARGUMENTS = '-pred 1'
|
||||
|
||||
POWERSAVE_MODE_MAPPING = {
|
||||
1: 'best_battery_life',
|
||||
@ -38,7 +39,7 @@ POWERSAVE_MODE_MAPPING = {
|
||||
}
|
||||
|
||||
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):
|
||||
"""Generate an HTTP MJPEG stream from the camera."""
|
||||
from haffmpeg import CameraMjpeg
|
||||
from haffmpeg.camera import CameraMjpeg
|
||||
video = self._camera.last_video
|
||||
if not video:
|
||||
error_msg = \
|
||||
@ -97,8 +98,9 @@ class ArloCam(Camera):
|
||||
video.video_url, extra_cmd=self._ffmpeg_arguments)
|
||||
|
||||
try:
|
||||
stream_reader = await stream.get_reader()
|
||||
return await async_aiohttp_proxy_stream(
|
||||
self.hass, request, stream,
|
||||
self.hass, request, stream_reader,
|
||||
self._ffmpeg.ffmpeg_stream_content_type)
|
||||
finally:
|
||||
await stream.close()
|
||||
|
@ -3,19 +3,18 @@ import logging
|
||||
|
||||
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.const import (
|
||||
ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, TEMP_CELSIUS,
|
||||
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY)
|
||||
|
||||
ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, 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.entity import Entity
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
|
||||
from . import ATTRIBUTION, DATA_ARLO, DEFAULT_BRAND, SIGNAL_UPDATE_ARLO
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['arlo']
|
||||
|
1
homeassistant/components/aruba/__init__.py
Normal file
1
homeassistant/components/aruba/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The aruba component."""
|
1
homeassistant/components/arwn/__init__.py
Normal file
1
homeassistant/components/arwn/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The arwn component."""
|
1
homeassistant/components/asterisk_cdr/__init__.py
Normal file
1
homeassistant/components/asterisk_cdr/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The asterisk_cdr component."""
|
@ -1,12 +1,13 @@
|
||||
"""Support for the Asterisk Voicemail interface."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.asterisk_mbox import DOMAIN as ASTERISK_DOMAIN
|
||||
from homeassistant.components.mailbox import (
|
||||
CONTENT_TYPE_MPEG, Mailbox, StreamError)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from . import DOMAIN as ASTERISK_DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['asterisk_mbox']
|
||||
|
@ -6,9 +6,10 @@ https://home-assistant.io/components/device_tracker.asuswrt/
|
||||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.asuswrt import DATA_ASUSWRT
|
||||
from homeassistant.components.device_tracker import DeviceScanner
|
||||
|
||||
from . import DATA_ASUSWRT
|
||||
|
||||
DEPENDENCIES = ['asuswrt']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
@ -7,7 +7,8 @@ https://home-assistant.io/components/sensor.asuswrt/
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.components.asuswrt import DATA_ASUSWRT
|
||||
|
||||
from . import DATA_ASUSWRT
|
||||
|
||||
DEPENDENCIES = ['asuswrt']
|
||||
|
@ -1,9 +1,10 @@
|
||||
"""Support for August binary sensors."""
|
||||
from datetime import datetime, timedelta
|
||||
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__)
|
||||
|
||||
|
@ -3,9 +3,10 @@ from datetime import timedelta
|
||||
|
||||
import requests
|
||||
|
||||
from homeassistant.components.august import DATA_AUGUST, DEFAULT_TIMEOUT
|
||||
from homeassistant.components.camera import Camera
|
||||
|
||||
from . import DATA_AUGUST, DEFAULT_TIMEOUT
|
||||
|
||||
DEPENDENCIES = ['august']
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=5)
|
||||
|
@ -1,11 +1,12 @@
|
||||
"""Support for August lock."""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from homeassistant.components.august import DATA_AUGUST
|
||||
from homeassistant.components.lock import LockDevice
|
||||
from homeassistant.const import ATTR_BATTERY_LEVEL
|
||||
|
||||
from . import DATA_AUGUST
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['august']
|
||||
|
1
homeassistant/components/aurora/__init__.py
Normal file
1
homeassistant/components/aurora/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The aurora component."""
|
16
homeassistant/components/auth/.translations/bg.json
Normal file
16
homeassistant/components/auth/.translations/bg.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
@ -9,13 +9,15 @@
|
||||
},
|
||||
"step": {
|
||||
"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"
|
||||
},
|
||||
"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": "Egyszeri Jelsz\u00f3 \u00c9rtes\u00edt\u00e9s"
|
||||
},
|
||||
"totp": {
|
||||
"error": {
|
||||
|
@ -81,7 +81,8 @@ from . import indieauth
|
||||
async def async_setup(hass, store_result):
|
||||
"""Component to allow users to login."""
|
||||
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(
|
||||
LoginFlowResourceView(hass.auth.login_flow, store_result))
|
||||
|
||||
@ -142,9 +143,10 @@ class LoginFlowIndexView(HomeAssistantView):
|
||||
name = 'api:auth:login_flow'
|
||||
requires_auth = False
|
||||
|
||||
def __init__(self, flow_mgr):
|
||||
def __init__(self, flow_mgr, store_result):
|
||||
"""Initialize the flow manager index view."""
|
||||
self._flow_mgr = flow_mgr
|
||||
self._store_result = store_result
|
||||
|
||||
async def get(self, request):
|
||||
"""Do not allow index of flows in progress."""
|
||||
@ -179,6 +181,12 @@ class LoginFlowIndexView(HomeAssistantView):
|
||||
except data_entry_flow.UnknownStep:
|
||||
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))
|
||||
|
||||
|
||||
|
1
homeassistant/components/automatic/__init__.py
Normal file
1
homeassistant/components/automatic/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The automatic component."""
|
@ -6,20 +6,20 @@ import logging
|
||||
|
||||
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 (
|
||||
ATTR_ENTITY_ID, CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
||||
SERVICE_TOGGLE, SERVICE_RELOAD, EVENT_HOMEASSISTANT_START, CONF_ID,
|
||||
EVENT_AUTOMATION_TRIGGERED, ATTR_NAME)
|
||||
ATTR_ENTITY_ID, ATTR_NAME, CONF_ID, CONF_PLATFORM,
|
||||
EVENT_AUTOMATION_TRIGGERED, EVENT_HOMEASSISTANT_START, SERVICE_RELOAD,
|
||||
SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON)
|
||||
from homeassistant.core import Context, CoreState
|
||||
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_component import EntityComponent
|
||||
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
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
DOMAIN = 'automation'
|
||||
DEPENDENCIES = ['group']
|
||||
@ -54,9 +54,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
def _platform_validator(config):
|
||||
"""Validate it is a valid platform."""
|
||||
try:
|
||||
platform = importlib.import_module(
|
||||
'homeassistant.components.automation.{}'.format(
|
||||
config[CONF_PLATFORM]))
|
||||
platform = importlib.import_module('.{}'.format(config[CONF_PLATFORM]),
|
||||
__name__)
|
||||
except ImportError:
|
||||
raise vol.Invalid('Invalid platform specified') from None
|
||||
|
||||
|
1
homeassistant/components/avion/__init__.py
Normal file
1
homeassistant/components/avion/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The avion component."""
|
@ -4,6 +4,7 @@ Support for Avion dimmers.
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/light.avion/
|
||||
"""
|
||||
import importlib
|
||||
import logging
|
||||
import time
|
||||
|
||||
@ -38,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up an Avion switch."""
|
||||
# pylint: disable=no-member
|
||||
import avion
|
||||
avion = importlib.import_module('avion')
|
||||
|
||||
lights = []
|
||||
if CONF_USERNAME in config and CONF_PASSWORD in config:
|
||||
@ -108,7 +109,7 @@ class AvionLight(Light):
|
||||
def set_state(self, brightness):
|
||||
"""Set the state of this lamp to the provided brightness."""
|
||||
# pylint: disable=no-member
|
||||
import avion
|
||||
avion = importlib.import_module('avion')
|
||||
|
||||
# Bluetooth LE is unreliable, and the connection may drop at any
|
||||
# time. Make an effort to re-establish the link.
|
1
homeassistant/components/awair/__init__.py
Normal file
1
homeassistant/components/awair/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The awair component."""
|
176
homeassistant/components/aws/__init__.py
Normal file
176
homeassistant/components/aws/__init__.py
Normal 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
Loading…
x
Reference in New Issue
Block a user