Merge pull request #40179 from home-assistant/rc

This commit is contained in:
Paulus Schoutsen 2020-09-17 17:37:29 +02:00 committed by GitHub
commit 58c6702080
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2974 changed files with 77842 additions and 20333 deletions

View File

@ -8,10 +8,6 @@ omit =
homeassistant/scripts/*.py
# omit pieces of code that rely on external devices being present
homeassistant/components/accuweather/__init__.py
homeassistant/components/accuweather/const.py
homeassistant/components/accuweather/sensor.py
homeassistant/components/accuweather/weather.py
homeassistant/components/acer_projector/switch.py
homeassistant/components/actiontec/device_tracker.py
homeassistant/components/acmeda/__init__.py
@ -29,6 +25,7 @@ omit =
homeassistant/components/ads/*
homeassistant/components/aftership/sensor.py
homeassistant/components/agent_dvr/__init__.py
homeassistant/components/agent_dvr/alarm_control_panel.py
homeassistant/components/agent_dvr/camera.py
homeassistant/components/agent_dvr/const.py
homeassistant/components/agent_dvr/helpers.py
@ -103,11 +100,11 @@ omit =
homeassistant/components/braviatv/__init__.py
homeassistant/components/braviatv/const.py
homeassistant/components/braviatv/media_player.py
homeassistant/components/broadlink/__init__.py
homeassistant/components/broadlink/const.py
homeassistant/components/broadlink/device.py
homeassistant/components/broadlink/remote.py
homeassistant/components/broadlink/sensor.py
homeassistant/components/broadlink/switch.py
homeassistant/components/broadlink/updater.py
homeassistant/components/brottsplatskartan/sensor.py
homeassistant/components/browser/*
homeassistant/components/brunt/cover.py
@ -169,7 +166,9 @@ omit =
homeassistant/components/deutsche_bahn/sensor.py
homeassistant/components/devolo_home_control/__init__.py
homeassistant/components/devolo_home_control/binary_sensor.py
homeassistant/components/devolo_home_control/climate.py
homeassistant/components/devolo_home_control/const.py
homeassistant/components/devolo_home_control/cover.py
homeassistant/components/devolo_home_control/devolo_device.py
homeassistant/components/devolo_home_control/devolo_multi_level_switch.py
homeassistant/components/devolo_home_control/light.py
@ -221,7 +220,6 @@ omit =
homeassistant/components/emby/media_player.py
homeassistant/components/emoncms/sensor.py
homeassistant/components/emoncms_history/*
homeassistant/components/emulated_hue/upnp.py
homeassistant/components/enigma2/media_player.py
homeassistant/components/enocean/__init__.py
homeassistant/components/enocean/binary_sensor.py
@ -309,8 +307,6 @@ omit =
homeassistant/components/gc100/*
homeassistant/components/geniushub/*
homeassistant/components/geizhals/sensor.py
homeassistant/components/gios/__init__.py
homeassistant/components/gios/air_quality.py
homeassistant/components/github/sensor.py
homeassistant/components/gitlab_ci/sensor.py
homeassistant/components/gitter/sensor.py
@ -397,7 +393,17 @@ omit =
homeassistant/components/ihc/*
homeassistant/components/imap/sensor.py
homeassistant/components/imap_email_content/sensor.py
homeassistant/components/insteon/*
homeassistant/components/insteon/binary_sensor.py
homeassistant/components/insteon/climate.py
homeassistant/components/insteon/const.py
homeassistant/components/insteon/cover.py
homeassistant/components/insteon/fan.py
homeassistant/components/insteon/insteon_entity.py
homeassistant/components/insteon/ipdb.py
homeassistant/components/insteon/light.py
homeassistant/components/insteon/schemas.py
homeassistant/components/insteon/switch.py
homeassistant/components/insteon/utils.py
homeassistant/components/incomfort/*
homeassistant/components/intesishome/*
homeassistant/components/ios/*
@ -440,6 +446,7 @@ omit =
homeassistant/components/knx/climate.py
homeassistant/components/knx/cover.py
homeassistant/components/kodi/__init__.py
homeassistant/components/kodi/browse_media.py
homeassistant/components/kodi/const.py
homeassistant/components/kodi/media_player.py
homeassistant/components/kodi/notify.py
@ -581,8 +588,7 @@ omit =
homeassistant/components/nuki/lock.py
homeassistant/components/nut/sensor.py
homeassistant/components/nx584/alarm_control_panel.py
homeassistant/components/nzbget/__init__.py
homeassistant/components/nzbget/sensor.py
homeassistant/components/nzbget/coordinator.py
homeassistant/components/obihai/*
homeassistant/components/octoprint/*
homeassistant/components/oem/climate.py
@ -617,6 +623,9 @@ omit =
homeassistant/components/openuv/sensor.py
homeassistant/components/openweathermap/sensor.py
homeassistant/components/openweathermap/weather.py
homeassistant/components/openweathermap/forecast_update_coordinator.py
homeassistant/components/openweathermap/weather_update_coordinator.py
homeassistant/components/openweathermap/abstract_owm_sensor.py
homeassistant/components/opnsense/*
homeassistant/components/opple/light.py
homeassistant/components/orangepi_gpio/*
@ -647,19 +656,16 @@ omit =
homeassistant/components/plaato/*
homeassistant/components/plex/media_player.py
homeassistant/components/plex/sensor.py
homeassistant/components/plugwise/__init__.py
homeassistant/components/plugwise/binary_sensor.py
homeassistant/components/plugwise/climate.py
homeassistant/components/plugwise/sensor.py
homeassistant/components/plugwise/switch.py
homeassistant/components/plum_lightpad/light.py
homeassistant/components/pocketcasts/sensor.py
homeassistant/components/point/*
homeassistant/components/poolsense/__init__.py
homeassistant/components/poolsense/sensor.py
homeassistant/components/poolsense/binary_sensor.py
homeassistant/components/prezzibenzina/sensor.py
homeassistant/components/proliphix/climate.py
homeassistant/components/progettihwsw/__init__.py
homeassistant/components/progettihwsw/binary_sensor.py
homeassistant/components/progettihwsw/switch.py
homeassistant/components/prometheus/*
homeassistant/components/prowl/notify.py
homeassistant/components/proxmoxve/*
@ -711,6 +717,10 @@ omit =
homeassistant/components/roomba/roomba.py
homeassistant/components/roomba/sensor.py
homeassistant/components/roomba/vacuum.py
homeassistant/components/roon/__init__.py
homeassistant/components/roon/const.py
homeassistant/components/roon/media_player.py
homeassistant/components/roon/server.py
homeassistant/components/route53/*
homeassistant/components/rova/sensor.py
homeassistant/components/rpi_camera/*
@ -735,7 +745,6 @@ omit =
homeassistant/components/sensehat/light.py
homeassistant/components/sensehat/sensor.py
homeassistant/components/sensibo/climate.py
homeassistant/components/sentry/__init__.py
homeassistant/components/serial/sensor.py
homeassistant/components/serial_pm/sensor.py
homeassistant/components/sesame/lock.py
@ -743,6 +752,13 @@ omit =
homeassistant/components/seventeentrack/sensor.py
homeassistant/components/shiftr/*
homeassistant/components/shodan/sensor.py
homeassistant/components/shelly/__init__.py
homeassistant/components/shelly/binary_sensor.py
homeassistant/components/shelly/cover.py
homeassistant/components/shelly/entity.py
homeassistant/components/shelly/light.py
homeassistant/components/shelly/sensor.py
homeassistant/components/shelly/switch.py
homeassistant/components/sht31/sensor.py
homeassistant/components/sigfox/sensor.py
homeassistant/components/simplepush/notify.py
@ -801,7 +817,8 @@ omit =
homeassistant/components/streamlabswater/*
homeassistant/components/suez_water/*
homeassistant/components/supervisord/sensor.py
homeassistant/components/surepetcare/*.py
homeassistant/components/surepetcare/__init__.py
homeassistant/components/surepetcare/sensor.py
homeassistant/components/swiss_hydrological_data/sensor.py
homeassistant/components/swiss_public_transport/sensor.py
homeassistant/components/swisscom/device_tracker.py
@ -921,6 +938,7 @@ omit =
homeassistant/components/vesync/__init__.py
homeassistant/components/vesync/common.py
homeassistant/components/vesync/const.py
homeassistant/components/vesync/fan.py
homeassistant/components/vesync/switch.py
homeassistant/components/viaggiatreno/sensor.py
homeassistant/components/vicare/*
@ -1010,7 +1028,6 @@ omit =
homeassistant/components/supla/*
homeassistant/components/zwave/util.py
homeassistant/components/ozw/__init__.py
homeassistant/components/ozw/discovery.py
homeassistant/components/ozw/entity.py
homeassistant/components/ozw/services.py

View File

@ -16,7 +16,7 @@
<!--
Provide details about the versions you are using, which helps us to reproduce
and find the issue quicker. Version information is found in the
Home Assistant frontend: Developer tools -> Info.
Home Assistant frontend: Configuration -> Info.
-->
- Home Assistant Core release with the issue:

View File

@ -20,7 +20,7 @@ about: Report an issue with Home Assistant Core
<!--
Provide details about the versions you are using, which helps us to reproduce
and find the issue quicker. Version information is found in the
Home Assistant frontend: Developer tools -> Info.
Home Assistant frontend: Configuration -> Info.
-->
- Home Assistant Core release with the issue:

View File

@ -13,7 +13,7 @@
## Proposed change
<!--
<!--
Describe the big picture of your changes here to communicate to the
maintainers why we should accept this pull request. If it fixes a bug
or resolves a feature request, be sure to link to that issue in the
@ -24,7 +24,7 @@
## Type of change
<!--
What type of change does your PR introduce to Home Assistant?
NOTE: Please, check only 1! box!
NOTE: Please, check only 1! box!
If your PR requires multiple boxes to be checked, you'll most likely need to
split it into multiple PRs. This makes things easier and faster to code review.
-->
@ -98,6 +98,29 @@ The integration reached or maintains the following [Integration Quality Scale][q
- [ ] 🥇 Gold
- [ ] 🏆 Platinum
<!--
This project is very active and we have a high turnover of pull requests.
Unfortunately, the number of incoming pull requests is higher than what our
reviewers can review and merge so there is a long backlog of pull requests
waiting for review. You can help here!
By reviewing another pull request, you will help raise the code quality of
that pull request and the final review will be faster. This way the general
pace of pull request reviews will go up and your wait time will go down.
When picking a pull request to review, try to choose one that hasn't yet
been reviewed.
Thanks for helping out!
-->
To help with the load of incoming pull requests:
- [ ] I have reviewed two other [open pull requests][prs] in this repository.
[prs]: https://github.com/home-assistant/core/pulls?q=is%3Aopen+is%3Apr+-author%3A%40me+-draft%3Atrue+-label%3Awaiting-for-upstream+sort%3Acreated-asc+-review%3Aapproved
<!--
Thank you for contributing <3

View File

@ -10,6 +10,7 @@ on:
pull_request: ~
env:
CACHE_VERSION: 1
DEFAULT_PYTHON: 3.7
PRE_COMMIT_HOME: ~/.cache/pre-commit
@ -24,7 +25,7 @@ jobs:
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
@ -33,34 +34,31 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
restore-keys: |
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_test.txt') }}-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_test.txt') }}-
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
pip install -U pip==20.1.1 setuptools
pip install -U pip setuptools
pip install -r requirements.txt -r requirements_test.txt
# Uninstalling typing as a workaround. Eventually we should make sure
# all our dependencies drop typing.
# Find offending deps with `pipdeptree -r -p typing`
pip uninstall -y typing
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v2
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
restore-keys: |
${{ runner.os }}-pre-commit-
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-
- name: Install pre-commit dependencies
if: steps.cache-precommit.outputs.cache-hit != 'true'
run: |
@ -75,7 +73,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -85,8 +83,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -100,7 +99,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -119,7 +118,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -129,8 +128,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -144,7 +144,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -163,7 +163,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -173,8 +173,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -188,7 +189,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -229,7 +230,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -239,8 +240,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -254,7 +256,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -276,7 +278,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -286,8 +288,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -301,7 +304,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -323,7 +326,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -333,8 +336,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -348,7 +352,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -367,7 +371,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -377,8 +381,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -392,7 +397,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -414,7 +419,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -424,8 +429,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -439,7 +445,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -469,7 +475,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -479,8 +485,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -494,7 +501,7 @@ jobs:
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@ -516,7 +523,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -526,8 +533,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -548,7 +556,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.1
uses: actions/setup-python@v2.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -558,8 +566,9 @@ jobs:
with:
path: venv
key: >-
${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version
}}-${{ hashFiles('requirements.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements.txt') }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
@ -582,34 +591,28 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name:
Restore full Python ${{ matrix.python-version }} virtual environment
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v2
with:
path: venv
key: >-
${{ runner.os }}-venv-${{ matrix.python-version }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('requirements_all.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{
matrix.python-version }}-${{ hashFiles('requirements_test.txt')
}}-${{ hashFiles('requirements_all.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
restore-keys: |
${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('requirements_all.txt') }}
${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}
${{ runner.os }}-venv-${{ matrix.python-version }}-
- name:
Create full Python ${{ matrix.python-version }} virtual environment
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('requirements_all.txt') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-
- name: Create full Python ${{ matrix.python-version }} virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
pip install -U pip==20.1.1 setuptools wheel
pip install -U pip setuptools wheel
pip install -r requirements_all.txt
pip install -r requirements_test.txt
# Uninstalling typing as a workaround. Eventually we should make sure
# all our dependencies drop typing.
# Find offending deps with `pipdeptree -r -p typing`
pip uninstall -y typing
pip install -e .
pylint:
@ -623,16 +626,15 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name:
Restore full Python ${{ matrix.python-version }} virtual environment
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v2
with:
path: venv
key: >-
${{ runner.os }}-venv-${{ matrix.python-version }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('requirements_all.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{
matrix.python-version }}-${{ hashFiles('requirements_test.txt')
}}-${{ hashFiles('requirements_all.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
@ -658,16 +660,15 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name:
Restore full Python ${{ matrix.python-version }} virtual environment
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v2
with:
path: venv
key: >-
${{ runner.os }}-venv-${{ matrix.python-version }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('requirements_all.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{
matrix.python-version }}-${{ hashFiles('requirements_test.txt')
}}-${{ hashFiles('requirements_all.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
@ -695,16 +696,15 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name:
Restore full Python ${{ matrix.python-version }} virtual environment
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v2
with:
path: venv
key: >-
${{ runner.os }}-venv-${{ matrix.python-version }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('requirements_all.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{
matrix.python-version }}-${{ hashFiles('requirements_test.txt')
}}-${{ hashFiles('requirements_all.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
@ -737,7 +737,7 @@ jobs:
-p no:sugar \
tests
- name: Upload coverage artifact
uses: actions/upload-artifact@v2.1.3
uses: actions/upload-artifact@v2.1.4
with:
name: coverage-${{ matrix.python-version }}-group${{ matrix.group }}
path: .coverage
@ -756,16 +756,15 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name:
Restore full Python ${{ matrix.python-version }} virtual environment
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v2
with:
path: venv
key: >-
${{ runner.os }}-venv-${{ matrix.python-version }}-${{
hashFiles('requirements_test.txt') }}-${{
hashFiles('requirements_all.txt') }}-${{
${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{
matrix.python-version }}-${{ hashFiles('requirements_test.txt')
}}-${{ hashFiles('requirements_all.txt') }}-${{
hashFiles('homeassistant/package_constraints.txt') }}
- name: Fail job if Python cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
@ -781,4 +780,4 @@ jobs:
coverage report --fail-under=94
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1.0.12
uses: codecov/codecov-action@v1.0.13

View File

@ -1,11 +1,11 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.3.0
rev: v2.7.2
hooks:
- id: pyupgrade
args: [--py37-plus]
- repo: https://github.com/psf/black
rev: 19.10b0
rev: 20.8b1
hooks:
- id: black
args:
@ -13,11 +13,11 @@ repos:
- --quiet
files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
- repo: https://github.com/codespell-project/codespell
rev: v1.16.0
rev: v1.17.1
hooks:
- id: codespell
args:
- --ignore-words-list=hass,alot,datas,dof,dur,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing
- --ignore-words-list=hass,alot,datas,dof,dur,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing,iam,incomfort
- --skip="./.*,*.csv,*.json"
- --quiet-level=2
exclude_types: [csv, json]
@ -27,7 +27,7 @@ repos:
- id: flake8
additional_dependencies:
- flake8-docstrings==1.5.0
- pydocstyle==5.0.2
- pydocstyle==5.1.1
files: ^(homeassistant|script|tests)/.+\.py$
- repo: https://github.com/PyCQA/bandit
rev: 1.6.2
@ -38,12 +38,12 @@ repos:
- --format=custom
- --configfile=tests/bandit.yaml
files: ^(homeassistant|script|tests)/.+\.py$
- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21
- repo: https://github.com/PyCQA/isort
rev: 5.5.1
hooks:
- id: isort
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
rev: v3.2.0
hooks:
- id: check-executables-have-shebangs
stages: [manual]
@ -54,7 +54,7 @@ repos:
- --branch=master
- --branch=rc
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.23.0
rev: v1.24.2
hooks:
- id: yamllint
- repo: https://github.com/prettier/prettier

View File

@ -2,6 +2,7 @@ dist: bionic
addons:
apt:
packages:
- ffmpeg
- libudev-dev
- libavformat-dev
- libavcodec-dev
@ -30,7 +31,8 @@ jobs:
- python: "3.7.1"
env: TOXENV=lint
- python: "3.7.1"
env: TOXENV=pylint PYLINT_ARGS=--jobs=0 TRAVIS_WAIT=30
# PYLINT_ARGS=--jobs=0 disabled for now: https://github.com/PyCQA/pylint/issues/3584
env: TOXENV=pylint TRAVIS_WAIT=30
- python: "3.7.1"
env: TOXENV=typing

View File

@ -102,11 +102,14 @@ homeassistant/components/digital_ocean/* @fabaff
homeassistant/components/directv/* @ctalkington
homeassistant/components/discogs/* @thibmaek
homeassistant/components/doorbird/* @oblogic7 @bdraco
homeassistant/components/dsmr/* @Robbie1221
homeassistant/components/dsmr_reader/* @depl0y
homeassistant/components/dunehd/* @bieniu
homeassistant/components/dwd_weather_warnings/* @runningman84 @stephan192 @Hummel95
homeassistant/components/dweet/* @fabaff
homeassistant/components/dynalite/* @ziv1234
homeassistant/components/dyson/* @etheralm
homeassistant/components/eafm/* @Jc2k
homeassistant/components/ecobee/* @marthoc
homeassistant/components/ecovacs/* @OverloadUT
homeassistant/components/edl21/* @mtdcr
@ -117,6 +120,7 @@ homeassistant/components/elkm1/* @gwww @bdraco
homeassistant/components/elv/* @majuss
homeassistant/components/emby/* @mezz64
homeassistant/components/emoncms/* @borpin
homeassistant/components/emulated_kasa/* @kbickar
homeassistant/components/enigma2/* @fbradyirl
homeassistant/components/enocean/* @bdurrer
homeassistant/components/entur_public_transport/* @hfurubotten
@ -134,6 +138,7 @@ homeassistant/components/filter/* @dgomes
homeassistant/components/firmata/* @DaAwesomeP
homeassistant/components/fixer/* @fabaff
homeassistant/components/flick_electric/* @ZephireNZ
homeassistant/components/flo/* @dmulcahey
homeassistant/components/flock/* @fabaff
homeassistant/components/flume/* @ChrisMandich @bdraco
homeassistant/components/flunearyou/* @bachya
@ -192,6 +197,7 @@ homeassistant/components/iammeter/* @lewei50
homeassistant/components/iaqualink/* @flz
homeassistant/components/icloud/* @Quentame
homeassistant/components/ign_sismologia/* @exxamalte
homeassistant/components/image/* @home-assistant/core
homeassistant/components/incomfort/* @zxdavb
homeassistant/components/influxdb/* @fabaff @mdegat01
homeassistant/components/input_boolean/* @home-assistant/core
@ -219,8 +225,8 @@ homeassistant/components/keba/* @dannerph
homeassistant/components/keenetic_ndms2/* @foxel
homeassistant/components/kef/* @basnijholt
homeassistant/components/keyboard_remote/* @bendavid
homeassistant/components/knx/* @Julius2342
homeassistant/components/kodi/* @armills
homeassistant/components/knx/* @Julius2342 @farmio @marvin-w
homeassistant/components/kodi/* @OnFreund
homeassistant/components/konnected/* @heythisisnate @kit-klein
homeassistant/components/lametric/* @robbiet480
homeassistant/components/launch_library/* @ludeeus
@ -230,6 +236,7 @@ homeassistant/components/linux_battery/* @fabaff
homeassistant/components/local_ip/* @issacg
homeassistant/components/logger/* @home-assistant/core
homeassistant/components/logi_circle/* @evanjd
homeassistant/components/loopenergy/* @pavoni
homeassistant/components/lovelace/* @home-assistant/frontend
homeassistant/components/luci/* @fbradyirl @mzdrale
homeassistant/components/luftdaten/* @fabaff
@ -239,14 +246,15 @@ homeassistant/components/lutron_caseta/* @swails
homeassistant/components/mastodon/* @fabaff
homeassistant/components/matrix/* @tinloaf
homeassistant/components/mcp23017/* @jardiamj
homeassistant/components/media_source/* @hunterjm
homeassistant/components/mediaroom/* @dgomes
homeassistant/components/melcloud/* @vilppuvuorinen
homeassistant/components/melissa/* @kennedyshead
homeassistant/components/met/* @danielhiversen
homeassistant/components/met/* @danielhiversen @thimic
homeassistant/components/meteo_france/* @hacf-fr @oncleben31 @Quentame
homeassistant/components/meteoalarm/* @rolfberkenbosch
homeassistant/components/metoffice/* @MrHarcombe
homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel
homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel @basnijholt
homeassistant/components/mikrotik/* @engrbm87
homeassistant/components/mill/* @danielhiversen
homeassistant/components/min_max/* @fabaff
@ -272,10 +280,12 @@ homeassistant/components/netdata/* @fabaff
homeassistant/components/nexia/* @ryannazaretian @bdraco
homeassistant/components/nextbus/* @vividboarder
homeassistant/components/nextcloud/* @meichthys
homeassistant/components/nightscout/* @marciogranzotto
homeassistant/components/nilu/* @hfurubotten
homeassistant/components/nissan_leaf/* @filcole
homeassistant/components/nmbs/* @thibmaek
homeassistant/components/no_ip/* @fabaff
homeassistant/components/noaa_tides/* @jdelaney72
homeassistant/components/notify/* @home-assistant/core
homeassistant/components/notify_events/* @matrozov @papajojo
homeassistant/components/notion/* @bachya
@ -297,7 +307,7 @@ homeassistant/components/openerz/* @misialq
homeassistant/components/opengarage/* @danielhiversen
homeassistant/components/opentherm_gw/* @mvn23
homeassistant/components/openuv/* @bachya
homeassistant/components/openweathermap/* @fabaff
homeassistant/components/openweathermap/* @fabaff @freekode
homeassistant/components/opnsense/* @mtreinish
homeassistant/components/orangepi_gpio/* @pascallj
homeassistant/components/oru/* @bvlaicu
@ -320,6 +330,7 @@ homeassistant/components/plum_lightpad/* @ColinHarrington @prystupa
homeassistant/components/point/* @fredrike
homeassistant/components/poolsense/* @haemishkyd
homeassistant/components/powerwall/* @bdraco @jrester
homeassistant/components/progettihwsw/* @ardaseremet
homeassistant/components/prometheus/* @knyar
homeassistant/components/proxmoxve/* @k4ds3 @jhollowe
homeassistant/components/ps4/* @ktnrg45
@ -341,9 +352,11 @@ homeassistant/components/random/* @fabaff
homeassistant/components/repetier/* @MTrab
homeassistant/components/rfxtrx/* @danielhiversen @elupus
homeassistant/components/ring/* @balloob
homeassistant/components/risco/* @OnFreund
homeassistant/components/rmvtransport/* @cgtobi
homeassistant/components/roku/* @ctalkington
homeassistant/components/roomba/* @pschmitt @cyr-ius @shenxn
homeassistant/components/roon/* @pavoni
homeassistant/components/safe_mode/* @home-assistant/core
homeassistant/components/saj/* @fredericvl
homeassistant/components/salt/* @bjornorri
@ -355,11 +368,13 @@ homeassistant/components/script/* @home-assistant/core
homeassistant/components/search/* @home-assistant/core
homeassistant/components/sense/* @kbickar
homeassistant/components/sensibo/* @andrey-git
homeassistant/components/sentry/* @dcramer
homeassistant/components/sentry/* @dcramer @frenck
homeassistant/components/serial/* @fabaff
homeassistant/components/seven_segments/* @fabaff
homeassistant/components/seventeentrack/* @bachya
homeassistant/components/sharkiq/* @ajmarks
homeassistant/components/shell_command/* @home-assistant/core
homeassistant/components/shelly/* @balloob @bieniu
homeassistant/components/shiftr/* @fabaff
homeassistant/components/shodan/* @fabaff
homeassistant/components/sighthound/* @robmarkcole
@ -371,6 +386,7 @@ homeassistant/components/sky_hub/* @rogerselwyn
homeassistant/components/slide/* @ualex73
homeassistant/components/sma/* @kellerza
homeassistant/components/smappee/* @bsmappee
homeassistant/components/smart_meter_texas/* @grahamwetzler
homeassistant/components/smarthab/* @outadoc
homeassistant/components/smartthings/* @andrewsayre
homeassistant/components/smarty/* @z0mbieprocess
@ -393,7 +409,7 @@ homeassistant/components/starline/* @anonym-tsk
homeassistant/components/statistics/* @fabaff
homeassistant/components/stiebel_eltron/* @fucm
homeassistant/components/stookalert/* @fwestenberg
homeassistant/components/stream/* @hunterjm
homeassistant/components/stream/* @hunterjm @uvjustin
homeassistant/components/stt/* @pvizeli
homeassistant/components/suez_water/* @ooii
homeassistant/components/sun/* @Swamp-Ig
@ -409,6 +425,7 @@ homeassistant/components/synology_dsm/* @ProtoThis @Quentame
homeassistant/components/synology_srm/* @aerialls
homeassistant/components/syslog/* @fabaff
homeassistant/components/tado/* @michaelarnauts @bdraco
homeassistant/components/tag/* @balloob @dmulcahey
homeassistant/components/tahoma/* @philklei
homeassistant/components/tankerkoenig/* @guillempages
homeassistant/components/tautulli/* @ludeeus
@ -429,6 +446,7 @@ homeassistant/components/tplink/* @rytilahti
homeassistant/components/traccar/* @ludeeus
homeassistant/components/tradfri/* @ggravlingen
homeassistant/components/trafikverket_train/* @endor-force
homeassistant/components/trafikverket_weatherstation/* @endor-force
homeassistant/components/transmission/* @engrbm87 @JPHutchins
homeassistant/components/tts/* @pvizeli
homeassistant/components/tuya/* @ollo69
@ -437,7 +455,7 @@ homeassistant/components/ubee/* @mzdrale
homeassistant/components/unifi/* @Kane610
homeassistant/components/unifiled/* @florisvdk
homeassistant/components/upb/* @gwww
homeassistant/components/upc_connect/* @pvizeli
homeassistant/components/upc_connect/* @pvizeli @fabaff
homeassistant/components/upcloud/* @scop
homeassistant/components/updater/* @home-assistant/core
homeassistant/components/upnp/* @StevenLooman
@ -448,13 +466,14 @@ homeassistant/components/velbus/* @Cereal2nd @brefra
homeassistant/components/velux/* @Julius2342
homeassistant/components/vera/* @vangorra
homeassistant/components/versasense/* @flamm3blemuff1n
homeassistant/components/version/* @fabaff
homeassistant/components/vesync/* @markperdue @webdjoe
homeassistant/components/version/* @fabaff @ludeeus
homeassistant/components/vesync/* @markperdue @webdjoe @thegardenmonkey
homeassistant/components/vicare/* @oischinger
homeassistant/components/vilfo/* @ManneW
homeassistant/components/vivotek/* @HarlemSquirrel
homeassistant/components/vizio/* @raman325
homeassistant/components/vlc_telnet/* @rodripf
homeassistant/components/volkszaehler/* @fabaff
homeassistant/components/volumio/* @OnFreund
homeassistant/components/waqi/* @andrey-git
homeassistant/components/watson_tts/* @rutkai
@ -462,6 +481,7 @@ homeassistant/components/weather/* @fabaff
homeassistant/components/webostv/* @bendavid
homeassistant/components/websocket_api/* @home-assistant/core
homeassistant/components/wiffi/* @mampfes
homeassistant/components/wilight/* @leofig-rj
homeassistant/components/withings/* @vangorra
homeassistant/components/wled/* @frenck
homeassistant/components/wolflink/* @adamkrol93
@ -475,11 +495,10 @@ homeassistant/components/xiaomi_tv/* @simse
homeassistant/components/xmpp/* @fabaff @flowolf
homeassistant/components/yamaha_musiccast/* @jalmeroth
homeassistant/components/yandex_transport/* @rishatik92 @devbis
homeassistant/components/yeelight/* @rytilahti @zewelor
homeassistant/components/yeelight/* @rytilahti @zewelor @shenxn
homeassistant/components/yeelightsunflower/* @lindsaymarkward
homeassistant/components/yessssms/* @flowolf
homeassistant/components/yi/* @bachya
homeassistant/components/yr/* @danielhiversen
homeassistant/components/zeroconf/* @Kane610
homeassistant/components/zerproc/* @emlove
homeassistant/components/zha/* @dmulcahey @adminiuga

View File

@ -11,7 +11,6 @@ COPY . homeassistant/
RUN \
pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links "${WHEELS_LINKS}" \
-r homeassistant/requirements_all.txt \
&& pip3 uninstall -y typing \
&& pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links "${WHEELS_LINKS}" \
-e ./homeassistant \
&& python3 -m compileall homeassistant/homeassistant

View File

@ -166,9 +166,6 @@ stages:
. venv/bin/activate
pip install -U pip setuptools pytest-azurepipelines pytest-xdist -c homeassistant/package_constraints.txt
pip install -r requirements_test_all.txt
# This is a TEMP. Eventually we should make sure our 4 dependencies drop typing.
# Find offending deps with `pipdeptree -r -p typing`
pip uninstall -y typing
- script: |
. venv/bin/activate
pip install -e .
@ -211,9 +208,6 @@ stages:
pip install -U pip setuptools wheel
pip install -r requirements_all.txt
pip install -r requirements_test.txt
# This is a TEMP. Eventually we should make sure our 4 dependencies drop typing.
# Find offending deps with `pipdeptree -r -p typing`
pip uninstall -y typing
- script: |
. venv/bin/activate
pip install -e .

View File

@ -47,8 +47,9 @@ jobs:
- template: templates/azp-job-wheels.yaml@azure
parameters:
builderVersion: '$(versionWheels)'
builderApk: 'build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev'
builderApk: 'build-base;cmake;git;linux-headers;libexecinfo-dev;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev'
builderPip: 'Cython;numpy;scikit-build'
builderEnvFile: true
skipBinary: 'aiohttp'
wheelsRequirement: 'requirements_wheels.txt'
wheelsRequirementDiff: 'requirements_diff.txt'
@ -90,4 +91,10 @@ jobs:
sed -i "s|# bme680|bme680|g" ${requirement_file}
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
done
# Write env for build settings
(
echo "GRPC_BUILD_WITH_BORING_SSL_ASM="
echo "GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1"
) > .env_file
displayName: 'Prepare requirements files for Home Assistant wheels'

View File

@ -1,11 +1,11 @@
{
"image": "homeassistant/{arch}-homeassistant",
"build_from": {
"aarch64": "homeassistant/aarch64-homeassistant-base:8.2.1",
"armhf": "homeassistant/armhf-homeassistant-base:8.2.1",
"armv7": "homeassistant/armv7-homeassistant-base:8.2.1",
"amd64": "homeassistant/amd64-homeassistant-base:8.2.1",
"i386": "homeassistant/i386-homeassistant-base:8.2.1"
"aarch64": "homeassistant/aarch64-homeassistant-base:8.4.0",
"armhf": "homeassistant/armhf-homeassistant-base:8.4.0",
"armv7": "homeassistant/armv7-homeassistant-base:8.4.0",
"amd64": "homeassistant/amd64-homeassistant-base:8.4.0",
"i386": "homeassistant/i386-homeassistant-base:8.4.0"
},
"labels": {
"io.hass.type": "core"

View File

@ -195,7 +195,7 @@ def closefds_osx(min_fd: int, max_fd: int) -> None:
get rid of.
"""
# pylint: disable=import-outside-toplevel
from fcntl import fcntl, F_GETFD, F_SETFD, FD_CLOEXEC
from fcntl import F_GETFD, F_SETFD, FD_CLOEXEC, fcntl
for _fd in range(min_fd, max_fd):
try:

View File

@ -312,9 +312,7 @@ class AuthManager:
if provider is not None and hasattr(provider, "async_will_remove_credentials"):
# https://github.com/python/mypy/issues/1424
await provider.async_will_remove_credentials( # type: ignore
credentials
)
await provider.async_will_remove_credentials(credentials) # type: ignore
await self._store.async_remove_credentials(credentials)

View File

@ -150,7 +150,9 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) -> types.Modul
module = importlib.import_module(module_path)
except ImportError as err:
_LOGGER.error("Unable to load mfa module %s: %s", module_name, err)
raise HomeAssistantError(f"Unable to load mfa module {module_name}: {err}")
raise HomeAssistantError(
f"Unable to load mfa module {module_name}: {err}"
) from err
if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module

View File

@ -48,7 +48,10 @@ class User:
)
_permissions: Optional[perm_mdl.PolicyPermissions] = attr.ib(
init=False, eq=False, order=False, default=None,
init=False,
eq=False,
order=False,
default=None,
)
@property

View File

@ -72,4 +72,4 @@ class _OwnerPermissions(AbstractPermissions):
return lambda entity_id, key: True
OwnerPermissions = _OwnerPermissions() # pylint: disable=invalid-name
OwnerPermissions = _OwnerPermissions()

View File

@ -5,8 +5,10 @@ import attr
if TYPE_CHECKING:
# pylint: disable=unused-import
from homeassistant.helpers import entity_registry as ent_reg # noqa: F401
from homeassistant.helpers import device_registry as dev_reg # noqa: F401
from homeassistant.helpers import ( # noqa: F401
device_registry as dev_reg,
entity_registry as ent_reg,
)
@attr.s(slots=True)

View File

@ -146,7 +146,9 @@ async def load_auth_provider_module(
module = importlib.import_module(f"homeassistant.auth.providers.{provider}")
except ImportError as err:
_LOGGER.error("Unable to load auth provider %s: %s", provider, err)
raise HomeAssistantError(f"Unable to load auth provider {provider}: {err}")
raise HomeAssistantError(
f"Unable to load auth provider {provider}: {err}"
) from err
if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module

View File

@ -71,7 +71,7 @@ class CommandLineAuthProvider(AuthProvider):
except OSError as err:
# happens when command doesn't exist or permission is denied
_LOGGER.error("Error while authenticating %r: %s", username, err)
raise InvalidAuthError
raise InvalidAuthError from err
if process.returncode != 0:
_LOGGER.error(

View File

@ -30,6 +30,16 @@ def _disallow_id(conf: Dict[str, Any]) -> Dict[str, Any]:
CONFIG_SCHEMA = vol.All(AUTH_PROVIDER_SCHEMA, _disallow_id)
@callback
def async_get_provider(hass: HomeAssistant) -> "HassAuthProvider":
"""Get the provider."""
for prv in hass.auth.auth_providers:
if prv.type == "homeassistant":
return cast(HassAuthProvider, prv)
raise RuntimeError("Provider not found")
class InvalidAuth(HomeAssistantError):
"""Raised when we encounter invalid authentication."""
@ -235,6 +245,35 @@ class HassAuthProvider(AuthProvider):
self.data.validate_login, username, password
)
async def async_add_auth(self, username: str, password: str) -> None:
"""Call add_auth on data."""
if self.data is None:
await self.async_initialize()
assert self.data is not None
await self.hass.async_add_executor_job(self.data.add_auth, username, password)
await self.data.async_save()
async def async_remove_auth(self, username: str) -> None:
"""Call remove_auth on data."""
if self.data is None:
await self.async_initialize()
assert self.data is not None
self.data.async_remove_auth(username)
await self.data.async_save()
async def async_change_password(self, username: str, new_password: str) -> None:
"""Call change_password on data."""
if self.data is None:
await self.async_initialize()
assert self.data is not None
await self.hass.async_add_executor_job(
self.data.change_password, username, new_password
)
await self.data.async_save()
async def async_get_or_create_credentials(
self, flow_result: Dict[str, str]
) -> Credentials:

View File

@ -112,7 +112,8 @@ async def async_setup_hass(
config_dict = await conf_util.async_hass_config_yaml(hass)
except HomeAssistantError as err:
_LOGGER.error(
"Failed to parse configuration.yaml: %s. Activating safe mode", err,
"Failed to parse configuration.yaml: %s. Activating safe mode",
err,
)
else:
if not is_virtual_env():
@ -160,7 +161,8 @@ async def async_setup_hass(
http_conf = (await http.async_get_last_config(hass)) or {}
await async_from_config_dict(
{"safe_mode": {}, "http": http_conf}, hass,
{"safe_mode": {}, "http": http_conf},
hass,
)
if runtime_config.open_ui:
@ -331,8 +333,10 @@ def async_enable_logging(
):
if log_rotate_days:
err_handler: logging.FileHandler = logging.handlers.TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days
err_handler: logging.FileHandler = (
logging.handlers.TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days
)
)
else:
err_handler = logging.FileHandler(err_log_path, mode="w", delay=True)
@ -391,7 +395,8 @@ async def _async_log_pending_setups(
if remaining:
_LOGGER.warning(
"Waiting on integrations to complete setup: %s", ", ".join(remaining),
"Waiting on integrations to complete setup: %s",
", ".join(remaining),
)

View File

@ -120,7 +120,7 @@ async def async_setup_entry(hass, config_entry):
except (AbodeException, ConnectTimeout, HTTPError) as ex:
LOGGER.error("Unable to connect to Abode: %s", str(ex))
raise ConfigEntryNotReady
raise ConfigEntryNotReady from ex
for platform in ABODE_PLATFORMS:
hass.async_create_task(

View File

@ -127,6 +127,6 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator):
InvalidApiKeyError,
RequestsExceededError,
) as error:
raise UpdateFailed(error)
raise UpdateFailed(error) from error
_LOGGER.debug("Requests remaining: %s", self.accuweather.requests_remaining)
return {**current, **{ATTR_FORECAST: forecast}}

View File

@ -34,7 +34,7 @@ class AccuWeatherFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if user_input is not None:
websession = async_get_clientsession(self.hass)
try:
with timeout(10):
async with timeout(10):
accuweather = AccuWeather(
user_input[CONF_API_KEY],
websession,

View File

@ -5,12 +5,12 @@ from homeassistant.const import (
LENGTH_FEET,
LENGTH_INCHES,
LENGTH_METERS,
PERCENTAGE,
SPEED_KILOMETERS_PER_HOUR,
SPEED_MILES_PER_HOUR,
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
TIME_HOURS,
UNIT_PERCENTAGE,
UV_INDEX,
VOLUME_CUBIC_METERS,
)
@ -53,15 +53,15 @@ FORECAST_SENSOR_TYPES = {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-cloudy",
ATTR_LABEL: "Cloud Cover Day",
ATTR_UNIT_METRIC: UNIT_PERCENTAGE,
ATTR_UNIT_IMPERIAL: UNIT_PERCENTAGE,
ATTR_UNIT_METRIC: PERCENTAGE,
ATTR_UNIT_IMPERIAL: PERCENTAGE,
},
"CloudCoverNight": {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-cloudy",
ATTR_LABEL: "Cloud Cover Night",
ATTR_UNIT_METRIC: UNIT_PERCENTAGE,
ATTR_UNIT_IMPERIAL: UNIT_PERCENTAGE,
ATTR_UNIT_METRIC: PERCENTAGE,
ATTR_UNIT_IMPERIAL: PERCENTAGE,
},
"Grass": {
ATTR_DEVICE_CLASS: None,
@ -130,15 +130,15 @@ FORECAST_SENSOR_TYPES = {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-lightning",
ATTR_LABEL: "Thunderstorm Probability Day",
ATTR_UNIT_METRIC: UNIT_PERCENTAGE,
ATTR_UNIT_IMPERIAL: UNIT_PERCENTAGE,
ATTR_UNIT_METRIC: PERCENTAGE,
ATTR_UNIT_IMPERIAL: PERCENTAGE,
},
"ThunderstormProbabilityNight": {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-lightning",
ATTR_LABEL: "Thunderstorm Probability Night",
ATTR_UNIT_METRIC: UNIT_PERCENTAGE,
ATTR_UNIT_IMPERIAL: UNIT_PERCENTAGE,
ATTR_UNIT_METRIC: PERCENTAGE,
ATTR_UNIT_IMPERIAL: PERCENTAGE,
},
"Tree": {
ATTR_DEVICE_CLASS: None,
@ -210,8 +210,8 @@ SENSOR_TYPES = {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-cloudy",
ATTR_LABEL: "Cloud Cover",
ATTR_UNIT_METRIC: UNIT_PERCENTAGE,
ATTR_UNIT_IMPERIAL: UNIT_PERCENTAGE,
ATTR_UNIT_METRIC: PERCENTAGE,
ATTR_UNIT_IMPERIAL: PERCENTAGE,
},
"DewPoint": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,

View File

@ -2,7 +2,8 @@
"domain": "accuweather",
"name": "AccuWeather",
"documentation": "https://www.home-assistant.io/integrations/accuweather/",
"requirements": ["accuweather==0.0.9"],
"requirements": ["accuweather==0.0.10"],
"codeowners": ["@bieniu"],
"config_flow": true
"config_flow": true,
"quality_scale": "platinum"
}

View File

@ -5,7 +5,7 @@ from homeassistant.const import (
CONF_NAME,
DEVICE_CLASS_TEMPERATURE,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
ATTR_FORECAST,
@ -48,14 +48,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(sensors, False)
class AccuWeatherSensor(Entity):
class AccuWeatherSensor(CoordinatorEntity):
"""Define an AccuWeather entity."""
def __init__(self, name, kind, coordinator, forecast_day=None):
"""Initialize."""
super().__init__(coordinator)
self._name = name
self.kind = kind
self.coordinator = coordinator
self._device_class = None
self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION}
self._unit_system = "Metric" if self.coordinator.is_metric else "Imperial"
@ -85,16 +85,6 @@ class AccuWeatherSensor(Entity):
"entry_type": "service",
}
@property
def should_poll(self):
"""Return the polling requirement of the entity."""
return False
@property
def available(self):
"""Return True if entity is available."""
return self.coordinator.last_update_success
@property
def state(self):
"""Return the state."""
@ -154,11 +144,7 @@ class AccuWeatherSensor(Entity):
def device_state_attributes(self):
"""Return the state attributes."""
if self.forecast_day is not None:
if self.kind == "WindGustDay":
self._attrs["direction"] = self.coordinator.data[ATTR_FORECAST][
self.forecast_day
][self.kind]["Direction"]["English"]
elif self.kind == "WindGustNight":
if self.kind in ["WindGustDay", "WindGustNight"]:
self._attrs["direction"] = self.coordinator.data[ATTR_FORECAST][
self.forecast_day
][self.kind]["Direction"]["English"]
@ -177,13 +163,3 @@ class AccuWeatherSensor(Entity):
def entity_registry_enabled_default(self):
"""Return if the entity should be enabled when first added to the entity registry."""
return bool(self.kind not in OPTIONAL_SENSORS)
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Update AccuWeather entity."""
await self.coordinator.async_request_refresh()

View File

@ -16,7 +16,7 @@
"longitude": "Longitud",
"name": "Nom de la integraci\u00f3"
},
"description": "Si necessites ajuda amb la configuraci\u00f3, consulta: https://www.home-assistant.io/integrations/accuweather/ \n\n La previsi\u00f3 meteorol\u00f2gica no est\u00e0 habilitada de manera predeterminada. Pots activar-la en les opcions de la integraci\u00f3.",
"description": "Si necessites ajuda amb la configuraci\u00f3, consulta els seg\u00fcent enlla\u00e7: https://www.home-assistant.io/integrations/accuweather/ \n\n Alguns sensors no estan activats de manera predeterminada. Els pots activar des del registre d'entitats, despr\u00e9s de la configurraci\u00f3 de la integraci\u00f3.\n La previsi\u00f3 meteorol\u00f2gica no est\u00e0 activada de manera predeterminada. Pots activar-la en les opcions de la integraci\u00f3.",
"title": "AccuWeather"
}
}

View File

@ -0,0 +1,12 @@
{
"config": {
"step": {
"user": {
"data": {
"latitude": "Zem\u011bpisn\u00e1 \u0161\u00ed\u0159ka",
"longitude": "Zem\u011bpisn\u00e1 d\u00e9lka"
}
}
}
}
}

View File

@ -0,0 +1,12 @@
{
"config": {
"abort": {
"single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible."
},
"step": {
"user": {
"description": "Si vous avez besoin d'aide pour la configuration, consultez le site suivant : https://www.home-assistant.io/integrations/accuweather/\n\nCertains capteurs ne sont pas activ\u00e9s par d\u00e9faut. Vous pouvez les activer dans le registre des entit\u00e9s apr\u00e8s la configuration de l'int\u00e9gration.\nLes pr\u00e9visions m\u00e9t\u00e9orologiques ne sont pas activ\u00e9es par d\u00e9faut. Vous pouvez l'activer dans les options d'int\u00e9gration."
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"config": {
"step": {
"user": {
"description": "\uad6c\uc131\uc5d0 \ub300\ud55c \ub3c4\uc6c0\uc774 \ud544\uc694\ud55c \uacbd\uc6b0 \ub2e4\uc74c\uc744 \ucc38\uc870\ud574\uc8fc\uc138\uc694:\nhttps://www.home-assistant.io/integrations/accuweather/\n\n\uc77c\ubd80 \uc13c\uc11c\ub294 \uae30\ubcf8\uc801\uc73c\ub85c \ud65c\uc131\ud654\ub418\uc5b4 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \uc5f0\ub3d9 \uad6c\uc131 \ud6c4 \uad6c\uc131\uc694\uc18c \ub808\uc9c0\uc2a4\ud2b8\ub9ac\uc5d0\uc11c \ud65c\uc131\ud654\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\n\uc77c\uae30\uc608\ubcf4\ub294 \uae30\ubcf8\uc801\uc73c\ub85c \ud65c\uc131\ud654\ub418\uc5b4 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \uc5f0\ub3d9 \uc635\uc158\uc5d0\uc11c \ud65c\uc131\ud654\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4."
}
}
}
}

View File

@ -16,8 +16,7 @@
"longitude": "Lengdegrad",
"name": "Navn p\u00e5 integrasjon"
},
"description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://www.home-assistant.io/integrations/accuweather/ \n\n Noen sensorer er ikke aktivert som standard. Du kan aktivere dem i enhetsregisteret etter integrasjonskonfigurasjonen. \n V\u00e6rmelding er ikke aktivert som standard. Du kan aktivere det i integrasjonsalternativene.",
"title": ""
"description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://www.home-assistant.io/integrations/accuweather/ \n\n Noen sensorer er ikke aktivert som standard. Du kan aktivere dem i enhetsregisteret etter integrasjonskonfigurasjonen. \n V\u00e6rmelding er ikke aktivert som standard. Du kan aktivere det i integrasjonsalternativene."
}
}
},

View File

@ -6,7 +6,7 @@
"error": {
"cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia.",
"invalid_api_key": "Nieprawid\u0142owy klucz API.",
"requests_exceeded": "Dozwolona liczba zapyta\u0144 do interfejsu API Accuweather zosta\u0142a przekroczona. Musisz poczeka\u0107 lub zmieni\u0107 klucz API."
"requests_exceeded": "Dozwolona liczba zapyta\u0144 do interfejsu API AccuWeather zosta\u0142a przekroczona. Musisz poczeka\u0107 lub zmieni\u0107 klucz API."
},
"step": {
"user": {

View File

@ -0,0 +1,24 @@
{
"config": {
"step": {
"user": {
"data": {
"api_key": "Chave API",
"latitude": "Latitude",
"longitude": "Longitude"
},
"title": "AccuWeather"
}
}
},
"options": {
"step": {
"user": {
"data": {
"forecast": "Previs\u00e3o do Tempo"
},
"description": "Devido \u00e0s limita\u00e7\u00f5es da vers\u00e3o gratuita da chave da API AccuWeather, quando voc\u00ea habilita a previs\u00e3o do tempo, as atualiza\u00e7\u00f5es de dados ser\u00e3o realizadas a cada 64 minutos em vez de a cada 32 minutos."
}
}
}
}

View File

@ -1,8 +1,16 @@
{
"config": {
"abort": {
"single_instance_allowed": "J\u00e1 configurado. Apenas uma \u00fanica configura\u00e7\u00e3o \u00e9 poss\u00edvel."
},
"error": {
"cannot_connect": "Falha na liga\u00e7\u00e3o",
"invalid_api_key": "Chave de API inv\u00e1lida"
},
"step": {
"user": {
"data": {
"api_key": "Chave de API",
"latitude": "Latitude",
"longitude": "Longitude"
}

View File

@ -4,7 +4,7 @@
"single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e."
},
"error": {
"cannot_connect": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.",
"cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.",
"invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.",
"requests_exceeded": "\u041f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a API Accuweather. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043e\u0436\u0434\u0430\u0442\u044c \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043b\u044e\u0447 API."
},

View File

@ -0,0 +1,9 @@
{
"state": {
"accuweather__pressure_tendency": {
"falling": "Disminuint",
"rising": "Augmentant",
"steady": "Estable"
}
}
}

View File

@ -0,0 +1,9 @@
{
"state": {
"accuweather__pressure_tendency": {
"falling": "R\u00e9ckleefeg",
"rising": "Erh\u00e9ijung",
"steady": "Stabil"
}
}
}

View File

@ -0,0 +1,9 @@
{
"state": {
"accuweather__pressure_tendency": {
"falling": "\u4e0b\u964d",
"rising": "\u4e0a\u5347",
"steady": "\u7a69\u5b9a"
}
}
}

View File

@ -16,7 +16,7 @@
"longitude": "\u7d93\u5ea6",
"name": "\u6574\u5408\u540d\u7a31"
},
"description": "\u5047\u5982\u4f60\u9700\u8981\u5354\u52a9\u9032\u884c\u8a2d\u5b9a\uff0c\u8acb\u53c3\u95b1\uff1ahttps://www.home-assistant.io/integrations/accuweather/\n\n\u5929\u6c23\u9810\u5831\u9810\u8a2d\u672a\u958b\u555f\u3002\u53ef\u4ee5\u65bc\u6574\u5408\u9078\u9805\u4e2d\u958b\u555f\u3002",
"description": "\u5047\u5982\u4f60\u9700\u8981\u5354\u52a9\u9032\u884c\u8a2d\u5b9a\uff0c\u8acb\u53c3\u95b1\uff1ahttps://www.home-assistant.io/integrations/accuweather/\n\n\u67d0\u4e9b\u50b3\u611f\u5668\u9810\u8a2d\u70ba\u672a\u555f\u7528\uff0c\u53ef\u4ee5\u65bc\u6574\u5408\u8a2d\u5b9a\u4e2d\u555f\u7528\u9019\u4e9b\u5be6\u9ad4\u3002\u5929\u6c23\u9810\u5831\u9810\u8a2d\u672a\u958b\u555f\u3002\u53ef\u4ee5\u65bc\u6574\u5408\u9078\u9805\u4e2d\u958b\u555f\u3002",
"title": "AccuWeather"
}
}

View File

@ -13,6 +13,7 @@ from homeassistant.components.weather import (
WeatherEntity,
)
from homeassistant.const import CONF_NAME, TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import utc_from_timestamp
from .const import (
@ -37,13 +38,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities([AccuWeatherEntity(name, coordinator)], False)
class AccuWeatherEntity(WeatherEntity):
class AccuWeatherEntity(CoordinatorEntity, WeatherEntity):
"""Define an AccuWeather entity."""
def __init__(self, name, coordinator):
"""Initialize."""
super().__init__(coordinator)
self._name = name
self.coordinator = coordinator
self._attrs = {}
self._unit_system = "Metric" if self.coordinator.is_metric else "Imperial"
@ -72,16 +73,6 @@ class AccuWeatherEntity(WeatherEntity):
"entry_type": "service",
}
@property
def should_poll(self):
"""Return the polling requirement of the entity."""
return False
@property
def available(self):
"""Return True if entity is available."""
return self.coordinator.last_update_success
@property
def condition(self):
"""Return the current condition."""
@ -169,16 +160,6 @@ class AccuWeatherEntity(WeatherEntity):
]
return forecast
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Update AccuWeather entity."""
await self.coordinator.async_request_refresh()
@staticmethod
def _calc_precipitation(day: dict) -> float:
"""Return sum of the precipitation."""

View File

@ -26,10 +26,8 @@ class AcmedaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if (
user_input is not None
and self.discovered_hubs is not None
# pylint: disable=unsupported-membership-test
and user_input["id"] in self.discovered_hubs
):
# pylint: disable=unsubscriptable-object
return await self.async_create(self.discovered_hubs[user_input["id"]])
# Already configured hosts

View File

@ -37,5 +37,6 @@ async def update_devices(hass, config_entry, api):
)
if device is not None:
dev_registry.async_update_device(
device.id, name=api_item.name,
device.id,
name=api_item.name,
)

View File

@ -1,5 +1,5 @@
"""Support for Acmeda Roller Blind Batteries."""
from homeassistant.const import DEVICE_CLASS_BATTERY, UNIT_PERCENTAGE
from homeassistant.const import DEVICE_CLASS_BATTERY, PERCENTAGE
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -33,7 +33,7 @@ class AcmedaBattery(AcmedaBase):
"""Representation of a Acmeda cover device."""
device_class = DEVICE_CLASS_BATTERY
unit_of_measurement = UNIT_PERCENTAGE
unit_of_measurement = PERCENTAGE
@property
def name(self):

View File

@ -11,6 +11,5 @@
"title": "Velg en hub du vil legge til"
}
}
},
"title": ""
}
}

View File

@ -11,7 +11,7 @@ from homeassistant.components.adguard.const import (
DOMAIN,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TIME_MILLISECONDS, UNIT_PERCENTAGE
from homeassistant.const import PERCENTAGE, TIME_MILLISECONDS
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers.typing import HomeAssistantType
@ -134,7 +134,7 @@ class AdGuardHomePercentageBlockedSensor(AdGuardHomeSensor):
"AdGuard DNS Queries Blocked Ratio",
"mdi:magnify-close",
"blocked_percentage",
UNIT_PERCENTAGE,
PERCENTAGE,
)
async def _adguard_update(self) -> None:

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "\u0422\u0430\u0437\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0438\u0437\u0438\u0441\u043a\u0432\u0430 AdGuard Home {minimal_version} \u0438\u043b\u0438 \u043f\u043e-\u043d\u043e\u0432\u0430 {minimal_version}, \u0438\u043c\u0430\u0442\u0435 {current_version}. \u041c\u043e\u043b\u044f, \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u0439\u0442\u0435 \u0432\u0430\u0448\u0430\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u043a\u0430 \u0437\u0430 Hass.io AdGuard Home.",
"adguard_home_outdated": "\u0422\u0430\u0437\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0438\u0437\u0438\u0441\u043a\u0432\u0430 AdGuard Home {minimal_version} \u0438\u043b\u0438 \u043f\u043e-\u043d\u043e\u0432\u0430 {minimal_version}, \u0438\u043c\u0430\u0442\u0435 {current_version}.",
"existing_instance_updated": "\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430\u0449\u0430\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f.",
"single_instance_allowed": "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430 AdGuard Home."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Aquesta integraci\u00f3 necessita la versi\u00f3 d'AdGuard Home {minimal_version} o una superior, tens la {current_version}. Actualitza el complement de Hass.io d'AdGuard Home.",
"adguard_home_outdated": "Aquesta integraci\u00f3 necessita la versi\u00f3 d'AdGuard Home {minimal_version} o una superior, tens la {current_version}.",
"existing_instance_updated": "S'ha actualitzat la configuraci\u00f3 existent.",
"single_instance_allowed": "Nom\u00e9s es permet una \u00fanica configuraci\u00f3 d'AdGuard Home."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Denne integration kr\u00e6ver AdGuard Home {minimal_version} eller h\u00f8jere, du har {current_version}. Opdater venligst din Hass.io AdGuard Home-tilf\u00f8jelse.",
"adguard_home_outdated": "Denne integration kr\u00e6ver AdGuard Home {minimal_version} eller h\u00f8jere, du har {current_version}.",
"existing_instance_updated": "Opdaterede eksisterende konfiguration.",
"single_instance_allowed": "Kun en enkelt konfiguration af AdGuard Home er tilladt."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Diese Integration erfordert AdGuard Home {minimal_version} oder h\u00f6her, du hast {current_version}. Bitte aktualisiere dein Hass.io AdGuard Home Add-on.",
"adguard_home_outdated": "Diese Integration erfordert AdGuard Home {minimal_version} oder h\u00f6her, du hast {current_version}.",
"existing_instance_updated": "Bestehende Konfiguration wurde aktualisiert.",
"single_instance_allowed": "Es ist nur eine einzige Konfiguration von AdGuard Home zul\u00e4ssig."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "This integration requires AdGuard Home {minimal_version} or higher, you have {current_version}. Please update your Hass.io AdGuard Home add-on.",
"adguard_home_outdated": "This integration requires AdGuard Home {minimal_version} or higher, you have {current_version}.",
"existing_instance_updated": "Updated existing configuration.",
"single_instance_allowed": "Only a single configuration of AdGuard Home is allowed."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Esta integraci\u00f3n requiere AdGuard Home {minimal_version} o superior, tiene {current_version}. Actualice su complemento Hass.io AdGuard Home.",
"adguard_home_outdated": "Esta integraci\u00f3n requiere AdGuard Home {minimal_version} o superior, tiene {current_version}.",
"existing_instance_updated": "Se actualiz\u00f3 la configuraci\u00f3n existente.",
"single_instance_allowed": "Solo se permite una \u00fanica configuraci\u00f3n de AdGuard Home."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Esta integraci\u00f3n requiere AdGuard Home {minimal_version} o superior, usted tiene {current_version}. Por favor, actualice su complemento Hass.io AdGuard Home.",
"adguard_home_outdated": "Esta integraci\u00f3n requiere AdGuard Home {minimal_version} o superior, usted tiene {current_version}.",
"existing_instance_updated": "Se ha actualizado la configuraci\u00f3n existente.",
"single_instance_allowed": "S\u00f3lo se permite una \u00fanica configuraci\u00f3n de AdGuard Home."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Cette int\u00e9gration n\u00e9cessite AdGuard Home {minimal_version} ou une version ult\u00e9rieure, vous disposez de {current_version}. Veuillez mettre \u00e0 jour votre compl\u00e9ment Hass.io AdGuard Home.",
"adguard_home_outdated": "Cette int\u00e9gration n\u00e9cessite AdGuard Home {minimal_version} ou une version ult\u00e9rieure, vous disposez de {current_version}.",
"existing_instance_updated": "La configuration existante a \u00e9t\u00e9 mise \u00e0 jour.",
"single_instance_allowed": "Une seule configuration d'AdGuard Home est autoris\u00e9e."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Questa integrazione richiede AdGuard Home {minimal_version} o versione successiva, si dispone di {current_version}. Aggiorna il componente aggiuntivo AdGuard Home di Hass.io.",
"adguard_home_outdated": "Questa integrazione richiede AdGuard Home {minimal_version} o versione successiva, si dispone di {current_version}.",
"existing_instance_updated": "Configurazione esistente aggiornata.",
"single_instance_allowed": "\u00c8 consentita solo una singola configurazione di AdGuard Home."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "\uc774 \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\ub294 AdGuard Home {minimal_version} \uc774\uc0c1\uc774 \ud544\uc694\ud569\ub2c8\ub2e4. \ud604\uc7ac \ubc84\uc804\uc740 {current_version} \uc785\ub2c8\ub2e4. Hass.io AdGuard Home \uc560\ub4dc\uc628\uc744 \uc5c5\ub370\uc774\ud2b8 \ud574\uc8fc\uc138\uc694.",
"adguard_home_outdated": "\uc774 \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\ub294 AdGuard Home {minimal_version} \uc774\uc0c1\uc774 \ud544\uc694\ud569\ub2c8\ub2e4. \ud604\uc7ac \ubc84\uc804\uc740 {current_version} \uc785\ub2c8\ub2e4.",
"existing_instance_updated": "\uae30\uc874 \uad6c\uc131\uc744 \uc5c5\ub370\uc774\ud2b8\ud588\uc2b5\ub2c8\ub2e4.",
"single_instance_allowed": "\ud558\ub098\uc758 AdGuard Home \ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "D\u00ebs Integratioun ben\u00e9idegt AdgGuard Home {minimal_version} oder m\u00e9i, dir hutt {current_version}. Aktualis\u00e9iert w.e.g. \u00e4ren Hass.io AdGuard Home Add-on.",
"adguard_home_outdated": "D\u00ebs Integratioun ben\u00e9idegt AdgGuard Home {minimal_version} oder m\u00e9i, dir hutt {current_version}.",
"existing_instance_updated": "D\u00e9i bestehend Konfiguratioun ass ge\u00e4nnert.",
"single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun AdGuard Home ass erlaabt."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Deze integratie vereist AdGuard Home {minimal_version} of hoger, u heeft {current_version}. Update uw Hass.io AdGuard Home-add-on.",
"adguard_home_outdated": "Deze integratie vereist AdGuard Home {minimal_version} of hoger, u heeft {current_version}.",
"existing_instance_updated": "Bestaande configuratie bijgewerkt.",
"single_instance_allowed": "Slechts \u00e9\u00e9n configuratie van AdGuard Home is toegestaan."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Denne integrasjonen krever AdGuard Home {minimal_version} eller h\u00f8yere, du har {current_version}. Vennligst oppdater Hass.io AdGuard Home-tillegget.",
"adguard_home_outdated": "Denne integrasjonen krever AdGuard Home {minimal_version} eller h\u00f8yere, du har {current_version}.",
"existing_instance_updated": "Oppdatert eksisterende konfigurasjon.",
"single_instance_allowed": "Kun en konfigurasjon av AdGuard Hjemer tillatt."
},
@ -18,7 +16,6 @@
"data": {
"host": "Vert",
"password": "Passord",
"port": "",
"ssl": "AdGuard Hjem bruker et SSL-sertifikat",
"username": "Brukernavn",
"verify_ssl": "AdGuard Home bruker et riktig sertifikat"

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Ta integracja wymaga AdGuard Home {minimal_version} lub nowszej wersji, masz {current_version}. Zaktualizuj sw\u00f3j dodatek Hass.io AdGuard Home.",
"adguard_home_outdated": "Ta integracja wymaga AdGuard Home {minimal_version} lub nowszej wersji, masz {current_version}.",
"existing_instance_updated": "Zaktualizowano istniej\u0105c\u0105 konfiguracj\u0119.",
"single_instance_allowed": "Dozwolona jest tylko jedna konfiguracja AdGuard Home."
},

View File

@ -16,7 +16,7 @@
"data": {
"password": "Senha",
"ssl": "O AdGuard Home usa um certificado SSL",
"username": "Nome de usu\u00e1rio",
"username": "Usu\u00e1rio",
"verify_ssl": "O AdGuard Home usa um certificado apropriado"
},
"description": "Configure sua inst\u00e2ncia do AdGuard Home para permitir o monitoramento e o controle."

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "\u042d\u0442\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 AdGuard Home \u0432\u0435\u0440\u0441\u0438\u0438 {current_version}. \u0414\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f {minimal_version}, \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043d\u043e\u0432\u0430\u044f. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 Hass.io.",
"adguard_home_outdated": "\u042d\u0442\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 AdGuard Home \u0432\u0435\u0440\u0441\u0438\u0438 {current_version}. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0432\u0435\u0440\u0441\u0438\u044e {minimal_version} \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043d\u043e\u0432\u0443\u044e.",
"existing_instance_updated": "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0430.",
"single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Za to integracijo je potrebna AdGuard Home {minimal_version} ali vi\u0161ja, vi imate {current_version}. Prosimo posodobite va\u0161 hass.io AdGuard Home dodatek.",
"adguard_home_outdated": "Za to integracijo je potrebna AdGuard Home {minimal_version} ali vi\u0161ja, vi imate {current_version}.",
"existing_instance_updated": "Posodobljena obstoje\u010da konfiguracija.",
"single_instance_allowed": "Dovoljena je samo ena konfiguracija AdGuard Home."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "Den h\u00e4r integrationen kr\u00e4ver AdGuard Home {minimal_version} eller senare, du har {current_version}. Uppdatera ditt Hass.io AdGuard Home-till\u00e4gg.",
"adguard_home_outdated": "Den h\u00e4r integrationen kr\u00e4ver AdGuard Home {minimal_version} eller senare, du har {current_version}.",
"existing_instance_updated": "Uppdaterade existerande konfiguration.",
"single_instance_allowed": "Endast en enda konfiguration av AdGuard Home \u00e4r till\u00e5ten."
},

View File

@ -1,8 +1,6 @@
{
"config": {
"abort": {
"adguard_home_addon_outdated": "\u6574\u5408\u9700\u8981 AdGuard Home {minimal_version} \u6216\u66f4\u65b0\u7248\u672c\uff0c\u60a8\u76ee\u524d\u4f7f\u7528\u7248\u672c\u70ba {current_version}\u3002\u8acb\u66f4\u65b0 Hass.io AdGuard Home \u5143\u4ef6\u3002",
"adguard_home_outdated": "\u6574\u5408\u9700\u8981 AdGuard Home {minimal_version} \u6216\u66f4\u65b0\u7248\u672c\uff0c\u60a8\u76ee\u524d\u4f7f\u7528\u7248\u672c\u70ba {current_version}\u3002",
"existing_instance_updated": "\u5df2\u66f4\u65b0\u73fe\u6709\u8a2d\u5b9a\u3002",
"single_instance_allowed": "\u50c5\u5141\u8a31\u8a2d\u5b9a\u4e00\u7d44 AdGuard Home\u3002"
},

View File

@ -2,6 +2,6 @@
"domain": "ads",
"name": "ADS",
"documentation": "https://www.home-assistant.io/integrations/ads",
"requirements": ["pyads==3.2.1"],
"requirements": ["pyads==3.2.2"],
"codeowners": []
}

View File

@ -16,7 +16,7 @@ DEFAULT_BRAND = "Agent DVR by ispyconnect.com"
_LOGGER = logging.getLogger(__name__)
FORWARDS = ["camera"]
FORWARDS = ["alarm_control_panel", "camera"]
async def async_setup(hass, config):
@ -33,9 +33,9 @@ async def async_setup_entry(hass, config_entry):
agent_client = Agent(server_origin, async_get_clientsession(hass))
try:
await agent_client.update()
except AgentError:
except AgentError as err:
await agent_client.close()
raise ConfigEntryNotReady
raise ConfigEntryNotReady from err
if not agent_client.is_available:
raise ConfigEntryNotReady

View File

@ -0,0 +1,124 @@
"""Support for Agent DVR Alarm Control Panels."""
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntity
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
SUPPORT_ALARM_ARM_HOME,
SUPPORT_ALARM_ARM_NIGHT,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
)
from .const import CONNECTION, DOMAIN as AGENT_DOMAIN
ICON = "mdi:security"
CONF_HOME_MODE_NAME = "home"
CONF_AWAY_MODE_NAME = "away"
CONF_NIGHT_MODE_NAME = "night"
CONST_ALARM_CONTROL_PANEL_NAME = "Alarm Panel"
async def async_setup_entry(
hass, config_entry, async_add_entities, discovery_info=None
):
"""Set up the Agent DVR Alarm Control Panels."""
async_add_entities(
[AgentBaseStation(hass.data[AGENT_DOMAIN][config_entry.entry_id][CONNECTION])]
)
class AgentBaseStation(AlarmControlPanelEntity):
"""Representation of an Agent DVR Alarm Control Panel."""
def __init__(self, client):
"""Initialize the alarm control panel."""
self._state = None
self._client = client
self._unique_id = f"{client.unique}_CP"
name = CONST_ALARM_CONTROL_PANEL_NAME
self._name = name = f"{client.name} {name}"
@property
def icon(self):
"""Return icon."""
return ICON
@property
def state(self):
"""Return the state of the device."""
return self._state
@property
def supported_features(self) -> int:
"""Return the list of supported features."""
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT
@property
def device_info(self):
"""Return the device info for adding the entity to the agent object."""
return {
"identifiers": {(AGENT_DOMAIN, self._client.unique)},
"manufacturer": "Agent",
"model": CONST_ALARM_CONTROL_PANEL_NAME,
"sw_version": self._client.version,
}
async def async_update(self):
"""Update the state of the device."""
await self._client.update()
armed = self._client.is_armed
if armed is None:
self._state = None
return
if armed:
prof = (await self._client.get_active_profile()).lower()
self._state = STATE_ALARM_ARMED_AWAY
if prof == CONF_HOME_MODE_NAME:
self._state = STATE_ALARM_ARMED_HOME
elif prof == CONF_NIGHT_MODE_NAME:
self._state = STATE_ALARM_ARMED_NIGHT
else:
self._state = STATE_ALARM_DISARMED
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
await self._client.disarm()
self._state = STATE_ALARM_DISARMED
async def async_alarm_arm_away(self, code=None):
"""Send arm away command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_AWAY_MODE_NAME)
self._state = STATE_ALARM_ARMED_AWAY
async def async_alarm_arm_home(self, code=None):
"""Send arm home command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_HOME_MODE_NAME)
self._state = STATE_ALARM_ARMED_HOME
async def async_alarm_arm_night(self, code=None):
"""Send arm night command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_NIGHT_MODE_NAME)
self._state = STATE_ALARM_ARMED_NIGHT
@property
def name(self):
"""Return the name of the base station."""
return self._name
@property
def available(self) -> bool:
"""Device available."""
return self._client.is_available
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return self._unique_id

View File

@ -10,8 +10,7 @@
"step": {
"user": {
"data": {
"host": "Vert",
"port": ""
"host": "Vert"
},
"title": "Konfigurere Agent DVR"
}

View File

@ -2,6 +2,13 @@
"config": {
"error": {
"device_unavailable": "O dispositivo n\u00e3o est\u00e1 dispon\u00edvel"
},
"step": {
"user": {
"data": {
"port": "Porta"
}
}
}
}
}

View File

@ -125,7 +125,7 @@ class AirlyDataUpdateCoordinator(DataUpdateCoordinator):
try:
await measurements.update()
except (AirlyError, ClientConnectorError) as error:
raise UpdateFailed(error)
raise UpdateFailed(error) from error
values = measurements.current["values"]
index = measurements.current["indexes"][0]

View File

@ -6,6 +6,7 @@ from homeassistant.components.air_quality import (
AirQualityEntity,
)
from homeassistant.const import CONF_NAME
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
ATTR_API_ADVICE,
@ -57,12 +58,12 @@ def round_state(func):
return _decorator
class AirlyAirQuality(AirQualityEntity):
class AirlyAirQuality(CoordinatorEntity, AirQualityEntity):
"""Define an Airly air quality."""
def __init__(self, coordinator, name):
"""Initialize."""
self.coordinator = coordinator
super().__init__(coordinator)
self._name = name
self._icon = "mdi:blur"
@ -71,11 +72,6 @@ class AirlyAirQuality(AirQualityEntity):
"""Return the name."""
return self._name
@property
def should_poll(self):
"""Return the polling requirement of the entity."""
return False
@property
def icon(self):
"""Return the icon."""
@ -121,11 +117,6 @@ class AirlyAirQuality(AirQualityEntity):
"entry_type": "service",
}
@property
def available(self):
"""Return True if entity is available."""
return self.coordinator.last_update_success
@property
def device_state_attributes(self):
"""Return the state attributes."""
@ -138,13 +129,3 @@ class AirlyAirQuality(AirQualityEntity):
LABEL_PM_10_LIMIT: self.coordinator.data[ATTR_API_PM10_LIMIT],
LABEL_PM_10_PERCENT: round(self.coordinator.data[ATTR_API_PM10_PERCENT]),
}
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Update Airly entity."""
await self.coordinator.async_request_refresh()

View File

@ -7,11 +7,11 @@ from homeassistant.const import (
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
PRESSURE_HPA,
TEMP_CELSIUS,
UNIT_PERCENTAGE,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
ATTR_API_HUMIDITY,
@ -42,7 +42,7 @@ SENSOR_TYPES = {
ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY,
ATTR_ICON: None,
ATTR_LABEL: ATTR_API_HUMIDITY.capitalize(),
ATTR_UNIT: UNIT_PERCENTAGE,
ATTR_UNIT: PERCENTAGE,
},
ATTR_API_PRESSURE: {
ATTR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
@ -72,12 +72,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(sensors, False)
class AirlySensor(Entity):
class AirlySensor(CoordinatorEntity):
"""Define an Airly sensor."""
def __init__(self, coordinator, name, kind):
"""Initialize."""
self.coordinator = coordinator
super().__init__(coordinator)
self._name = name
self.kind = kind
self._device_class = None
@ -91,11 +91,6 @@ class AirlySensor(Entity):
"""Return the name."""
return f"{self._name} {SENSOR_TYPES[self.kind][ATTR_LABEL]}"
@property
def should_poll(self):
"""Return the polling requirement of the entity."""
return False
@property
def state(self):
"""Return the state."""
@ -143,18 +138,3 @@ class AirlySensor(Entity):
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return SENSOR_TYPES[self.kind][ATTR_UNIT]
@property
def available(self):
"""Return True if entity is available."""
return self.coordinator.last_update_success
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Update Airly entity."""
await self.coordinator.async_request_refresh()

View File

@ -10,7 +10,7 @@
"step": {
"user": {
"data": {
"api_key": "Cl\u00e9 API Airly",
"api_key": "Cl\u00e9 d'API",
"latitude": "Latitude",
"longitude": "Longitude",
"name": "Nom de l'int\u00e9gration"

View File

@ -15,8 +15,7 @@
"longitude": "Lengdegrad",
"name": "Navn p\u00e5 integrasjonen"
},
"description": "Sett opp Airly luftkvalitet integrasjon. For \u00e5 opprette API-n\u00f8kkel, g\u00e5 til [https://developer.airly.eu/register](https://developer.airly.eu/register)",
"title": ""
"description": "Sett opp Airly luftkvalitet integrasjon. For \u00e5 opprette API-n\u00f8kkel, g\u00e5 til [https://developer.airly.eu/register](https://developer.airly.eu/register)"
}
}
}

View File

@ -3,11 +3,9 @@
"step": {
"user": {
"data": {
"api_key": "",
"latitude": "Latitude",
"longitude": "Longitude"
},
"title": ""
}
}
}
}

View File

@ -20,8 +20,11 @@ from homeassistant.const import (
)
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
UpdateFailed,
)
from .const import (
CONF_CITY,
@ -220,13 +223,14 @@ async def async_setup_entry(hass, config_entry):
)
else:
api_coro = client.api.nearest_city(
config_entry.data[CONF_LATITUDE], config_entry.data[CONF_LONGITUDE],
config_entry.data[CONF_LATITUDE],
config_entry.data[CONF_LONGITUDE],
)
try:
return await api_coro
except AirVisualError as err:
raise UpdateFailed(f"Error while retrieving data: {err}")
raise UpdateFailed(f"Error while retrieving data: {err}") from err
coordinator = DataUpdateCoordinator(
hass,
@ -262,7 +266,7 @@ async def async_setup_entry(hass, config_entry):
include_trends=False,
)
except NodeProError as err:
raise UpdateFailed(f"Error while retrieving data: {err}")
raise UpdateFailed(f"Error while retrieving data: {err}") from err
coordinator = DataUpdateCoordinator(
hass,
@ -350,20 +354,15 @@ async def async_update_options(hass, config_entry):
await coordinator.async_request_refresh()
class AirVisualEntity(Entity):
class AirVisualEntity(CoordinatorEntity):
"""Define a generic AirVisual entity."""
def __init__(self, coordinator):
"""Initialize."""
super().__init__(coordinator)
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._icon = None
self._unit = None
self.coordinator = coordinator
@property
def available(self):
"""Return if entity is available."""
return self.coordinator.last_update_success
@property
def device_state_attributes(self):
@ -375,11 +374,6 @@ class AirVisualEntity(Entity):
"""Return the icon."""
return self._icon
@property
def should_poll(self) -> bool:
"""Disable polling."""
return False
@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
@ -398,13 +392,6 @@ class AirVisualEntity(Entity):
self.update_from_latest_data()
async def async_update(self):
"""Update the entity.
Only used by the generic entity update service.
"""
await self.coordinator.async_request_refresh()
@callback
def update_from_latest_data(self):
"""Update the entity from the latest data."""

View File

@ -15,8 +15,8 @@ from homeassistant.const import (
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
TEMP_CELSIUS,
UNIT_PERCENTAGE,
)
from homeassistant.core import callback
@ -57,8 +57,8 @@ GEOGRAPHY_SENSORS = [
GEOGRAPHY_SENSOR_LOCALES = {"cn": "Chinese", "us": "U.S."}
NODE_PRO_SENSORS = [
(SENSOR_KIND_BATTERY_LEVEL, "Battery", DEVICE_CLASS_BATTERY, UNIT_PERCENTAGE),
(SENSOR_KIND_HUMIDITY, "Humidity", DEVICE_CLASS_HUMIDITY, UNIT_PERCENTAGE),
(SENSOR_KIND_BATTERY_LEVEL, "Battery", DEVICE_CLASS_BATTERY, PERCENTAGE),
(SENSOR_KIND_HUMIDITY, "Humidity", DEVICE_CLASS_HUMIDITY, PERCENTAGE),
(SENSOR_KIND_TEMPERATURE, "Temperature", DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS),
]
@ -98,7 +98,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
if config_entry.data[CONF_INTEGRATION_TYPE] == INTEGRATION_TYPE_GEOGRAPHY:
sensors = [
AirVisualGeographySensor(
coordinator, config_entry, kind, name, icon, unit, locale,
coordinator,
config_entry,
kind,
name,
icon,
unit,
locale,
)
for locale in GEOGRAPHY_SENSOR_LOCALES
for kind, name, icon, unit in GEOGRAPHY_SENSORS

View File

@ -21,7 +21,7 @@
"node_pro": {
"data": {
"ip_address": "Adresse IP / nom d'h\u00f4te de l'unit\u00e9",
"password": "Mot de passe de l'unit\u00e9"
"password": "Mot de passe"
},
"description": "Surveillez une unit\u00e9 AirVisual personnelle. Le mot de passe peut \u00eatre r\u00e9cup\u00e9r\u00e9 dans l'interface utilisateur de l'unit\u00e9.",
"title": "Configurer un AirVisual Node/Pro"
@ -32,7 +32,7 @@
"node_pro": "AirVisual Node Pro",
"type": "Type d'int\u00e9gration"
},
"description": "Surveiller la qualit\u00e9 de l\u2019air dans un emplacement g\u00e9ographique.",
"description": "Choisissez le type de donn\u00e9es AirVisual que vous souhaitez surveiller.",
"title": "Configurer AirVisual"
}
}

View File

@ -29,7 +29,6 @@
"user": {
"data": {
"cloud_api": "Geografisk plassering",
"node_pro": "",
"type": "Integrasjonstype"
},
"description": "Velg hvilken type AirVisual-data du vil overv\u00e5ke.",

View File

@ -11,6 +11,11 @@
"longitude": "Longitude"
}
},
"node_pro": {
"data": {
"password": "Senha"
}
},
"user": {
"data": {
"type": "Tipo de Integra\u00e7\u00e3o"

View File

@ -8,8 +8,9 @@ from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_HOME,
SUPPORT_ALARM_ARM_NIGHT,
)
from homeassistant.components.automation import AutomationActionType, state
from homeassistant.components.automation import AutomationActionType
from homeassistant.components.device_automation import TRIGGER_BASE_SCHEMA
from homeassistant.components.homeassistant.triggers import state as state_trigger
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_DOMAIN,
@ -151,13 +152,13 @@ async def async_attach_trigger(
to_state = STATE_ALARM_ARMED_NIGHT
state_config = {
state.CONF_PLATFORM: "state",
state_trigger.CONF_PLATFORM: "state",
CONF_ENTITY_ID: config[CONF_ENTITY_ID],
state.CONF_TO: to_state,
state_trigger.CONF_TO: to_state,
}
if from_state:
state_config[state.CONF_FROM] = from_state
state_config = state.TRIGGER_SCHEMA(state_config)
return await state.async_attach_trigger(
state_config[state_trigger.CONF_FROM] = from_state
state_config = state_trigger.TRIGGER_SCHEMA(state_config)
return await state_trigger.async_attach_trigger(
hass, state_config, action, automation_info, platform_type="device"
)

View File

@ -25,7 +25,7 @@
"state": {
"_": {
"armed": "Zabezpe\u010deno",
"armed_away": "Re\u017eim nep\u0159\u00edtomnost",
"armed_away": "Nep\u0159\u00edtomnost",
"armed_custom_bypass": "Zabezpe\u010deno u\u017eivatelsk\u00fdm obejit\u00edm",
"armed_home": "Re\u017eim domov",
"armed_night": "No\u010dn\u00ed re\u017eim",

View File

@ -26,7 +26,7 @@
"_": {
"armed": "Activ\u00e9",
"armed_away": "Enclench\u00e9e (absent)",
"armed_custom_bypass": "Activ\u00e9e avec exception",
"armed_custom_bypass": "Arm\u00e9 avec exception personnalis\u00e9e",
"armed_home": "Enclench\u00e9e (pr\u00e9sent)",
"armed_night": "Enclench\u00e9 (nuit)",
"arming": "Activation",

View File

@ -1,5 +1,6 @@
"""Alexa capabilities."""
import logging
from typing import List, Optional
from homeassistant.components import (
cover,
@ -36,6 +37,7 @@ from homeassistant.const import (
STATE_UNKNOWN,
STATE_UNLOCKED,
)
from homeassistant.core import State
import homeassistant.util.color as color_util
import homeassistant.util.dt as dt_util
@ -71,32 +73,32 @@ class AlexaCapability:
supported_locales = {"en-US"}
def __init__(self, entity, instance=None):
def __init__(self, entity: State, instance: Optional[str] = None):
"""Initialize an Alexa capability."""
self.entity = entity
self.instance = instance
def name(self):
def name(self) -> str:
"""Return the Alexa API name of this interface."""
raise NotImplementedError
@staticmethod
def properties_supported():
def properties_supported() -> List[dict]:
"""Return what properties this entity supports."""
return []
@staticmethod
def properties_proactively_reported():
def properties_proactively_reported() -> bool:
"""Return True if properties asynchronously reported."""
return False
@staticmethod
def properties_retrievable():
def properties_retrievable() -> bool:
"""Return True if properties can be retrieved."""
return False
@staticmethod
def properties_non_controllable():
def properties_non_controllable() -> bool:
"""Return True if non controllable."""
return None
@ -237,20 +239,34 @@ class AlexaCapability:
"""Return properties serialized for an API response."""
for prop in self.properties_supported():
prop_name = prop["name"]
prop_value = self.get_property(prop_name)
if prop_value is not None:
result = {
"name": prop_name,
"namespace": self.name(),
"value": prop_value,
"timeOfSample": dt_util.utcnow().strftime(DATE_FORMAT),
"uncertaintyInMilliseconds": 0,
}
instance = self.instance
if instance is not None:
result["instance"] = instance
try:
prop_value = self.get_property(prop_name)
except UnsupportedProperty:
raise
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Unexpected error getting %s.%s property from %s",
self.name(),
prop_name,
self.entity,
)
prop_value = None
yield result
if prop_value is None:
continue
result = {
"name": prop_name,
"namespace": self.name(),
"value": prop_value,
"timeOfSample": dt_util.utcnow().strftime(DATE_FORMAT),
"uncertaintyInMilliseconds": 0,
}
instance = self.instance
if instance is not None:
result["instance"] = instance
yield result
class Alexa(AlexaCapability):
@ -850,7 +866,7 @@ class AlexaContactSensor(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-contactsensor.html
"""
supported_locales = {"en-CA", "en-US"}
supported_locales = {"en-CA", "en-US", "it-IT"}
def __init__(self, hass, entity):
"""Initialize the entity."""
@ -889,7 +905,7 @@ class AlexaMotionSensor(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-motionsensor.html
"""
supported_locales = {"en-CA", "en-US"}
supported_locales = {"en-CA", "en-US", "it-IT"}
def __init__(self, hass, entity):
"""Initialize the entity."""
@ -1097,7 +1113,22 @@ class AlexaSecurityPanelController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-securitypanelcontroller.html
"""
supported_locales = {"en-AU", "en-CA", "en-IN", "en-US"}
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"es-US",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
"pt_BR",
}
def __init__(self, hass, entity):
"""Initialize the entity."""

View File

@ -1,6 +1,6 @@
"""Alexa entity adapters."""
import logging
from typing import List
from typing import TYPE_CHECKING, List
from homeassistant.components import (
alarm_control_panel,
@ -34,7 +34,7 @@ from homeassistant.const import (
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
)
from homeassistant.core import callback
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.helpers import network
from homeassistant.util.decorator import Registry
@ -42,6 +42,7 @@ from .capabilities import (
Alexa,
AlexaBrightnessController,
AlexaCameraStreamController,
AlexaCapability,
AlexaChannelController,
AlexaColorController,
AlexaColorTemperatureController,
@ -72,6 +73,9 @@ from .capabilities import (
)
from .const import CONF_DESCRIPTION, CONF_DISPLAY_CATEGORIES
if TYPE_CHECKING:
from .config import AbstractConfig
_LOGGER = logging.getLogger(__name__)
ENTITY_ADAPTERS = Registry()
@ -197,13 +201,18 @@ class DisplayCategory:
WEARABLE = "WEARABLE"
def generate_alexa_id(entity_id: str) -> str:
"""Return the alexa ID for an entity ID."""
return entity_id.replace(".", "#").translate(TRANSLATION_TABLE)
class AlexaEntity:
"""An adaptation of an entity, expressed in Alexa's terms.
The API handlers should manipulate entities only through this interface.
"""
def __init__(self, hass, config, entity):
def __init__(self, hass: HomeAssistant, config: "AbstractConfig", entity: State):
"""Initialize Alexa Entity."""
self.hass = hass
self.config = config
@ -228,7 +237,7 @@ class AlexaEntity:
def alexa_id(self):
"""Return the Alexa API entity id."""
return self.entity.entity_id.replace(".", "#").translate(TRANSLATION_TABLE)
return generate_alexa_id(self.entity.entity_id)
def display_categories(self):
"""Return a list of display categories."""
@ -246,13 +255,13 @@ class AlexaEntity:
"""
raise NotImplementedError
def get_interface(self, capability):
def get_interface(self, capability) -> AlexaCapability:
"""Return the given AlexaInterface.
Raises _UnsupportedInterface.
"""
def interfaces(self):
def interfaces(self) -> List[AlexaCapability]:
"""Return a list of supported interfaces.
Used for discovery. The list should contain AlexaInterface instances.
@ -280,11 +289,18 @@ class AlexaEntity:
}
locale = self.config.locale
capabilities = [
i.serialize_discovery()
for i in self.interfaces()
if locale in i.supported_locales
]
capabilities = []
for i in self.interfaces():
if locale not in i.supported_locales:
continue
try:
capabilities.append(i.serialize_discovery())
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Error serializing %s discovery for %s", i.name(), self.entity
)
result["capabilities"] = capabilities

View File

@ -1542,8 +1542,10 @@ async def async_api_initialize_camera_stream(hass, config, directive, context):
require_ssl=True,
require_standard_port=True,
)
except network.NoURLAvailableError:
raise AlexaInvalidValueError("Failed to find suitable URL to serve to Alexa")
except network.NoURLAvailableError as err:
raise AlexaInvalidValueError(
"Failed to find suitable URL to serve to Alexa"
) from err
payload = {
"cameraStreams": [

View File

@ -10,7 +10,7 @@ from homeassistant.const import MATCH_ALL, STATE_ON
import homeassistant.util.dt as dt_util
from .const import API_CHANGE, Cause
from .entities import ENTITY_ADAPTERS
from .entities import ENTITY_ADAPTERS, generate_alexa_id
from .messages import AlexaResponse
_LOGGER = logging.getLogger(__name__)
@ -181,8 +181,7 @@ async def async_send_delete_message(hass, config, entity_ids):
if domain not in ENTITY_ADAPTERS:
continue
alexa_entity = ENTITY_ADAPTERS[domain](hass, config, hass.states.get(entity_id))
endpoints.append({"endpointId": alexa_entity.alexa_id()})
endpoints.append({"endpointId": generate_alexa_id(entity_id)})
payload = {"endpoints": endpoints, "scope": {"type": "BearerToken", "token": token}}

View File

@ -108,8 +108,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEnt
auth = AlmondLocalAuth(entry.data["host"], websession)
else:
# OAuth2
implementation = await config_entry_oauth2_flow.async_get_config_entry_implementation(
hass, entry
implementation = (
await config_entry_oauth2_flow.async_get_config_entry_implementation(
hass, entry
)
)
oauth_session = config_entry_oauth2_flow.OAuth2Session(
hass, entry, implementation
@ -206,7 +208,7 @@ async def _configure_almond_for_ha(
msg = err
_LOGGER.warning("Unable to configure Almond: %s", msg)
await hass.auth.async_remove_refresh_token(refresh_token)
raise ConfigEntryNotReady
raise ConfigEntryNotReady from err
# Clear all other refresh tokens
for token in list(user.refresh_tokens.values()):

View File

@ -11,7 +11,7 @@ from yarl import URL
from homeassistant import config_entries, core, data_entry_flow
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow
from .const import DOMAIN, TYPE_LOCAL, TYPE_OAUTH2
from .const import DOMAIN as ALMOND_DOMAIN, TYPE_LOCAL, TYPE_OAUTH2
async def async_verify_local_connection(hass: core.HomeAssistant, host: str):
@ -28,11 +28,11 @@ async def async_verify_local_connection(hass: core.HomeAssistant, host: str):
return False
@config_entries.HANDLERS.register(DOMAIN)
@config_entries.HANDLERS.register(ALMOND_DOMAIN)
class AlmondFlowHandler(config_entry_oauth2_flow.AbstractOAuth2FlowHandler):
"""Implementation of the Almond OAuth2 config flow."""
DOMAIN = DOMAIN
DOMAIN = ALMOND_DOMAIN
host = None
hassio_discovery = None

View File

@ -10,7 +10,8 @@
"abort": {
"already_setup": "You can only configure one Almond account.",
"cannot_connect": "Unable to connect to the Almond server.",
"missing_configuration": "Please check the documentation on how to set up Almond."
"missing_configuration": "Please check the documentation on how to set up Almond.",
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]"
}
}
}

View File

@ -7,8 +7,7 @@
},
"step": {
"hassio_confirm": {
"description": "Vil du konfigurere Home Assistant til \u00e5 koble til Almond levert av Hass.io add-on: {addon}?",
"title": ""
"description": "Vil du konfigurere Home Assistant til \u00e5 koble til Almond levert av Hass.io add-on: {addon}?"
},
"pick_implementation": {
"title": "Velg godkjenningsmetode"

View File

@ -2,7 +2,7 @@
"config": {
"abort": {
"access_token": "\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.",
"already_setup": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430.",
"already_setup": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant.",
"no_config": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Ambiclimate \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {

View File

@ -15,10 +15,10 @@ from homeassistant.const import (
CONF_API_KEY,
DEGREE,
EVENT_HOMEASSISTANT_STOP,
PERCENTAGE,
POWER_WATT,
SPEED_MILES_PER_HOUR,
TEMP_FAHRENHEIT,
UNIT_PERCENTAGE,
)
from homeassistant.core import callback
from homeassistant.exceptions import ConfigEntryNotReady
@ -160,18 +160,18 @@ SENSOR_TYPES = {
TYPE_EVENTRAININ: ("Event Rain", "in", TYPE_SENSOR, None),
TYPE_FEELSLIKE: ("Feels Like", TEMP_FAHRENHEIT, TYPE_SENSOR, "temperature"),
TYPE_HOURLYRAININ: ("Hourly Rain Rate", "in/hr", TYPE_SENSOR, None),
TYPE_HUMIDITY10: ("Humidity 10", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY1: ("Humidity 1", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY2: ("Humidity 2", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY3: ("Humidity 3", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY4: ("Humidity 4", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY5: ("Humidity 5", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY6: ("Humidity 6", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY7: ("Humidity 7", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY8: ("Humidity 8", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY9: ("Humidity 9", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY: ("Humidity", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITYIN: ("Humidity In", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY10: ("Humidity 10", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY1: ("Humidity 1", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY2: ("Humidity 2", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY3: ("Humidity 3", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY4: ("Humidity 4", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY5: ("Humidity 5", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY6: ("Humidity 6", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY7: ("Humidity 7", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY8: ("Humidity 8", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY9: ("Humidity 9", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITY: ("Humidity", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_HUMIDITYIN: ("Humidity In", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_LASTRAIN: ("Last Rain", None, TYPE_SENSOR, "timestamp"),
TYPE_MAXDAILYGUST: ("Max Gust", SPEED_MILES_PER_HOUR, TYPE_SENSOR, None),
TYPE_MONTHLYRAININ: ("Monthly Rain", "in", TYPE_SENSOR, None),
@ -185,16 +185,16 @@ SENSOR_TYPES = {
TYPE_RELAY7: ("Relay 7", None, TYPE_BINARY_SENSOR, "connectivity"),
TYPE_RELAY8: ("Relay 8", None, TYPE_BINARY_SENSOR, "connectivity"),
TYPE_RELAY9: ("Relay 9", None, TYPE_BINARY_SENSOR, "connectivity"),
TYPE_SOILHUM10: ("Soil Humidity 10", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM1: ("Soil Humidity 1", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM2: ("Soil Humidity 2", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM3: ("Soil Humidity 3", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM4: ("Soil Humidity 4", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM5: ("Soil Humidity 5", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM6: ("Soil Humidity 6", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM7: ("Soil Humidity 7", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM8: ("Soil Humidity 8", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM9: ("Soil Humidity 9", UNIT_PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM10: ("Soil Humidity 10", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM1: ("Soil Humidity 1", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM2: ("Soil Humidity 2", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM3: ("Soil Humidity 3", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM4: ("Soil Humidity 4", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM5: ("Soil Humidity 5", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM6: ("Soil Humidity 6", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM7: ("Soil Humidity 7", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM8: ("Soil Humidity 8", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILHUM9: ("Soil Humidity 9", PERCENTAGE, TYPE_SENSOR, "humidity"),
TYPE_SOILTEMP10F: ("Soil Temp 10", TEMP_FAHRENHEIT, TYPE_SENSOR, "temperature"),
TYPE_SOILTEMP1F: ("Soil Temp 1", TEMP_FAHRENHEIT, TYPE_SENSOR, "temperature"),
TYPE_SOILTEMP2F: ("Soil Temp 2", TEMP_FAHRENHEIT, TYPE_SENSOR, "temperature"),
@ -300,7 +300,7 @@ async def async_setup_entry(hass, config_entry):
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = ambient
except WebsocketError as err:
_LOGGER.error("Config entry failed: %s", err)
raise ConfigEntryNotReady
raise ConfigEntryNotReady from err
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, ambient.client.websocket.disconnect()

View File

@ -4,7 +4,7 @@ import logging
from amcrest import AmcrestError
from homeassistant.const import CONF_NAME, CONF_SENSORS, UNIT_PERCENTAGE
from homeassistant.const import CONF_NAME, CONF_SENSORS, PERCENTAGE
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
@ -20,7 +20,7 @@ SENSOR_SDCARD = "sdcard"
# Sensor types are defined like: Name, units, icon
SENSORS = {
SENSOR_PTZ_PRESET: ["PTZ Preset", None, "mdi:camera-iris"],
SENSOR_SDCARD: ["SD Used", UNIT_PERCENTAGE, "mdi:sd"],
SENSOR_SDCARD: ["SD Used", PERCENTAGE, "mdi:sd"],
}

View File

@ -4,8 +4,8 @@
"documentation": "https://www.home-assistant.io/integrations/androidtv",
"requirements": [
"adb-shell[async]==0.2.1",
"androidtv[async]==0.0.47",
"pure-python-adb==0.2.2.dev0"
"androidtv[async]==0.0.50",
"pure-python-adb[async]==0.3.0.dev0"
],
"codeowners": ["@JeffLIrion"]
}

View File

@ -374,8 +374,14 @@ def adb_decorator(override_available=False):
err,
)
await self.aftv.adb_close()
self._available = False # pylint: disable=protected-access
self._available = False
return None
except Exception:
# An unforeseen exception occurred. Close the ADB connection so that
# it doesn't happen over and over again, then raise the exception.
await self.aftv.adb_close()
self._available = False
raise
return _adb_exception_catcher
@ -421,10 +427,8 @@ class ADBDevice(MediaPlayerEntity):
# Using "adb_shell" (Python ADB implementation)
self.exceptions = (
AdbTimeoutError,
AttributeError,
BrokenPipeError,
ConnectionResetError,
TypeError,
ValueError,
InvalidChecksumError,
InvalidCommandError,
@ -597,7 +601,8 @@ class ADBDevice(MediaPlayerEntity):
msg = f"Output from service '{SERVICE_LEARN_SENDEVENT}' from {self.entity_id}: '{output}'"
self.hass.components.persistent_notification.async_create(
msg, title="Android TV",
msg,
title="Android TV",
)
_LOGGER.info("%s", msg)

View File

@ -8,7 +8,9 @@ import voluptuous as vol
from homeassistant.const import (
CONF_IP_ADDRESS,
CONF_PASSWORD,
CONF_PORT,
CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP,
EVENT_STATE_CHANGED,
STATE_UNAVAILABLE,
@ -16,6 +18,7 @@ from homeassistant.const import (
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entityfilter import FILTER_SCHEMA
from homeassistant.util import ssl as ssl_util
_LOGGER = logging.getLogger(__name__)
@ -23,6 +26,7 @@ DOMAIN = "apache_kafka"
CONF_FILTER = "filter"
CONF_TOPIC = "topic"
CONF_SECURITY_PROTOCOL = "security_protocol"
CONFIG_SCHEMA = vol.Schema(
{
@ -32,6 +36,11 @@ CONFIG_SCHEMA = vol.Schema(
vol.Required(CONF_PORT): cv.port,
vol.Required(CONF_TOPIC): cv.string,
vol.Optional(CONF_FILTER, default={}): FILTER_SCHEMA,
vol.Optional(CONF_SECURITY_PROTOCOL, default="PLAINTEXT"): vol.In(
["PLAINTEXT", "SASL_SSL"]
),
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
}
)
},
@ -49,6 +58,9 @@ async def async_setup(hass, config):
conf[CONF_PORT],
conf[CONF_TOPIC],
conf[CONF_FILTER],
conf[CONF_SECURITY_PROTOCOL],
conf.get(CONF_USERNAME),
conf.get(CONF_PASSWORD),
)
hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, kafka.shutdown())
@ -64,7 +76,7 @@ class DateTimeJSONEncoder(json.JSONEncoder):
Additionally add encoding for datetime objects as isoformat.
"""
def default(self, o): # pylint: disable=method-hidden
def default(self, o):
"""Implement encoding logic."""
if isinstance(o, datetime):
return o.isoformat()
@ -74,15 +86,31 @@ class DateTimeJSONEncoder(json.JSONEncoder):
class KafkaManager:
"""Define a manager to buffer events to Kafka."""
def __init__(self, hass, ip_address, port, topic, entities_filter):
def __init__(
self,
hass,
ip_address,
port,
topic,
entities_filter,
security_protocol,
username,
password,
):
"""Initialize."""
self._encoder = DateTimeJSONEncoder()
self._entities_filter = entities_filter
self._hass = hass
ssl_context = ssl_util.client_context()
self._producer = AIOKafkaProducer(
loop=hass.loop,
bootstrap_servers=f"{ip_address}:{port}",
compression_type="gzip",
security_protocol=security_protocol,
ssl_context=ssl_context,
sasl_mechanism="PLAIN",
sasl_plain_username=username,
sasl_plain_password=password,
)
self._topic = topic

View File

@ -10,11 +10,11 @@ from homeassistant.const import (
ELECTRICAL_CURRENT_AMPERE,
ELECTRICAL_VOLT_AMPERE,
FREQUENCY_HERTZ,
PERCENTAGE,
POWER_WATT,
TEMP_CELSIUS,
TIME_MINUTES,
TIME_SECONDS,
UNIT_PERCENTAGE,
VOLT,
)
import homeassistant.helpers.config_validation as cv
@ -34,7 +34,7 @@ SENSOR_TYPES = {
"battdate": ["Battery Replaced", "", "mdi:calendar-clock"],
"battstat": ["Battery Status", "", "mdi:information-outline"],
"battv": ["Battery Voltage", VOLT, "mdi:flash"],
"bcharge": ["Battery", UNIT_PERCENTAGE, "mdi:battery"],
"bcharge": ["Battery", PERCENTAGE, "mdi:battery"],
"cable": ["Cable Type", "", "mdi:ethernet-cable"],
"cumonbatt": ["Total Time on Battery", "", "mdi:timer-outline"],
"date": ["Status Date", "", "mdi:calendar-clock"],
@ -48,20 +48,20 @@ SENSOR_TYPES = {
"firmware": ["Firmware Version", "", "mdi:information-outline"],
"hitrans": ["Transfer High", VOLT, "mdi:flash"],
"hostname": ["Hostname", "", "mdi:information-outline"],
"humidity": ["Ambient Humidity", UNIT_PERCENTAGE, "mdi:water-percent"],
"humidity": ["Ambient Humidity", PERCENTAGE, "mdi:water-percent"],
"itemp": ["Internal Temperature", TEMP_CELSIUS, "mdi:thermometer"],
"lastxfer": ["Last Transfer", "", "mdi:transfer"],
"linefail": ["Input Voltage Status", "", "mdi:information-outline"],
"linefreq": ["Line Frequency", FREQUENCY_HERTZ, "mdi:information-outline"],
"linev": ["Input Voltage", VOLT, "mdi:flash"],
"loadpct": ["Load", UNIT_PERCENTAGE, "mdi:gauge"],
"loadapnt": ["Load Apparent Power", UNIT_PERCENTAGE, "mdi:gauge"],
"loadpct": ["Load", PERCENTAGE, "mdi:gauge"],
"loadapnt": ["Load Apparent Power", PERCENTAGE, "mdi:gauge"],
"lotrans": ["Transfer Low", VOLT, "mdi:flash"],
"mandate": ["Manufacture Date", "", "mdi:calendar"],
"masterupd": ["Master Update", "", "mdi:information-outline"],
"maxlinev": ["Input Voltage High", VOLT, "mdi:flash"],
"maxtime": ["Battery Timeout", "", "mdi:timer-off-outline"],
"mbattchg": ["Battery Shutdown", UNIT_PERCENTAGE, "mdi:battery-alert"],
"mbattchg": ["Battery Shutdown", PERCENTAGE, "mdi:battery-alert"],
"minlinev": ["Input Voltage Low", VOLT, "mdi:flash"],
"mintimel": ["Shutdown Time", "", "mdi:timer-outline"],
"model": ["Model", "", "mdi:information-outline"],
@ -76,7 +76,7 @@ SENSOR_TYPES = {
"reg1": ["Register 1 Fault", "", "mdi:information-outline"],
"reg2": ["Register 2 Fault", "", "mdi:information-outline"],
"reg3": ["Register 3 Fault", "", "mdi:information-outline"],
"retpct": ["Restore Requirement", UNIT_PERCENTAGE, "mdi:battery-alert"],
"retpct": ["Restore Requirement", PERCENTAGE, "mdi:battery-alert"],
"selftest": ["Last Self Test", "", "mdi:calendar-clock"],
"sense": ["Sensitivity", "", "mdi:information-outline"],
"serialno": ["Serial Number", "", "mdi:information-outline"],
@ -98,14 +98,14 @@ SPECIFIC_UNITS = {"ITEMP": TEMP_CELSIUS}
INFERRED_UNITS = {
" Minutes": TIME_MINUTES,
" Seconds": TIME_SECONDS,
" Percent": UNIT_PERCENTAGE,
" Percent": PERCENTAGE,
" Volts": VOLT,
" Ampere": ELECTRICAL_CURRENT_AMPERE,
" Volt-Ampere": ELECTRICAL_VOLT_AMPERE,
" Watts": POWER_WATT,
" Hz": FREQUENCY_HERTZ,
" C": TEMP_CELSIUS,
" Percent Load Capacity": UNIT_PERCENTAGE,
" Percent Load Capacity": PERCENTAGE,
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(

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