Merge pull request #71297 from home-assistant/rc

This commit is contained in:
Franck Nijhof 2022-05-04 19:11:20 +02:00 committed by GitHub
commit 4196c4e81c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3633 changed files with 67814 additions and 28395 deletions

View File

@ -73,7 +73,6 @@ omit =
homeassistant/components/arest/binary_sensor.py
homeassistant/components/arest/sensor.py
homeassistant/components/arest/switch.py
homeassistant/components/arlo/*
homeassistant/components/arris_tg2492lg/*
homeassistant/components/aruba/device_tracker.py
homeassistant/components/arwn/sensor.py
@ -83,9 +82,7 @@ omit =
homeassistant/components/aseko_pool_live/sensor.py
homeassistant/components/asterisk_cdr/mailbox.py
homeassistant/components/asterisk_mbox/*
homeassistant/components/asuswrt/__init__.py
homeassistant/components/asuswrt/diagnostics.py
homeassistant/components/asuswrt/router.py
homeassistant/components/aten_pe/*
homeassistant/components/atome/*
homeassistant/components/aurora/__init__.py
@ -120,6 +117,7 @@ omit =
homeassistant/components/bmw_connected_drive/__init__.py
homeassistant/components/bmw_connected_drive/binary_sensor.py
homeassistant/components/bmw_connected_drive/button.py
homeassistant/components/bmw_connected_drive/coordinator.py
homeassistant/components/bmw_connected_drive/device_tracker.py
homeassistant/components/bmw_connected_drive/lock.py
homeassistant/components/bmw_connected_drive/notify.py
@ -215,7 +213,6 @@ omit =
homeassistant/components/devolo_home_control/subscriber.py
homeassistant/components/devolo_home_control/switch.py
homeassistant/components/digital_ocean/*
homeassistant/components/digitalloggers/switch.py
homeassistant/components/discogs/sensor.py
homeassistant/components/discord/__init__.py
homeassistant/components/discord/notify.py
@ -593,10 +590,6 @@ omit =
homeassistant/components/keyboard_remote/*
homeassistant/components/kira/*
homeassistant/components/kiwi/lock.py
homeassistant/components/knx/__init__.py
homeassistant/components/knx/climate.py
homeassistant/components/knx/cover.py
homeassistant/components/knx/notify.py
homeassistant/components/kodi/__init__.py
homeassistant/components/kodi/browse_media.py
homeassistant/components/kodi/const.py
@ -678,6 +671,9 @@ omit =
homeassistant/components/map/*
homeassistant/components/mastodon/notify.py
homeassistant/components/matrix/*
homeassistant/components/meater/__init__.py
homeassistant/components/meater/const.py
homeassistant/components/meater/sensor.py
homeassistant/components/media_extractor/*
homeassistant/components/mediaroom/media_player.py
homeassistant/components/melcloud/__init__.py
@ -996,7 +992,8 @@ omit =
homeassistant/components/rtorrent/sensor.py
homeassistant/components/russound_rio/media_player.py
homeassistant/components/russound_rnet/media_player.py
homeassistant/components/sabnzbd/*
homeassistant/components/sabnzbd/__init__.py
homeassistant/components/sabnzbd/sensor.py
homeassistant/components/saj/sensor.py
homeassistant/components/satel_integra/*
homeassistant/components/schluter/*
@ -1030,6 +1027,10 @@ omit =
homeassistant/components/sensibo/number.py
homeassistant/components/sensibo/select.py
homeassistant/components/sensibo/sensor.py
homeassistant/components/sensibo/update.py
homeassistant/components/senz/__init__.py
homeassistant/components/senz/api.py
homeassistant/components/senz/climate.py
homeassistant/components/serial/sensor.py
homeassistant/components/serial_pm/sensor.py
homeassistant/components/sesame/lock.py
@ -1128,6 +1129,8 @@ omit =
homeassistant/components/spotify/media_player.py
homeassistant/components/spotify/system_health.py
homeassistant/components/spotify/util.py
homeassistant/components/slimproto/__init__.py
homeassistant/components/slimproto/media_player.py
homeassistant/components/squeezebox/__init__.py
homeassistant/components/squeezebox/browse_media.py
homeassistant/components/squeezebox/media_player.py
@ -1177,6 +1180,7 @@ omit =
homeassistant/components/synology_dsm/camera.py
homeassistant/components/synology_dsm/diagnostics.py
homeassistant/components/synology_dsm/common.py
homeassistant/components/synology_dsm/entity.py
homeassistant/components/synology_dsm/sensor.py
homeassistant/components/synology_dsm/service.py
homeassistant/components/synology_dsm/switch.py
@ -1201,7 +1205,7 @@ omit =
homeassistant/components/tankerkoenig/const.py
homeassistant/components/tankerkoenig/sensor.py
homeassistant/components/tapsaff/binary_sensor.py
homeassistant/components/tautulli/const.py
homeassistant/components/tautulli/__init__.py
homeassistant/components/tautulli/coordinator.py
homeassistant/components/tautulli/sensor.py
homeassistant/components/ted5000/sensor.py
@ -1265,6 +1269,7 @@ omit =
homeassistant/components/tractive/__init__.py
homeassistant/components/tractive/binary_sensor.py
homeassistant/components/tractive/device_tracker.py
homeassistant/components/tractive/diagnostics.py
homeassistant/components/tractive/entity.py
homeassistant/components/tractive/sensor.py
homeassistant/components/tractive/switch.py
@ -1276,6 +1281,9 @@ omit =
homeassistant/components/tradfri/light.py
homeassistant/components/tradfri/sensor.py
homeassistant/components/tradfri/switch.py
homeassistant/components/trafikverket_ferry/__init__.py
homeassistant/components/trafikverket_ferry/coordinator.py
homeassistant/components/trafikverket_ferry/sensor.py
homeassistant/components/trafikverket_train/__init__.py
homeassistant/components/trafikverket_train/sensor.py
homeassistant/components/trafikverket_weatherstation/__init__.py
@ -1365,6 +1373,7 @@ omit =
homeassistant/components/vicare/button.py
homeassistant/components/vicare/climate.py
homeassistant/components/vicare/const.py
homeassistant/components/vicare/diagnostics.py
homeassistant/components/vicare/__init__.py
homeassistant/components/vicare/sensor.py
homeassistant/components/vicare/water_heater.py
@ -1428,6 +1437,7 @@ omit =
homeassistant/components/xiaomi_miio/button.py
homeassistant/components/xiaomi_miio/device.py
homeassistant/components/xiaomi_miio/device_tracker.py
homeassistant/components/xiaomi_miio/diagnostics.py
homeassistant/components/xiaomi_miio/fan.py
homeassistant/components/xiaomi_miio/gateway.py
homeassistant/components/xiaomi_miio/humidifier.py
@ -1443,6 +1453,7 @@ omit =
homeassistant/components/yale_smart_alarm/__init__.py
homeassistant/components/yale_smart_alarm/alarm_control_panel.py
homeassistant/components/yale_smart_alarm/binary_sensor.py
homeassistant/components/yale_smart_alarm/button.py
homeassistant/components/yale_smart_alarm/const.py
homeassistant/components/yale_smart_alarm/coordinator.py
homeassistant/components/yale_smart_alarm/diagnostics.py
@ -1452,6 +1463,7 @@ omit =
homeassistant/components/yamaha_musiccast/media_player.py
homeassistant/components/yamaha_musiccast/number.py
homeassistant/components/yamaha_musiccast/select.py
homeassistant/components/yamaha_musiccast/switch.py
homeassistant/components/yandex_transport/*
homeassistant/components/yeelightsunflower/light.py
homeassistant/components/yi/camera.py
@ -1489,6 +1501,7 @@ omit =
homeassistant/components/zwave_me/button.py
homeassistant/components/zwave_me/cover.py
homeassistant/components/zwave_me/climate.py
homeassistant/components/zwave_me/fan.py
homeassistant/components/zwave_me/helpers.py
homeassistant/components/zwave_me/light.py
homeassistant/components/zwave_me/lock.py

View File

@ -11,7 +11,8 @@
"ms-python.vscode-pylance",
"visualstudioexptteam.vscodeintellicode",
"redhat.vscode-yaml",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"GitHub.vscode-pull-request-github"
],
// Please keep this file in sync with settings in home-assistant/.vscode/settings.default.json
"settings": {

View File

@ -78,12 +78,13 @@ body:
- type: textarea
attributes:
label: Diagnostics information
placeholder: "drag-and-drop the diagnostics data file here (do not copy-and-paste the content)"
description: >-
Many integrations provide the ability to download diagnostic data
on the device page (and on the integration dashboard).
**It would really help if you could download the diagnostics data for the device you are having issues with,
and drag-and-drop that file into the textbox below.**
and <ins>drag-and-drop that file into the textbox below.</ins>**
It generally allows pinpointing defects and thus resolving issues faster.
- type: textarea

View File

@ -24,12 +24,12 @@ jobs:
publish: ${{ steps.version.outputs.publish }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
with:
fetch-depth: 0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -67,10 +67,10 @@ jobs:
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -100,11 +100,11 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
if: needs.init.outputs.channel == 'dev'
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -173,7 +173,7 @@ jobs:
- tinker
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set build additional args
run: |
@ -216,7 +216,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Initialize git
uses: home-assistant/actions/helpers/git-init@master
@ -255,7 +255,7 @@ jobs:
- "homeassistant"
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Login to DockerHub
if: matrix.registry == 'homeassistant'

View File

@ -22,7 +22,7 @@ on:
env:
CACHE_VERSION: 9
PIP_CACHE_VERSION: 3
HA_SHORT_VERSION: 2022.4
HA_SHORT_VERSION: 2022.5
DEFAULT_PYTHON: 3.9
PRE_COMMIT_CACHE: ~/.cache/pre-commit
PIP_CACHE: /tmp/pip-cache
@ -51,7 +51,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Filter for core changes
uses: dorny/paths-filter@v2.10.2
id: core
@ -152,10 +152,10 @@ jobs:
pre-commit-key: ${{ steps.generate-pre-commit-key.outputs.key }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Generate partial Python venv restore key
@ -172,7 +172,7 @@ jobs:
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')"
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: >-
@ -189,7 +189,7 @@ jobs:
# ${{ runner.os }}-${{ steps.python.outputs.python-version }}-base-venv-${{ env.CACHE_VERSION }}-
- name: Restore pip wheel cache
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PIP_CACHE }}
key: >-
@ -212,7 +212,7 @@ jobs:
hashFiles('.pre-commit-config.yaml') }}"
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
@ -233,15 +233,15 @@ jobs:
- prepare-base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -253,7 +253,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }}
@ -283,15 +283,15 @@ jobs:
- prepare-base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -303,7 +303,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }}
@ -334,15 +334,15 @@ jobs:
needs: prepare-base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -354,7 +354,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }}
@ -376,15 +376,15 @@ jobs:
- prepare-base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -396,7 +396,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }}
@ -435,11 +435,19 @@ jobs:
. venv/bin/activate
pre-commit run --hook-stage manual check-json --all-files
- name: Run prettier
- name: Run prettier (fully)
if: needs.changes.outputs.test_full_suite == 'true'
run: |
. venv/bin/activate
pre-commit run --hook-stage manual prettier --all-files
- name: Run prettier (partially)
if: needs.changes.outputs.test_full_suite == 'false'
shell: bash
run: |
. venv/bin/activate
pre-commit run --hook-stage manual prettier --files {homeassistant,tests}/components/${{ needs.changes.outputs.integrations_glob }}/**/*
- name: Register check executables problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/check-executables-have-shebangs.json"
@ -491,10 +499,10 @@ jobs:
container: homeassistant/ci-azure:${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ matrix.python-version }}-${{
@ -515,15 +523,15 @@ jobs:
needs: prepare-base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -550,7 +558,7 @@ jobs:
container: homeassistant/ci-azure:${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Generate partial Python venv restore key
id: generate-python-key
run: >-
@ -565,7 +573,7 @@ jobs:
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')"
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: >-
@ -582,7 +590,7 @@ jobs:
# ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ env.CACHE_VERSION }}-
- name: Restore pip wheel cache
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: ${{ env.PIP_CACHE }}
key: >-
@ -618,10 +626,10 @@ jobs:
container: homeassistant/ci-azure:${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ matrix.python-version }}-${{
@ -660,10 +668,10 @@ jobs:
container: homeassistant/ci-azure:${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ matrix.python-version }}-${{
@ -704,10 +712,10 @@ jobs:
container: homeassistant/ci-azure:${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ matrix.python-version }}-${{
@ -747,10 +755,10 @@ jobs:
container: homeassistant/ci-azure:${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache@v3.0.0
uses: actions/cache@v3.0.2
with:
path: venv
key: ${{ runner.os }}-${{ matrix.python-version }}-${{
@ -835,14 +843,14 @@ jobs:
- pytest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Download all coverage artifacts
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
- name: Upload coverage to Codecov (full coverage)
if: needs.changes.outputs.test_full_suite == 'true'
uses: codecov/codecov-action@v2.1.0
uses: codecov/codecov-action@v3.1.0
with:
flags: full-suite
- name: Upload coverage to Codecov (partial coverage)
if: needs.changes.outputs.test_full_suite == 'false'
uses: codecov/codecov-action@v2.1.0
uses: codecov/codecov-action@v3.1.0

View File

@ -8,6 +8,7 @@ on:
jobs:
stale:
if: github.repository_owner == 'home-assistant'
runs-on: ubuntu-latest
steps:
# The 90 day stale policy
@ -16,7 +17,7 @@ jobs:
# - No PRs marked as no-stale
# - No issues marked as no-stale or help-wanted
- name: 90 days stale issues & PRs policy
uses: actions/stale@v4
uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90
@ -53,7 +54,7 @@ jobs:
# - No PRs marked as no-stale or new-integrations
# - No issues (-1)
- name: 30 days stale PRs policy
uses: actions/stale@v4
uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30
@ -78,7 +79,7 @@ jobs:
# - No Issues marked as no-stale or help-wanted
# - No PRs (-1)
- name: Needs more information stale issues policy
uses: actions/stale@v4
uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
only-labels: "needs-more-information"

View File

@ -21,10 +21,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -40,10 +40,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3.0.0
uses: actions/setup-python@v3.1.2
with:
python-version: ${{ env.DEFAULT_PYTHON }}

View File

@ -22,7 +22,7 @@ jobs:
architectures: ${{ steps.info.outputs.architectures }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Get information
id: info
@ -74,15 +74,15 @@ jobs:
- "3.9-alpine3.14"
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Download env_file
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: env_file
- name: Download requirements_diff
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: requirements_diff
@ -115,15 +115,15 @@ jobs:
- "3.9-alpine3.14"
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- name: Download env_file
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: env_file
- name: Download requirements_diff
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: requirements_diff

View File

@ -1,6 +1,6 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.31.1
rev: v2.32.0
hooks:
- id: pyupgrade
args: [--py39-plus]

View File

@ -46,6 +46,7 @@ homeassistant.components.ambient_station.*
homeassistant.components.amcrest.*
homeassistant.components.ampio.*
homeassistant.components.aseko_pool_live.*
homeassistant.components.asuswrt.*
homeassistant.components.automation.*
homeassistant.components.backup.*
homeassistant.components.binary_sensor.*
@ -62,11 +63,7 @@ homeassistant.components.canary.*
homeassistant.components.cover.*
homeassistant.components.crownstone.*
homeassistant.components.cpuspeed.*
homeassistant.components.deconz
homeassistant.components.deconz.config_flow
homeassistant.components.deconz.diagnostics
homeassistant.components.deconz.gateway
homeassistant.components.deconz.services
homeassistant.components.deconz.*
homeassistant.components.device_automation.*
homeassistant.components.device_tracker.*
homeassistant.components.devolo_home_control.*
@ -78,6 +75,7 @@ homeassistant.components.dsmr.*
homeassistant.components.dunehd.*
homeassistant.components.efergy.*
homeassistant.components.elgato.*
homeassistant.components.elkm1.*
homeassistant.components.esphome.*
homeassistant.components.energy.*
homeassistant.components.evil_genius_labs.*
@ -88,6 +86,7 @@ homeassistant.components.flunearyou.*
homeassistant.components.flux_led.*
homeassistant.components.forecast_solar.*
homeassistant.components.fritzbox.*
homeassistant.components.fritzbox_callmonitor.*
homeassistant.components.fronius.*
homeassistant.components.frontend.*
homeassistant.components.fritz.*
@ -196,6 +195,7 @@ homeassistant.components.scene.*
homeassistant.components.select.*
homeassistant.components.sensor.*
homeassistant.components.senseme.*
homeassistant.components.senz.*
homeassistant.components.shelly.*
homeassistant.components.simplisafe.*
homeassistant.components.slack.*

View File

@ -56,7 +56,6 @@ build.json @home-assistant/supervisor
/tests/components/alexa/ @home-assistant/cloud @ochlocracy
/homeassistant/components/almond/ @gcampax @balloob
/tests/components/almond/ @gcampax @balloob
/homeassistant/components/alpha_vantage/ @fabaff
/homeassistant/components/ambee/ @frenck
/tests/components/ambee/ @frenck
/homeassistant/components/amberelectric/ @madpilot
@ -82,7 +81,6 @@ build.json @home-assistant/supervisor
/tests/components/aprs/ @PhilRW
/homeassistant/components/arcam_fmj/ @elupus
/tests/components/arcam_fmj/ @elupus
/homeassistant/components/arest/ @fabaff
/homeassistant/components/arris_tg2492lg/ @vanbalken
/homeassistant/components/aseko_pool_live/ @milanmeu
/tests/components/aseko_pool_live/ @milanmeu
@ -121,7 +119,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/beewi_smartclim/ @alemuro
/homeassistant/components/binary_sensor/ @home-assistant/core
/tests/components/binary_sensor/ @home-assistant/core
/homeassistant/components/bitcoin/ @fabaff
/homeassistant/components/bizkaibus/ @UgaitzEtxebarria
/homeassistant/components/blebox/ @bbx-a @bbx-jp
/tests/components/blebox/ @bbx-a @bbx-jp
@ -253,7 +250,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/dunehd/ @bieniu
/tests/components/dunehd/ @bieniu
/homeassistant/components/dwd_weather_warnings/ @runningman84 @stephan192 @Hummel95
/homeassistant/components/dweet/ @fabaff
/homeassistant/components/dynalite/ @ziv1234
/tests/components/dynalite/ @ziv1234
/homeassistant/components/eafm/ @Jc2k
@ -332,7 +328,6 @@ build.json @home-assistant/supervisor
/tests/components/flipr/ @cnico
/homeassistant/components/flo/ @dmulcahey
/tests/components/flo/ @dmulcahey
/homeassistant/components/flock/ @fabaff
/homeassistant/components/flume/ @ChrisMandich @bdraco
/tests/components/flume/ @ChrisMandich @bdraco
/homeassistant/components/flunearyou/ @bachya
@ -354,6 +349,8 @@ build.json @home-assistant/supervisor
/tests/components/fritz/ @mammuth @AaronDavidSchneider @chemelli74 @mib1185
/homeassistant/components/fritzbox/ @mib1185 @flabbamann
/tests/components/fritzbox/ @mib1185 @flabbamann
/homeassistant/components/fritzbox_callmonitor/ @cdce8p
/tests/components/fritzbox_callmonitor/ @cdce8p
/homeassistant/components/fronius/ @nielstron @farmio
/tests/components/fronius/ @nielstron @farmio
/homeassistant/components/frontend/ @home-assistant/frontend
@ -381,9 +378,8 @@ build.json @home-assistant/supervisor
/tests/components/gios/ @bieniu
/homeassistant/components/github/ @timmo001 @ludeeus
/tests/components/github/ @timmo001 @ludeeus
/homeassistant/components/gitter/ @fabaff
/homeassistant/components/glances/ @fabaff @engrbm87
/tests/components/glances/ @fabaff @engrbm87
/homeassistant/components/glances/ @engrbm87
/tests/components/glances/ @engrbm87
/homeassistant/components/goalzero/ @tkdrob
/tests/components/goalzero/ @tkdrob
/homeassistant/components/gogogate2/ @vangorra @bdraco
@ -476,8 +472,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/image_processing/ @home-assistant/core
/tests/components/image_processing/ @home-assistant/core
/homeassistant/components/incomfort/ @zxdavb
/homeassistant/components/influxdb/ @fabaff @mdegat01
/tests/components/influxdb/ @fabaff @mdegat01
/homeassistant/components/influxdb/ @mdegat01
/tests/components/influxdb/ @mdegat01
/homeassistant/components/input_boolean/ @home-assistant/core
/tests/components/input_boolean/ @home-assistant/core
/homeassistant/components/input_button/ @home-assistant/core
@ -554,6 +550,7 @@ build.json @home-assistant/supervisor
/tests/components/lcn/ @alengwenus
/homeassistant/components/lg_netcast/ @Drafteed
/homeassistant/components/life360/ @pnbruckner
/homeassistant/components/lifx/ @Djelibeybi
/homeassistant/components/light/ @home-assistant/core
/tests/components/light/ @home-assistant/core
/homeassistant/components/linux_battery/ @fabaff
@ -588,6 +585,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/matrix/ @tinloaf
/homeassistant/components/mazda/ @bdr99
/tests/components/mazda/ @bdr99
/homeassistant/components/meater/ @Sotolotl @emontnemery
/tests/components/meater/ @Sotolotl @emontnemery
/homeassistant/components/media_player/ @home-assistant/core
/tests/components/media_player/ @home-assistant/core
/homeassistant/components/media_source/ @hunterjm
@ -637,7 +636,6 @@ build.json @home-assistant/supervisor
/tests/components/motion_blinds/ @starkillerOG
/homeassistant/components/motioneye/ @dermotduffy
/tests/components/motioneye/ @dermotduffy
/homeassistant/components/mpd/ @fabaff
/homeassistant/components/mqtt/ @emontnemery
/tests/components/mqtt/ @emontnemery
/homeassistant/components/msteams/ @peroyvind
@ -684,8 +682,6 @@ build.json @home-assistant/supervisor
/tests/components/nina/ @DeerMaximum
/homeassistant/components/nissan_leaf/ @filcole
/homeassistant/components/nmbs/ @thibmaek
/homeassistant/components/no_ip/ @fabaff
/tests/components/no_ip/ @fabaff
/homeassistant/components/noaa_tides/ @jdelaney72
/homeassistant/components/notify/ @home-assistant/core
/tests/components/notify/ @home-assistant/core
@ -758,8 +754,8 @@ build.json @home-assistant/supervisor
/tests/components/persistent_notification/ @home-assistant/core
/homeassistant/components/philips_js/ @elupus
/tests/components/philips_js/ @elupus
/homeassistant/components/pi_hole/ @fabaff @johnluetke @shenxn
/tests/components/pi_hole/ @fabaff @johnluetke @shenxn
/homeassistant/components/pi_hole/ @johnluetke @shenxn
/tests/components/pi_hole/ @johnluetke @shenxn
/homeassistant/components/picnic/ @corneyl
/tests/components/picnic/ @corneyl
/homeassistant/components/pilight/ @trekky12
@ -793,13 +789,15 @@ build.json @home-assistant/supervisor
/tests/components/pure_energie/ @klaasnicolaas
/homeassistant/components/push/ @dgomes
/tests/components/push/ @dgomes
/homeassistant/components/pvoutput/ @fabaff @frenck
/tests/components/pvoutput/ @fabaff @frenck
/homeassistant/components/pvoutput/ @frenck
/tests/components/pvoutput/ @frenck
/homeassistant/components/pvpc_hourly_pricing/ @azogue
/tests/components/pvpc_hourly_pricing/ @azogue
/homeassistant/components/qbittorrent/ @geoffreylagaisse
/homeassistant/components/qld_bushfire/ @exxamalte
/tests/components/qld_bushfire/ @exxamalte
/homeassistant/components/qnap_qsw/ @Noltari
/tests/components/qnap_qsw/ @Noltari
/homeassistant/components/quantum_gateway/ @cisasteelersfan
/homeassistant/components/qvr_pro/ @oblogic7
/homeassistant/components/qwikswitch/ @kellerza
@ -857,6 +855,8 @@ build.json @home-assistant/supervisor
/tests/components/rtsp_to_webrtc/ @allenporter
/homeassistant/components/ruckus_unleashed/ @gabe565
/tests/components/ruckus_unleashed/ @gabe565
/homeassistant/components/sabnzbd/ @shaiu
/tests/components/sabnzbd/ @shaiu
/homeassistant/components/safe_mode/ @home-assistant/core
/tests/components/safe_mode/ @home-assistant/core
/homeassistant/components/saj/ @fredericvl
@ -887,6 +887,8 @@ build.json @home-assistant/supervisor
/tests/components/sensor/ @home-assistant/core
/homeassistant/components/sentry/ @dcramer @frenck
/tests/components/sentry/ @dcramer @frenck
/homeassistant/components/senz/ @milanmeu
/tests/components/senz/ @milanmeu
/homeassistant/components/serial/ @fabaff
/homeassistant/components/seven_segments/ @fabaff
/homeassistant/components/sharkiq/ @JeffResc @funkybunch @AritroSaha10
@ -915,6 +917,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/sleepiq/ @mfugate1 @kbickar
/tests/components/sleepiq/ @mfugate1 @kbickar
/homeassistant/components/slide/ @ualex73
/homeassistant/components/slimproto/ @marcelveldt
/tests/components/slimproto/ @marcelveldt
/homeassistant/components/sma/ @kellerza @rklomp
/tests/components/sma/ @kellerza @rklomp
/homeassistant/components/smappee/ @bsmappee
@ -929,8 +933,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/smhi/ @gjohansson-ST
/tests/components/smhi/ @gjohansson-ST
/homeassistant/components/sms/ @ocalvo
/homeassistant/components/smtp/ @fabaff
/tests/components/smtp/ @fabaff
/homeassistant/components/solaredge/ @frenck
/tests/components/solaredge/ @frenck
/homeassistant/components/solaredge_local/ @drobtravels @scheric
@ -957,8 +959,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/splunk/ @Bre77
/homeassistant/components/spotify/ @frenck
/tests/components/spotify/ @frenck
/homeassistant/components/sql/ @dgomes
/tests/components/sql/ @dgomes
/homeassistant/components/sql/ @dgomes @gjohansson-ST
/tests/components/sql/ @dgomes @gjohansson-ST
/homeassistant/components/squeezebox/ @rajlaud
/tests/components/squeezebox/ @rajlaud
/homeassistant/components/srp_energy/ @briglx
@ -967,6 +969,8 @@ build.json @home-assistant/supervisor
/tests/components/starline/ @anonym-tsk
/homeassistant/components/statistics/ @fabaff @ThomDietrich
/tests/components/statistics/ @fabaff @ThomDietrich
/homeassistant/components/steam_online/ @tkdrob
/tests/components/steam_online/ @tkdrob
/homeassistant/components/steamist/ @bdraco
/tests/components/steamist/ @bdraco
/homeassistant/components/stiebel_eltron/ @fucm
@ -1002,7 +1006,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/synology_dsm/ @hacf-fr @Quentame @mib1185
/tests/components/synology_dsm/ @hacf-fr @Quentame @mib1185
/homeassistant/components/synology_srm/ @aerialls
/homeassistant/components/syslog/ @fabaff
/homeassistant/components/system_bridge/ @timmo001
/tests/components/system_bridge/ @timmo001
/homeassistant/components/tado/ @michaelarnauts @north3221
@ -1016,7 +1019,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/tapsaff/ @bazwilliams
/homeassistant/components/tasmota/ @emontnemery
/tests/components/tasmota/ @emontnemery
/homeassistant/components/tautulli/ @ludeeus
/homeassistant/components/tautulli/ @ludeeus @tkdrob
/tests/components/tautulli/ @ludeeus @tkdrob
/homeassistant/components/tellduslive/ @fredrike
/tests/components/tellduslive/ @fredrike
/homeassistant/components/template/ @PhracturedBlue @tetienne @home-assistant/core
@ -1042,14 +1046,16 @@ build.json @home-assistant/supervisor
/tests/components/tomorrowio/ @raman325
/homeassistant/components/totalconnect/ @austinmroczek
/tests/components/totalconnect/ @austinmroczek
/homeassistant/components/tplink/ @rytilahti @thegardenmonkey
/tests/components/tplink/ @rytilahti @thegardenmonkey
/homeassistant/components/tplink/ @rytilahti @thegardenmonkey @bdraco
/tests/components/tplink/ @rytilahti @thegardenmonkey @bdraco
/homeassistant/components/traccar/ @ludeeus
/tests/components/traccar/ @ludeeus
/homeassistant/components/trace/ @home-assistant/core
/tests/components/trace/ @home-assistant/core
/homeassistant/components/tractive/ @Danielhiversen @zhulik @bieniu
/tests/components/tractive/ @Danielhiversen @zhulik @bieniu
/homeassistant/components/trafikverket_ferry/ @gjohansson-ST
/tests/components/trafikverket_ferry/ @gjohansson-ST
/homeassistant/components/trafikverket_train/ @endor-force @gjohansson-ST
/tests/components/trafikverket_train/ @endor-force @gjohansson-ST
/homeassistant/components/trafikverket_weatherstation/ @endor-force @gjohansson-ST
@ -1058,8 +1064,8 @@ build.json @home-assistant/supervisor
/tests/components/transmission/ @engrbm87 @JPHutchins
/homeassistant/components/tts/ @pvizeli
/tests/components/tts/ @pvizeli
/homeassistant/components/tuya/ @Tuya @zlinoliver @METISU @frenck
/tests/components/tuya/ @Tuya @zlinoliver @METISU @frenck
/homeassistant/components/tuya/ @Tuya @zlinoliver @frenck
/tests/components/tuya/ @Tuya @zlinoliver @frenck
/homeassistant/components/twentemilieu/ @frenck
/tests/components/twentemilieu/ @frenck
/homeassistant/components/twinkly/ @dr1rrb @Robbie1221
@ -1076,8 +1082,6 @@ build.json @home-assistant/supervisor
/tests/components/upcloud/ @scop
/homeassistant/components/update/ @home-assistant/core
/tests/components/update/ @home-assistant/core
/homeassistant/components/updater/ @home-assistant/core
/tests/components/updater/ @home-assistant/core
/homeassistant/components/upnp/ @StevenLooman @ehendrix23
/tests/components/upnp/ @StevenLooman @ehendrix23
/homeassistant/components/uptime/ @frenck
@ -1104,8 +1108,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/verisure/ @frenck
/tests/components/verisure/ @frenck
/homeassistant/components/versasense/ @flamm3blemuff1n
/homeassistant/components/version/ @fabaff @ludeeus
/tests/components/version/ @fabaff @ludeeus
/homeassistant/components/version/ @ludeeus
/tests/components/version/ @ludeeus
/homeassistant/components/vesync/ @markperdue @webdjoe @thegardenmonkey
/tests/components/vesync/ @markperdue @webdjoe @thegardenmonkey
/homeassistant/components/vicare/ @oischinger

View File

@ -19,6 +19,7 @@ RUN \
libpcap-dev \
libturbojpeg0 \
git \
cmake \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@ -147,9 +147,7 @@ class Data:
if not bcrypt.checkpw(password.encode(), user_hash):
raise InvalidAuth
def hash_password( # pylint: disable=no-self-use
self, password: str, for_storage: bool = False
) -> bytes:
def hash_password(self, password: str, for_storage: bool = False) -> bytes:
"""Encode a password."""
hashed: bytes = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

View File

@ -4,10 +4,7 @@ from __future__ import annotations
from abodepy.devices.alarm import AbodeAlarm as AbodeAl
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
SUPPORT_ALARM_ARM_HOME,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
@ -38,7 +35,10 @@ class AbodeAlarm(AbodeDevice, alarm.AlarmControlPanelEntity):
_attr_icon = ICON
_attr_code_arm_required = False
_attr_supported_features = SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME
| AlarmControlPanelEntityFeature.ARM_AWAY
)
_device: AbodeAl
@property

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3."
},
"create_entry": {
"default": "Alguns sensors no estan activats de manera predeterminada. Els pots activar des del registre d'entitats, despr\u00e9s de la configuraci\u00f3 de la integraci\u00f3.\nLa previsi\u00f3 meteorol\u00f2gica no est\u00e0 activada de manera predeterminada. Pots activar-la a les opcions de la integraci\u00f3."
},
"error": {
"cannot_connect": "Ha fallat la connexi\u00f3",
"invalid_api_key": "Clau API inv\u00e0lida",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Bereits konfiguriert. Nur eine einzige Konfiguration m\u00f6glich."
},
"create_entry": {
"default": "Einige Sensoren sind standardm\u00e4\u00dfig nicht aktiviert. Du kannst sie nach der Integrationskonfiguration in der Entit\u00e4tsregistrierung aktivieren.\nDie Wettervorhersage ist nicht standardm\u00e4\u00dfig aktiviert. Du kannst sie in den Integrationsoptionen aktivieren."
},
"error": {
"cannot_connect": "Verbindung fehlgeschlagen",
"invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "\u0388\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03c1\u03c5\u03b8\u03bc\u03b9\u03c3\u03c4\u03b5\u03af. \u039c\u03cc\u03bd\u03bf \u03bc\u03af\u03b1 \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae."
},
"create_entry": {
"default": "\u039f\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf\u03b9 \u03b1\u03b9\u03c3\u03b8\u03b7\u03c4\u03ae\u03c1\u03b5\u03c2 \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf\u03b9 \u03b1\u03c0\u03cc \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae. \u039c\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03c4\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c3\u03c4\u03bf \u03bc\u03b7\u03c4\u03c1\u03ce\u03bf \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd \u03bc\u03b5\u03c4\u03ac \u03c4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03b5\u03bd\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7\u03c2.\n \u0397 \u03c0\u03c1\u03cc\u03b3\u03bd\u03c9\u03c3\u03b7 \u03ba\u03b1\u03b9\u03c1\u03bf\u03cd \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b1\u03c0\u03cc \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae. \u039c\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03c4\u03bf \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c3\u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7\u03c2."
},
"error": {
"cannot_connect": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2",
"invalid_api_key": "\u039c\u03b7 \u03ad\u03b3\u03ba\u03c5\u03c1\u03bf \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Already configured. Only a single configuration possible."
},
"create_entry": {
"default": "Some sensors are not enabled by default. You can enable them in the entity registry after the integration configuration.\nWeather forecast is not enabled by default. You can enable it in the integration options."
},
"error": {
"cannot_connect": "Failed to connect",
"invalid_api_key": "Invalid API key",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Sidumine juba tehtud. V\u00f5imalik on ainult 1 sidumine."
},
"create_entry": {
"default": "M\u00f5ned andurid ei ole vaikimisi lubatud. Saad neid lubada \u00fcksuse registris p\u00e4rast sidumise seadistamist.\nIlmaprognoos ei ole vaikimisi lubatud. Saad selle lubada sidumise valikutes."
},
"error": {
"cannot_connect": "\u00dchendamine nurjus",
"invalid_api_key": "API v\u00f5ti on vale",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible."
},
"create_entry": {
"default": "Certains capteurs ne sont pas activ\u00e9s par d\u00e9faut. Vous pouvez les activer dans le registre des entit\u00e9s une fois la configuration de l'int\u00e9gration termin\u00e9e.\nLes pr\u00e9visions m\u00e9t\u00e9orologiques ne sont pas activ\u00e9es par d\u00e9faut. Vous pouvez les activer dans les options de l'int\u00e9gration."
},
"error": {
"cannot_connect": "\u00c9chec de connexion",
"invalid_api_key": "Cl\u00e9 d'API non valide",
@ -16,7 +19,7 @@
"longitude": "Longitude",
"name": "Nom"
},
"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.",
"description": "Si vous avez besoin d'aide pour la configuration, consultez\u00a0: 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 une fois la configuration de l'int\u00e9gration termin\u00e9e.\nLes pr\u00e9visions m\u00e9t\u00e9orologiques ne sont pas activ\u00e9es par d\u00e9faut. Vous pouvez les activer dans les options de l'int\u00e9gration.",
"title": "AccuWeather"
}
}

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "M\u00e1r konfigur\u00e1lva van. Csak egy konfigur\u00e1ci\u00f3 lehets\u00e9ges."
},
"create_entry": {
"default": "Egyes \u00e9rz\u00e9kel\u0151k alap\u00e9rtelmez\u00e9s szerint nincsenek enged\u00e9lyezve. Az integr\u00e1ci\u00f3s konfigur\u00e1ci\u00f3 ut\u00e1n enged\u00e9lyezheti \u0151ket az entit\u00e1s rendszerle\u00edr\u00f3 adatb\u00e1zis\u00e1ban.\nAz id\u0151j\u00e1r\u00e1s-el\u0151rejelz\u00e9s alap\u00e9rtelmez\u00e9s szerint nincs enged\u00e9lyezve. Ezt az integr\u00e1ci\u00f3s be\u00e1ll\u00edt\u00e1sokban enged\u00e9lyezheti."
},
"error": {
"cannot_connect": "Sikertelen csatlakoz\u00e1s",
"invalid_api_key": "\u00c9rv\u00e9nytelen API kulcs",
@ -14,7 +17,7 @@
"api_key": "API kulcs",
"latitude": "Sz\u00e9less\u00e9g",
"longitude": "Hossz\u00fas\u00e1g",
"name": "N\u00e9v"
"name": "Elnevez\u00e9s"
},
"description": "Ha seg\u00edts\u00e9gre van sz\u00fcks\u00e9ge a konfigur\u00e1l\u00e1shoz, n\u00e9zze meg itt: https://www.home-assistant.io/integrations/accuweather/ \n\nEgyes \u00e9rz\u00e9kel\u0151k alap\u00e9rtelmez\u00e9s szerint nincsenek enged\u00e9lyezve. Az integr\u00e1ci\u00f3s konfigur\u00e1ci\u00f3 ut\u00e1n enged\u00e9lyezheti \u0151ket az entit\u00e1s-nyilv\u00e1ntart\u00e1sban.\nAz id\u0151j\u00e1r\u00e1s-el\u0151rejelz\u00e9s alap\u00e9rtelmez\u00e9s szerint nincs enged\u00e9lyezve. Ezt az integr\u00e1ci\u00f3s be\u00e1ll\u00edt\u00e1sokban enged\u00e9lyezheti.",
"title": "AccuWeather"

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Sudah dikonfigurasi. Hanya satu konfigurasi yang diizinkan."
},
"create_entry": {
"default": "Beberapa sensor tidak diaktifkan secara default. Anda dapat mengaktifkannya di registri entitas setelah konfigurasi integrasi.\nPrakiraan cuaca tidak diaktifkan secara default. Anda dapat mengaktifkannya di opsi integrasi."
},
"error": {
"cannot_connect": "Gagal terhubung",
"invalid_api_key": "Kunci API tidak valid",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione."
},
"create_entry": {
"default": "Alcuni sensori non sono abilitati per impostazione predefinita. Puoi abilitarli nel registro delle entit\u00e0 dopo la configurazione dell'integrazione.\nLe previsioni del tempo non sono abilitate per impostazione predefinita. Puoi abilitarlo nelle opzioni di integrazione."
},
"error": {
"cannot_connect": "Impossibile connettersi",
"invalid_api_key": "Chiave API non valida",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "\u3059\u3067\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u5358\u4e00\u306e\u8a2d\u5b9a\u3057\u304b\u3067\u304d\u307e\u305b\u3093\u3002"
},
"create_entry": {
"default": "\u4e00\u90e8\u306e\u30bb\u30f3\u30b5\u30fc\u306f\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u3067\u306f\u6709\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u69cb\u6210\u5f8c\u3001\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u30ec\u30b8\u30b9\u30c8\u30ea\u3067\u305d\u308c\u3089\u3092\u6709\u52b9\u306b\u3067\u304d\u307e\u3059\u3002\n\u5929\u6c17\u4e88\u5831\u306f\u30c7\u30d5\u30a9\u30eb\u30c8\u3067\u306f\u6709\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u6709\u52b9\u306b\u3067\u304d\u307e\u3059\u3002"
},
"error": {
"cannot_connect": "\u63a5\u7d9a\u306b\u5931\u6557\u3057\u307e\u3057\u305f",
"invalid_api_key": "\u7121\u52b9\u306aAPI\u30ad\u30fc",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Al geconfigureerd. Slechts een enkele configuratie mogelijk."
},
"create_entry": {
"default": "Sommige sensoren zijn standaard niet ingeschakeld. U kunt ze inschakelen in het entiteitenregister na de integratieconfiguratie.\nWeersvoorspelling is niet standaard ingeschakeld. U kunt deze inschakelen in de integratieopties."
},
"error": {
"cannot_connect": "Kan geen verbinding maken",
"invalid_api_key": "API-sleutel",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig."
},
"create_entry": {
"default": "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 integreringsalternativene."
},
"error": {
"cannot_connect": "Tilkobling mislyktes",
"invalid_api_key": "Ugyldig API-n\u00f8kkel",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja."
},
"create_entry": {
"default": "Niekt\u00f3re sensory nie s\u0105 domy\u015blnie w\u0142\u0105czone. Mo\u017cesz je w\u0142\u0105czy\u0107 w rejestrze encji po skonfigurowaniu integracji.\nPrognoza pogody nie jest domy\u015blnie w\u0142\u0105czona. Mo\u017cesz to w\u0142\u0105czy\u0107 w opcjach integracji."
},
"error": {
"cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia",
"invalid_api_key": "Nieprawid\u0142owy klucz API",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "J\u00e1 configurado. Apenas uma configura\u00e7\u00e3o \u00e9 poss\u00edvel."
},
"create_entry": {
"default": "Alguns sensores n\u00e3o s\u00e3o ativados por padr\u00e3o. Voc\u00ea pode habilit\u00e1-los no registro da entidade ap\u00f3s a configura\u00e7\u00e3o da integra\u00e7\u00e3o.\n A previs\u00e3o do tempo n\u00e3o est\u00e1 habilitada por padr\u00e3o. Voc\u00ea pode habilit\u00e1-lo nas op\u00e7\u00f5es de integra\u00e7\u00e3o."
},
"error": {
"cannot_connect": "Falha ao conectar",
"invalid_api_key": "Chave de API inv\u00e1lida",

View File

@ -3,6 +3,9 @@
"abort": {
"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."
},
"create_entry": {
"default": "\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u043d\u0441\u043e\u0440\u044b \u0441\u043a\u0440\u044b\u0442\u044b \u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u0440\u043e\u0433\u043d\u043e\u0437 \u043f\u043e\u0433\u043e\u0434\u044b. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0443\u0436\u043d\u044b\u0445 \u0441\u0435\u043d\u0441\u043e\u0440\u043e\u0432 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u043d\u043e\u0437 \u043f\u043e\u0433\u043e\u0434\u044b \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438."
},
"error": {
"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.",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "Zaten yap\u0131land\u0131r\u0131lm\u0131\u015f. Yaln\u0131zca tek bir konfig\u00fcrasyon m\u00fcmk\u00fcnd\u00fcr."
},
"create_entry": {
"default": "Baz\u0131 sens\u00f6rler varsay\u0131lan olarak etkin de\u011fildir. Bunlar\u0131, entegrasyon yap\u0131land\u0131rmas\u0131ndan sonra varl\u0131k kay\u0131t defterinde etkinle\u015ftirebilirsiniz.\n Hava tahmini varsay\u0131lan olarak etkin de\u011fildir. Entegrasyon se\u00e7eneklerinde etkinle\u015ftirebilirsiniz."
},
"error": {
"cannot_connect": "Ba\u011flanma hatas\u0131",
"invalid_api_key": "Ge\u00e7ersiz API anahtar\u0131",

View File

@ -3,6 +3,9 @@
"abort": {
"single_instance_allowed": "\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210\u3001\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u88dd\u7f6e\u3002"
},
"create_entry": {
"default": "\u90e8\u5206\u611f\u6e2c\u5668\u9810\u8a2d\u70ba\u4e0d\u555f\u7528\u72c0\u614b\u3002\u53ef\u4ee5\u7a0d\u5f8c\u65bc\u6574\u5408\u8a2d\u5b9a\u9801\u9762\u4e2d\u7684\u5be6\u9ad4\u8a3b\u518a\u8868\u9032\u884c\u555f\u7528\u3002\n\u5929\u6c23\u9810\u5831\u9810\u8a2d\u70ba\u4e0d\u555f\u7528\u3001\u53ef\u4ee5\u65bc\u6574\u5408\u9078\u9805\u4e2d\u9032\u884c\u555f\u7528\u3002"
},
"error": {
"cannot_connect": "\u9023\u7dda\u5931\u6557",
"invalid_api_key": "API \u91d1\u9470\u7121\u6548",

View File

@ -3,15 +3,8 @@ from __future__ import annotations
from homeassistant.components.cover import (
ATTR_POSITION,
SUPPORT_CLOSE,
SUPPORT_CLOSE_TILT,
SUPPORT_OPEN,
SUPPORT_OPEN_TILT,
SUPPORT_SET_POSITION,
SUPPORT_SET_TILT_POSITION,
SUPPORT_STOP,
SUPPORT_STOP_TILT,
CoverEntity,
CoverEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
@ -79,14 +72,17 @@ class AcmedaCover(AcmedaBase, CoverEntity):
supported_features = 0
if self.current_cover_position is not None:
supported_features |= (
SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP | SUPPORT_SET_POSITION
CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.STOP
| CoverEntityFeature.SET_POSITION
)
if self.current_cover_tilt_position is not None:
supported_features |= (
SUPPORT_OPEN_TILT
| SUPPORT_CLOSE_TILT
| SUPPORT_STOP_TILT
| SUPPORT_SET_TILT_POSITION
CoverEntityFeature.OPEN_TILT
| CoverEntityFeature.CLOSE_TILT
| CoverEntityFeature.STOP_TILT
| CoverEntityFeature.SET_TILT_POSITION
)
return supported_features

View File

@ -7,11 +7,7 @@ from adax import Adax
from adax_local import Adax as AdaxLocal
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
HVAC_MODE_HEAT,
HVAC_MODE_OFF,
SUPPORT_TARGET_TEMPERATURE,
)
from homeassistant.components.climate.const import ClimateEntityFeature, HVACMode
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_TEMPERATURE,
@ -65,10 +61,10 @@ async def async_setup_entry(
class AdaxDevice(ClimateEntity):
"""Representation of a heater."""
_attr_hvac_modes = [HVAC_MODE_HEAT, HVAC_MODE_OFF]
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
_attr_max_temp = 35
_attr_min_temp = 5
_attr_supported_features = SUPPORT_TARGET_TEMPERATURE
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
_attr_target_temperature_step = PRECISION_WHOLE
_attr_temperature_unit = TEMP_CELSIUS
@ -86,12 +82,12 @@ class AdaxDevice(ClimateEntity):
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
"""Set hvac mode."""
if hvac_mode == HVAC_MODE_HEAT:
if hvac_mode == HVACMode.HEAT:
temperature = max(self.min_temp, self.target_temperature or self.min_temp)
await self._adax_data_handler.set_room_target_temperature(
self._device_id, temperature, True
)
elif hvac_mode == HVAC_MODE_OFF:
elif hvac_mode == HVACMode.OFF:
await self._adax_data_handler.set_room_target_temperature(
self._device_id, self.min_temp, False
)
@ -116,10 +112,10 @@ class AdaxDevice(ClimateEntity):
self._attr_current_temperature = room.get("temperature")
self._attr_target_temperature = room.get("targetTemperature")
if room["heatingEnabled"]:
self._attr_hvac_mode = HVAC_MODE_HEAT
self._attr_hvac_mode = HVACMode.HEAT
self._attr_icon = "mdi:radiator"
else:
self._attr_hvac_mode = HVAC_MODE_OFF
self._attr_hvac_mode = HVACMode.OFF
self._attr_icon = "mdi:radiator-off"
return
@ -127,11 +123,11 @@ class AdaxDevice(ClimateEntity):
class LocalAdaxDevice(ClimateEntity):
"""Representation of a heater."""
_attr_hvac_modes = [HVAC_MODE_HEAT]
_attr_hvac_mode = HVAC_MODE_HEAT
_attr_hvac_modes = [HVACMode.HEAT]
_attr_hvac_mode = HVACMode.HEAT
_attr_max_temp = 35
_attr_min_temp = 5
_attr_supported_features = SUPPORT_TARGET_TEMPERATURE
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
_attr_target_temperature_step = PRECISION_WHOLE
_attr_temperature_unit = TEMP_CELSIUS

View File

@ -20,9 +20,9 @@
"local": {
"data": {
"wifi_pswd": "WiFi jelsz\u00f3",
"wifi_ssid": "WiFi ssid"
"wifi_ssid": "Wi-Fi SSID"
},
"description": "\u00c1ll\u00edtsa vissza a f\u0171t\u0151berendez\u00e9st a + \u00e9s az OK gomb nyomvatart\u00e1s\u00e1val, m\u00edg a kijelz\u0151n a \"Reset\" (Vissza\u00e1ll\u00edt\u00e1s) felirat nem jelenik meg. Ezut\u00e1n nyomja meg \u00e9s tartsa lenyomva a f\u0171t\u0151berendez\u00e9s OK gombj\u00e1t, am\u00edg a k\u00e9k led villogni nem kezd, majd nyomja meg a K\u00fcld\u00e9s gombot. A f\u0171t\u0151berendez\u00e9s konfigur\u00e1l\u00e1sa n\u00e9h\u00e1ny percet vehet ig\u00e9nybe."
"description": "\u00c1ll\u00edtsa vissza a f\u0171t\u0151berendez\u00e9st a + \u00e9s az OK gomb nyomvatart\u00e1s\u00e1val, m\u00edg a kijelz\u0151n a \"Reset\" (Vissza\u00e1ll\u00edt\u00e1s) felirat nem jelenik meg. Ezut\u00e1n nyomja meg \u00e9s tartsa lenyomva a f\u0171t\u0151berendez\u00e9s OK gombj\u00e1t, am\u00edg a k\u00e9k led villogni nem kezd, l\u00e9pjen tov\u00e1bb. A f\u0171t\u0151berendez\u00e9s konfigur\u00e1l\u00e1sa n\u00e9h\u00e1ny percet vehet ig\u00e9nybe."
},
"user": {
"data": {

View File

@ -31,7 +31,7 @@
"host": "Host",
"password": "Wachtwoord"
},
"description": "Selecteer verbindingstype. Lokaal vereist verwarming met bluetooth"
"description": "Selecteer verbindingstype. Lokaal vereist verwarming met Bluetooth."
}
}
}

View File

@ -8,11 +8,8 @@ from homeassistant.components.cover import (
ATTR_POSITION,
DEVICE_CLASSES_SCHEMA,
PLATFORM_SCHEMA,
SUPPORT_CLOSE,
SUPPORT_OPEN,
SUPPORT_SET_POSITION,
SUPPORT_STOP,
CoverEntity,
CoverEntityFeature,
)
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
from homeassistant.core import HomeAssistant
@ -117,11 +114,13 @@ class AdsCover(AdsEntity, CoverEntity):
self._ads_var_close = ads_var_close
self._ads_var_stop = ads_var_stop
self._attr_device_class = device_class
self._attr_supported_features = SUPPORT_OPEN | SUPPORT_CLOSE
self._attr_supported_features = (
CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
)
if ads_var_stop is not None:
self._attr_supported_features |= SUPPORT_STOP
self._attr_supported_features |= CoverEntityFeature.STOP
if ads_var_pos_set is not None:
self._attr_supported_features |= SUPPORT_SET_POSITION
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
async def async_added_to_hass(self):
"""Register device notification."""

View File

@ -7,7 +7,7 @@ import voluptuous as vol
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
PLATFORM_SCHEMA,
SUPPORT_BRIGHTNESS,
ColorMode,
LightEntity,
)
from homeassistant.const import CONF_NAME
@ -60,7 +60,11 @@ class AdsLight(AdsEntity, LightEntity):
self._state_dict[STATE_KEY_BRIGHTNESS] = None
self._ads_var_brightness = ads_var_brightness
if ads_var_brightness is not None:
self._attr_supported_features = SUPPORT_BRIGHTNESS
self._attr_color_mode = ColorMode.BRIGHTNESS
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
else:
self._attr_color_mode = ColorMode.ONOFF
self._attr_supported_color_modes = {ColorMode.ONOFF}
async def async_added_to_hass(self):
"""Register device notification."""

View File

@ -9,15 +9,8 @@ from homeassistant.components.climate.const import (
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
SUPPORT_FAN_MODE,
SUPPORT_TARGET_TEMPERATURE,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, TEMP_CELSIUS
@ -35,20 +28,20 @@ from .const import (
from .entity import AdvantageAirEntity
ADVANTAGE_AIR_HVAC_MODES = {
"heat": HVAC_MODE_HEAT,
"cool": HVAC_MODE_COOL,
"vent": HVAC_MODE_FAN_ONLY,
"dry": HVAC_MODE_DRY,
"myauto": HVAC_MODE_AUTO,
"heat": HVACMode.HEAT,
"cool": HVACMode.COOL,
"vent": HVACMode.FAN_ONLY,
"dry": HVACMode.DRY,
"myauto": HVACMode.AUTO,
}
HASS_HVAC_MODES = {v: k for k, v in ADVANTAGE_AIR_HVAC_MODES.items()}
AC_HVAC_MODES = [
HVAC_MODE_OFF,
HVAC_MODE_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_DRY,
HVACMode.OFF,
HVACMode.COOL,
HVACMode.HEAT,
HVACMode.FAN_ONLY,
HVACMode.DRY,
]
ADVANTAGE_AIR_FAN_MODES = {
@ -61,7 +54,7 @@ HASS_FAN_MODES = {v: k for k, v in ADVANTAGE_AIR_FAN_MODES.items()}
FAN_SPEEDS = {FAN_LOW: 30, FAN_MEDIUM: 60, FAN_HIGH: 100}
ADVANTAGE_AIR_SERVICE_SET_MYZONE = "set_myzone"
ZONE_HVAC_MODES = [HVAC_MODE_OFF, HVAC_MODE_HEAT_COOL]
ZONE_HVAC_MODES = [HVACMode.OFF, HVACMode.HEAT_COOL]
PARALLEL_UPDATES = 0
@ -108,7 +101,9 @@ class AdvantageAirAC(AdvantageAirClimateEntity):
_attr_fan_modes = [FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH]
_attr_hvac_modes = AC_HVAC_MODES
_attr_supported_features = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
)
def __init__(self, instance, ac_key):
"""Initialize an AdvantageAir AC unit."""
@ -116,7 +111,7 @@ class AdvantageAirAC(AdvantageAirClimateEntity):
self._attr_name = self._ac["name"]
self._attr_unique_id = f'{self.coordinator.data["system"]["rid"]}-{ac_key}'
if self._ac.get("myAutoModeEnabled"):
self._attr_hvac_modes = AC_HVAC_MODES + [HVAC_MODE_AUTO]
self._attr_hvac_modes = AC_HVAC_MODES + [HVACMode.AUTO]
@property
def target_temperature(self):
@ -128,7 +123,7 @@ class AdvantageAirAC(AdvantageAirClimateEntity):
"""Return the current HVAC modes."""
if self._ac["state"] == ADVANTAGE_AIR_STATE_ON:
return ADVANTAGE_AIR_HVAC_MODES.get(self._ac["mode"])
return HVAC_MODE_OFF
return HVACMode.OFF
@property
def fan_mode(self):
@ -137,7 +132,7 @@ class AdvantageAirAC(AdvantageAirClimateEntity):
async def async_set_hvac_mode(self, hvac_mode):
"""Set the HVAC Mode and State."""
if hvac_mode == HVAC_MODE_OFF:
if hvac_mode == HVACMode.OFF:
await self.async_change(
{self.ac_key: {"info": {"state": ADVANTAGE_AIR_STATE_OFF}}}
)
@ -169,7 +164,7 @@ class AdvantageAirZone(AdvantageAirClimateEntity):
"""AdvantageAir Zone control."""
_attr_hvac_modes = ZONE_HVAC_MODES
_attr_supported_features = SUPPORT_TARGET_TEMPERATURE
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
def __init__(self, instance, ac_key, zone_key):
"""Initialize an AdvantageAir Zone control."""
@ -183,8 +178,8 @@ class AdvantageAirZone(AdvantageAirClimateEntity):
def hvac_mode(self):
"""Return the current state as HVAC mode."""
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
return HVAC_MODE_HEAT_COOL
return HVAC_MODE_OFF
return HVACMode.HEAT_COOL
return HVACMode.OFF
@property
def current_temperature(self):
@ -198,7 +193,7 @@ class AdvantageAirZone(AdvantageAirClimateEntity):
async def async_set_hvac_mode(self, hvac_mode):
"""Set the HVAC Mode and State."""
if hvac_mode == HVAC_MODE_OFF:
if hvac_mode == HVACMode.OFF:
await self.async_change(
{
self.ac_key: {

View File

@ -1,11 +1,9 @@
"""Cover platform for Advantage Air integration."""
from homeassistant.components.cover import (
ATTR_POSITION,
SUPPORT_CLOSE,
SUPPORT_OPEN,
SUPPORT_SET_POSITION,
CoverDeviceClass,
CoverEntity,
CoverEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -43,7 +41,11 @@ class AdvantageAirZoneVent(AdvantageAirEntity, CoverEntity):
"""Advantage Air Cover Class."""
_attr_device_class = CoverDeviceClass.DAMPER
_attr_supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
_attr_supported_features = (
CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.SET_POSITION
)
def __init__(self, instance, ac_key, zone_key):
"""Initialize an Advantage Air Cover Class."""

View File

@ -14,7 +14,7 @@
"longitude": "Longitud",
"name": "Nom de la integraci\u00f3"
},
"description": "Configura la integraci\u00f3 d'AEMET OpenData. Per generar la clau API, v\u00e9s a https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Per generar la clau API, v\u00e9s a https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "L\u00e4ngengrad",
"name": "Name der Integration"
},
"description": "Richte die AEMET OpenData Integration ein. Um den API-Schl\u00fcssel zu generieren, besuche https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Um den API-Schl\u00fcssel zu generieren, besuche https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Longitude",
"name": "Name of the integration"
},
"description": "Set up AEMET OpenData integration. To generate API key go to https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "To generate API key go to https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Pikkuskraad",
"name": "Sidumise nimi"
},
"description": "Seadista AEMET OpenData sidumine. API v\u00f5tme loomiseks mine aadressile https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "API-v\u00f5tme loomiseks mine aadressile https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Longitude",
"name": "Nom de l'int\u00e9gration"
},
"description": "Configurez l'int\u00e9gration AEMET OpenData. Pour g\u00e9n\u00e9rer la cl\u00e9 API, acc\u00e9dez \u00e0 https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Pour g\u00e9n\u00e9rer une cl\u00e9 d'API, rendez-vous sur https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Hossz\u00fas\u00e1g",
"name": "Az integr\u00e1ci\u00f3 neve"
},
"description": "\u00c1ll\u00edtsa be az AEMET OpenData integr\u00e1ci\u00f3t. Az API-kulcs el\u0151\u00e1ll\u00edt\u00e1s\u00e1hoz keresse fel a https://opendata.aemet.es/centrodedescargas/altaUsuario webhelyet.",
"description": "Az API-kulcs l\u00e9trehoz\u00e1s\u00e1hoz keresse fel a https://opendata.aemet.es/centrodedescargas/altaUsuario webhelyet",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Bujur",
"name": "Nama integrasi"
},
"description": "Siapkan integrasi AEMET OpenData. Untuk menghasilkan kunci API, buka https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Untuk membuat kunci API, buka https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Logitudine",
"name": "Nome dell'integrazione"
},
"description": "Imposta l'integrazione di AEMET OpenData. Per generare la chiave API, vai su https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Per generare la chiave API, vai su https://opendata.aemet.es/centrodescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Lengtegraad",
"name": "Naam van de integratie"
},
"description": "Stel AEMET OpenData-integratie in. Ga naar https://opendata.aemet.es/centrodedescargas/altaUsuario om een API-sleutel te genereren",
"description": "Om een API sleutel te genereren ga naar https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Lengdegrad",
"name": "Navnet p\u00e5 integrasjonen"
},
"description": "Sett opp AEMET OpenData-integrasjon. For \u00e5 generere API-n\u00f8kkel, g\u00e5 til https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "For \u00e5 generere API-n\u00f8kkel, g\u00e5 til https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "D\u0142ugo\u015b\u0107 geograficzna",
"name": "Nazwa integracji"
},
"description": "Skonfiguruj integracj\u0119 AEMET OpenData. Aby wygenerowa\u0107 klucz API, przejd\u017a do https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Aby wygenerowa\u0107 klucz API, przejd\u017a do https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Longitude",
"name": "Nome da integra\u00e7\u00e3o"
},
"description": "Configure a integra\u00e7\u00e3o AEMET OpenData. Para gerar a chave API acesse https://opendata.aemet.es/centrodedescargas/altaUsuario",
"description": "Para gerar a chave API acesse https://opendata.aemet.es/centrodedescargas/altaUsuario",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "\u0414\u043e\u043b\u0433\u043e\u0442\u0430",
"name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435"
},
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Home Assistant \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 AEMET OpenData. \u0427\u0442\u043e\u0431\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u044e\u0447 API, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430 https://opendata.aemet.es/centrodedescargas/altaUsuario.",
"description": "\u0427\u0442\u043e\u0431\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u044e\u0447 API, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 https://opendata.aemet.es/centrodedescargas/altaUsuario.",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "Boylam",
"name": "Entegrasyonun ad\u0131"
},
"description": "AEMET OpenData entegrasyonunu ayarlay\u0131n. API anahtar\u0131 olu\u015fturmak i\u00e7in https://opendata.aemet.es/centrodedescargas/altaUsuario adresine gidin.",
"description": "API anahtar\u0131 olu\u015fturmak i\u00e7in https://opendata.aemet.es/centrodedescargas/altaUsuario adresine gidin.",
"title": "AEMET OpenData"
}
}

View File

@ -14,7 +14,7 @@
"longitude": "\u7d93\u5ea6",
"name": "\u6574\u5408\u540d\u7a31"
},
"description": "\u6b32\u8a2d\u5b9a AEMET OpenData \u6574\u5408\u3002\u8acb\u81f3 https://opendata.aemet.es/centrodedescargas/altaUsuario \u7522\u751f API \u91d1\u9470",
"description": "\u8acb\u81f3 https://opendata.aemet.es/centrodedescargas/altaUsuario \u4ee5\u7522\u751f API \u91d1\u9470",
"title": "AEMET OpenData"
}
}

View File

@ -1,9 +1,7 @@
"""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.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
@ -38,7 +36,9 @@ class AgentBaseStation(AlarmControlPanelEntity):
_attr_icon = ICON
_attr_supported_features = (
SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT
AlarmControlPanelEntityFeature.ARM_HOME
| AlarmControlPanelEntityFeature.ARM_AWAY
| AlarmControlPanelEntityFeature.ARM_NIGHT
)
def __init__(self, client):

View File

@ -4,7 +4,7 @@ import logging
from agent import AgentError
from homeassistant.components.camera import SUPPORT_ON_OFF
from homeassistant.components.camera import CameraEntityFeature
from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.helpers import entity_platform
@ -63,6 +63,8 @@ async def async_setup_entry(
class AgentCamera(MjpegCamera):
"""Representation of an Agent Device Stream."""
_attr_supported_features = CameraEntityFeature.ON_OFF
def __init__(self, device):
"""Initialize as a subclass of MjpegCamera."""
self.device = device
@ -134,11 +136,6 @@ class AgentCamera(MjpegCamera):
"""Return True if entity is connected."""
return self.device.connected
@property
def supported_features(self) -> int:
"""Return supported features."""
return SUPPORT_ON_OFF
@property
def is_on(self) -> bool:
"""Return true if on."""

View File

@ -4,7 +4,7 @@
"already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van"
},
"error": {
"already_in_progress": "A konfigur\u00e1l\u00e1s m\u00e1r folyamatban van",
"already_in_progress": "A be\u00e1ll\u00edt\u00e1si folyamat m\u00e1r el lett kezdve",
"cannot_connect": "Sikertelen csatlakoz\u00e1s"
},
"step": {

View File

@ -0,0 +1,31 @@
"""Diagnostics support for Airly."""
from __future__ import annotations
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_API_KEY,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_UNIQUE_ID,
)
from homeassistant.core import HomeAssistant
from . import AirlyDataUpdateCoordinator
from .const import DOMAIN
TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_UNIQUE_ID}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict:
"""Return diagnostics for a config entry."""
coordinator: AirlyDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
diagnostics_data = {
"config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT),
"coordinator_data": coordinator.data,
}
return diagnostics_data

View File

@ -15,7 +15,7 @@
"longitude": "Longitud",
"name": "Nom"
},
"description": "Configura la integraci\u00f3 de qualitat de l'aire Airly. Per generar la clau API, v\u00e9s a https://developer.airly.eu/register",
"description": "Per generar la clau API, v\u00e9s a https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "L\u00e4ngengrad",
"name": "Name"
},
"description": "Einrichtung der Airly-Luftqualit\u00e4t Integration. Um einen API-Schl\u00fcssel zu generieren, registriere dich auf https://developer.airly.eu/register",
"description": "Um einen API-Schl\u00fcssel zu generieren, besuche https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Longitude",
"name": "Name"
},
"description": "Set up Airly air quality integration. To generate API key go to https://developer.airly.eu/register",
"description": "To generate API key go to https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Pikkuskraad",
"name": "Nimi"
},
"description": "Seadista Airly \u00f5hukvaliteedi andmete sidumine. API v\u00f5tme loomiseks mine aadressile https://developer.airly.eu/register",
"description": "API-v\u00f5tme loomiseks mine aadressile https://developer.airly.eu/register",
"title": ""
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Longitude",
"name": "Nom"
},
"description": "Configurez l'int\u00e9gration de la qualit\u00e9 de l'air Airly. Pour g\u00e9n\u00e9rer une cl\u00e9 API, rendez-vous sur https://developer.airly.eu/register.",
"description": "Pour g\u00e9n\u00e9rer une cl\u00e9 d'API, rendez-vous sur https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -13,9 +13,9 @@
"api_key": "API kulcs",
"latitude": "Sz\u00e9less\u00e9g",
"longitude": "Hossz\u00fas\u00e1g",
"name": "N\u00e9v"
"name": "Elnevez\u00e9s"
},
"description": "Az Airly leveg\u0151min\u0151s\u00e9gi integr\u00e1ci\u00f3j\u00e1nak be\u00e1ll\u00edt\u00e1sa. Api-kulcs l\u00e9trehoz\u00e1s\u00e1hoz nyissa meg a k\u00f6vetkez\u0151 weboldalt: https://developer.airly.eu/register",
"description": "Az API-kulcs l\u00e9trehoz\u00e1s\u00e1hoz keresse fel a https://developer.airly.eu/register webhelyet",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Bujur",
"name": "Nama"
},
"description": "Siapkan integrasi kualitas udara Airly. Untuk membuat kunci API, buka https://developer.airly.eu/register",
"description": "Untuk membuat kunci API, buka https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Logitudine",
"name": "Nome"
},
"description": "Configurazione dell'integrazione della qualit\u00e0 dell'aria Airly. Per generare la chiave API vai su https://developer.airly.eu/register",
"description": "Per generare la chiave API, vai su https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Lengtegraad",
"name": "Naam"
},
"description": "Airly-integratie van luchtkwaliteit instellen. Ga naar https://developer.airly.eu/register om de API-sleutel te genereren",
"description": "Om een API sleutel te genereren ga naar https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Lengdegrad",
"name": "Navn"
},
"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)",
"description": "For \u00e5 generere API-n\u00f8kkel, g\u00e5 til https://developer.airly.eu/register",
"title": ""
}
}

View File

@ -15,7 +15,7 @@
"longitude": "D\u0142ugo\u015b\u0107 geograficzna",
"name": "Nazwa"
},
"description": "Konfiguracja integracji Airly. By wygenerowa\u0107 klucz API, przejd\u017a na stron\u0119 https://developer.airly.eu/register",
"description": "By wygenerowa\u0107 klucz API, przejd\u017a na stron\u0119 https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Longitude",
"name": "Nome"
},
"description": "Configure a integra\u00e7\u00e3o da qualidade do ar airly. Para gerar a chave de API v\u00e1 para https://developer.airly.eu/register",
"description": "Para gerar a chave de API, acesse https://developer.airly.eu/register",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "\u0414\u043e\u043b\u0433\u043e\u0442\u0430",
"name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435"
},
"description": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043f\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0443 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u043e\u0437\u0434\u0443\u0445\u0430 Airly. \u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u044e\u0447 API, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 https://developer.airly.eu/register.",
"description": "\u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u044e\u0447 API, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 https://developer.airly.eu/register.",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "Boylam",
"name": "Ad"
},
"description": "Airly hava kalitesi entegrasyonunu ayarlay\u0131n. API anahtar\u0131 olu\u015fturmak i\u00e7in https://developer.airly.eu/register adresine gidin.",
"description": "API anahtar\u0131 olu\u015fturmak i\u00e7in https://developer.airly.eu/register adresine gidin.",
"title": "Airly"
}
}

View File

@ -15,7 +15,7 @@
"longitude": "\u7d93\u5ea6",
"name": "\u540d\u7a31"
},
"description": "\u6b32\u8a2d\u5b9a Airly \u7a7a\u6c23\u54c1\u8cea\u6574\u5408\u3002\u8acb\u81f3 https://developer.airly.eu/register \u7522\u751f API \u91d1\u9470",
"description": "\u8acb\u81f3 https://developer.airly.eu/register \u4ee5\u7522\u751f API \u91d1\u9470",
"title": "Airly"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Longitud",
"radius": "Radi de l'estaci\u00f3 (milles; opcional)"
},
"description": "Configura la integraci\u00f3 de qualitat d'aire AirNow. Per generar la clau API, v\u00e9s a https://docs.airnowapi.org/account/request/",
"description": "Per generar la clau API, v\u00e9s a https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "L\u00e4ngengrad",
"radius": "Stationsradius (Meilen; optional)"
},
"description": "Richte die AirNow-Luftqualit\u00e4tsintegration ein. Um den API-Schl\u00fcssel zu generieren, besuche https://docs.airnowapi.org/account/request/.",
"description": "Um den API-Schl\u00fcssel zu generieren, besuche https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Longitude",
"radius": "Station Radius (miles; optional)"
},
"description": "Set up AirNow air quality integration. To generate API key go to https://docs.airnowapi.org/account/request/",
"description": "To generate API key go to https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Pikkuskraad",
"radius": "Jaama raadius (miilid; valikuline)"
},
"description": "Seadista AirNow \u00f5hukvaliteedi sidumine. API-v\u00f5tme loomiseks mine aadressile https://docs.airnowapi.org/account/request/",
"description": "API-v\u00f5tme loomiseks mine aadressile https://docs.airnowapi.org/account/request/",
"title": ""
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Longitude",
"radius": "Rayon d'action de la station (en miles, facultatif)"
},
"description": "Configurez l'int\u00e9gration de la qualit\u00e9 de l'air AirNow. Pour g\u00e9n\u00e9rer la cl\u00e9 API, acc\u00e9dez \u00e0 https://docs.airnowapi.org/account/request/",
"description": "Pour g\u00e9n\u00e9rer une cl\u00e9 d'API, rendez-vous sur https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Hossz\u00fas\u00e1g",
"radius": "\u00c1llom\u00e1s sugara (m\u00e9rf\u00f6ld; opcion\u00e1lis)"
},
"description": "\u00c1ll\u00edtsa be az AirNow leveg\u0151min\u0151s\u00e9gi integr\u00e1ci\u00f3t. Az API-kulcs el\u0151\u00e1ll\u00edt\u00e1s\u00e1hoz keresse fel a https://docs.airnowapi.org/account/request/ oldalt.",
"description": "Az API-kulcs l\u00e9trehoz\u00e1s\u00e1hoz keresse fel a https://docs.airnowapi.org/account/request/ webhelyet",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Bujur",
"radius": "Radius Stasiun (mil; opsional)"
},
"description": "Siapkan integrasi kualitas udara AirNow. Untuk membuat kunci API buka https://docs.airnowapi.org/account/request/",
"description": "Untuk membuat kunci API buka https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Logitudine",
"radius": "Raggio stazione (miglia; opzionale)"
},
"description": "Configura l'integrazione per la qualit\u00e0 dell'aria AirNow. Per generare la chiave API, vai su https://docs.airnowapi.org/account/request/",
"description": "Per generare la chiave API vai su https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Lengtegraad",
"radius": "Stationsradius (mijl; optioneel)"
},
"description": "AirNow luchtkwaliteit integratie opzetten. Om een API sleutel te genereren ga naar https://docs.airnowapi.org/account/request/",
"description": "Om een API sleutel te genereren ga naar https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Lengdegrad",
"radius": "Stasjonsradius (miles; valgfritt)"
},
"description": "Konfigurer integrering av luftkvalitet i AirNow. For \u00e5 generere en API-n\u00f8kkel, g\u00e5r du til https://docs.airnowapi.org/account/request/",
"description": "For \u00e5 generere API-n\u00f8kkel, g\u00e5 til https://docs.airnowapi.org/account/request/",
"title": ""
}
}

View File

@ -17,7 +17,7 @@
"longitude": "D\u0142ugo\u015b\u0107 geograficzna",
"radius": "Promie\u0144 od stacji (w milach; opcjonalnie)"
},
"description": "Konfiguracja integracji jako\u015bci powietrza AirNow. Aby wygenerowa\u0107 klucz API, przejd\u017a do https://docs.airnowapi.org/account/request/",
"description": "Aby wygenerowa\u0107 klucz API, przejd\u017a do https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Longitude",
"radius": "Raio da Esta\u00e7\u00e3o (milhas; opcional)"
},
"description": "Configure a integra\u00e7\u00e3o da qualidade do ar AirNow. Para gerar a chave de API, acesse https://docs.airnowapi.org/account/request/",
"description": "Para gerar a chave de API, acesse https://docs.airnowapi.org/account/request/",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "\u0414\u043e\u043b\u0433\u043e\u0442\u0430",
"radius": "\u0420\u0430\u0434\u0438\u0443\u0441 \u0441\u0442\u0430\u043d\u0446\u0438\u0438 (\u0432 \u043c\u0438\u043b\u044f\u0445; \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e)"
},
"description": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043f\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0443 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u043e\u0437\u0434\u0443\u0445\u0430 AirNow. \u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u044e\u0447 API, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 https://docs.airnowapi.org/account/request/.",
"description": "\u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u044e\u0447 API, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 https://docs.airnowapi.org/account/request/.",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "Boylam",
"radius": "\u0130stasyon Yar\u0131\u00e7ap\u0131 (mil; iste\u011fe ba\u011fl\u0131)"
},
"description": "AirNow hava kalitesi entegrasyonunu ayarlay\u0131n. API anahtar\u0131 olu\u015fturmak i\u00e7in https://docs.airnowapi.org/account/request/ adresine gidin.",
"description": "API anahtar\u0131 olu\u015fturmak i\u00e7in https://docs.airnowapi.org/account/request/ adresine gidin.",
"title": "AirNow"
}
}

View File

@ -17,7 +17,7 @@
"longitude": "\u7d93\u5ea6",
"radius": "\u89c0\u6e2c\u7ad9\u534a\u5f91\uff08\u82f1\u91cc\uff1b\u9078\u9805\uff09"
},
"description": "\u6b32\u8a2d\u5b9a AirNow \u7a7a\u6c23\u54c1\u8cea\u6574\u5408\u3002\u8acb\u81f3 https://docs.airnowapi.org/account/request/ \u7522\u751f API \u91d1\u9470",
"description": "\u8acb\u81f3 https://docs.airnowapi.org/account/request/ \u4ee5\u7522\u751f API \u91d1\u9470",
"title": "AirNow"
}
}

View File

@ -11,14 +11,8 @@ from homeassistant.components.climate.const import (
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_OFF,
SUPPORT_FAN_MODE,
SUPPORT_TARGET_TEMPERATURE,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
@ -29,24 +23,23 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
AT_TO_HA_STATE = {
"Heat": HVAC_MODE_HEAT,
"Cool": HVAC_MODE_COOL,
"AutoHeat": HVAC_MODE_AUTO, # airtouch reports either autoheat or autocool
"AutoCool": HVAC_MODE_AUTO,
"Auto": HVAC_MODE_AUTO,
"Dry": HVAC_MODE_DRY,
"Fan": HVAC_MODE_FAN_ONLY,
"Heat": HVACMode.HEAT,
"Cool": HVACMode.COOL,
"AutoHeat": HVACMode.AUTO, # airtouch reports either autoheat or autocool
"AutoCool": HVACMode.AUTO,
"Auto": HVACMode.AUTO,
"Dry": HVACMode.DRY,
"Fan": HVACMode.FAN_ONLY,
}
HA_STATE_TO_AT = {
HVAC_MODE_HEAT: "Heat",
HVAC_MODE_COOL: "Cool",
HVAC_MODE_AUTO: "Auto",
HVAC_MODE_DRY: "Dry",
HVAC_MODE_FAN_ONLY: "Fan",
HVAC_MODE_OFF: "Off",
HVACMode.HEAT: "Heat",
HVACMode.COOL: "Cool",
HVACMode.AUTO: "Auto",
HVACMode.DRY: "Dry",
HVACMode.FAN_ONLY: "Fan",
HVACMode.OFF: "Off",
}
AT_TO_HA_FAN_SPEED = {
@ -59,7 +52,7 @@ AT_TO_HA_FAN_SPEED = {
"Turbo": "turbo",
}
AT_GROUP_MODES = [HVAC_MODE_OFF, HVAC_MODE_FAN_ONLY]
AT_GROUP_MODES = [HVACMode.OFF, HVACMode.FAN_ONLY]
HA_FAN_SPEED_TO_AT = {value: key for key, value in AT_TO_HA_FAN_SPEED.items()}
@ -90,7 +83,9 @@ async def async_setup_entry(
class AirtouchAC(CoordinatorEntity, ClimateEntity):
"""Representation of an AirTouch 4 ac."""
_attr_supported_features = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
)
_attr_temperature_unit = TEMP_CELSIUS
def __init__(self, coordinator, ac_number, info):
@ -147,7 +142,7 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
"""Return hvac target hvac state."""
is_off = self._unit.PowerState == "Off"
if is_off:
return HVAC_MODE_OFF
return HVACMode.OFF
return AT_TO_HA_STATE[self._airtouch.acs[self._ac_number].AcMode]
@ -156,7 +151,7 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
"""Return the list of available operation modes."""
airtouch_modes = self._airtouch.GetSupportedCoolingModesForAc(self._ac_number)
modes = [AT_TO_HA_STATE[mode] for mode in airtouch_modes]
modes.append(HVAC_MODE_OFF)
modes.append(HVACMode.OFF)
return modes
async def async_set_hvac_mode(self, hvac_mode):
@ -164,7 +159,7 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
if hvac_mode not in HA_STATE_TO_AT:
raise ValueError(f"Unsupported HVAC mode: {hvac_mode}")
if hvac_mode == HVAC_MODE_OFF:
if hvac_mode == HVACMode.OFF:
return await self.async_turn_off()
await self._airtouch.SetCoolingModeForAc(
self._ac_number, HA_STATE_TO_AT[hvac_mode]
@ -204,7 +199,7 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
class AirtouchGroup(CoordinatorEntity, ClimateEntity):
"""Representation of an AirTouch 4 group."""
_attr_supported_features = SUPPORT_TARGET_TEMPERATURE
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
_attr_temperature_unit = TEMP_CELSIUS
_attr_hvac_modes = AT_GROUP_MODES
@ -267,18 +262,18 @@ class AirtouchGroup(CoordinatorEntity, ClimateEntity):
# there are other power states that aren't 'on' but still count as on (eg. 'Turbo')
is_off = self._unit.PowerState == "Off"
if is_off:
return HVAC_MODE_OFF
return HVACMode.OFF
return HVAC_MODE_FAN_ONLY
return HVACMode.FAN_ONLY
async def async_set_hvac_mode(self, hvac_mode):
"""Set new operation mode."""
if hvac_mode not in HA_STATE_TO_AT:
raise ValueError(f"Unsupported HVAC mode: {hvac_mode}")
if hvac_mode == HVAC_MODE_OFF:
if hvac_mode == HVACMode.OFF:
return await self.async_turn_off()
if self.hvac_mode == HVAC_MODE_OFF:
if self.hvac_mode == HVACMode.OFF:
await self.async_turn_on()
self._unit = self._airtouch.GetGroups()[self._group_number]
_LOGGER.debug(

View File

@ -10,7 +10,7 @@
},
"airvisual__pollutant_level": {
"good": "Bon",
"hazardous": "Hasardeux",
"hazardous": "Dangereux",
"moderate": "Mod\u00e9r\u00e9",
"unhealthy": "Malsain",
"unhealthy_sensitive": "Malsain pour les groupes sensibles",

View File

@ -1,23 +1,30 @@
"""The Airzone integration."""
from __future__ import annotations
import logging
from typing import Any
from aioairzone.common import ConnectionOptions
from aioairzone.const import (
AZD_ID,
AZD_MAC,
AZD_NAME,
AZD_SYSTEM,
AZD_THERMOSTAT_FW,
AZD_THERMOSTAT_MODEL,
AZD_WEBSERVER,
AZD_ZONES,
DEFAULT_SYSTEM_ID,
)
from aioairzone.localapi import AirzoneLocalApi
from aioairzone.localapi import AirzoneLocalApi, ConnectionOptions
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PORT, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import (
aiohttp_client,
device_registry as dr,
entity_registry as er,
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@ -26,10 +33,20 @@ from .coordinator import AirzoneUpdateCoordinator
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.CLIMATE, Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
class AirzoneEntity(CoordinatorEntity[AirzoneUpdateCoordinator]):
"""Define an Airzone entity."""
def get_airzone_value(self, key) -> Any:
"""Return Airzone entity value by key."""
raise NotImplementedError()
class AirzoneZoneEntity(AirzoneEntity):
"""Define an Airzone Zone entity."""
def __init__(
self,
coordinator: AirzoneUpdateCoordinator,
@ -47,12 +64,15 @@ class AirzoneEntity(CoordinatorEntity[AirzoneUpdateCoordinator]):
self._attr_device_info: DeviceInfo = {
"identifiers": {(DOMAIN, f"{entry.entry_id}_{system_zone_id}")},
"manufacturer": MANUFACTURER,
"model": self.get_zone_value(AZD_THERMOSTAT_MODEL),
"model": self.get_airzone_value(AZD_THERMOSTAT_MODEL),
"name": f"Airzone [{system_zone_id}] {zone_data[AZD_NAME]}",
"sw_version": self.get_zone_value(AZD_THERMOSTAT_FW),
"sw_version": self.get_airzone_value(AZD_THERMOSTAT_FW),
}
self._attr_unique_id = (
entry.entry_id if entry.unique_id is None else entry.unique_id
)
def get_zone_value(self, key):
def get_airzone_value(self, key) -> Any:
"""Return zone value by key."""
value = None
if self.system_zone_id in self.coordinator.data[AZD_ZONES]:
@ -62,17 +82,58 @@ class AirzoneEntity(CoordinatorEntity[AirzoneUpdateCoordinator]):
return value
async def _async_migrate_unique_ids(
hass: HomeAssistant,
entry: ConfigEntry,
coordinator: AirzoneUpdateCoordinator,
) -> None:
"""Migrate entities when the mac address gets discovered."""
@callback
def _async_migrator(entity_entry: er.RegistryEntry) -> dict[str, Any] | None:
updates = None
unique_id = entry.unique_id
entry_id = entry.entry_id
entity_unique_id = entity_entry.unique_id
if entity_unique_id.startswith(entry_id):
new_unique_id = f"{unique_id}{entity_unique_id[len(entry_id):]}"
_LOGGER.info(
"Migrating unique_id from [%s] to [%s]",
entity_unique_id,
new_unique_id,
)
updates = {"new_unique_id": new_unique_id}
return updates
if (
entry.unique_id is None
and AZD_WEBSERVER in coordinator.data
and AZD_MAC in coordinator.data[AZD_WEBSERVER]
and (mac := coordinator.data[AZD_WEBSERVER][AZD_MAC]) is not None
):
updates: dict[str, Any] = {
"unique_id": dr.format_mac(mac),
}
hass.config_entries.async_update_entry(entry, **updates)
await er.async_migrate_entries(hass, entry.entry_id, _async_migrator)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Airzone from a config entry."""
options = ConnectionOptions(
entry.data[CONF_HOST],
entry.data[CONF_PORT],
entry.data.get(CONF_ID, DEFAULT_SYSTEM_ID),
)
airzone = AirzoneLocalApi(aiohttp_client.async_get_clientsession(hass), options)
coordinator = AirzoneUpdateCoordinator(hass, airzone)
await coordinator.async_config_entry_first_refresh()
await _async_migrate_unique_ids(hass, entry, coordinator)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator

View File

@ -7,6 +7,7 @@ from typing import Any, Final
from aioairzone.const import (
AZD_AIR_DEMAND,
AZD_BATTERY_LOW,
AZD_ERRORS,
AZD_FLOOR_DEMAND,
AZD_NAME,
@ -15,8 +16,7 @@ from aioairzone.const import (
)
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_PROBLEM,
DEVICE_CLASS_RUNNING,
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
@ -25,7 +25,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneEntity
from . import AirzoneEntity, AirzoneZoneEntity
from .const import DOMAIN
from .coordinator import AirzoneUpdateCoordinator
@ -37,14 +37,19 @@ class AirzoneBinarySensorEntityDescription(BinarySensorEntityDescription):
attributes: dict[str, str] | None = None
BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]] = (
ZONE_BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]] = (
AirzoneBinarySensorEntityDescription(
device_class=DEVICE_CLASS_RUNNING,
device_class=BinarySensorDeviceClass.RUNNING,
key=AZD_AIR_DEMAND,
name="Air Demand",
),
AirzoneBinarySensorEntityDescription(
device_class=DEVICE_CLASS_RUNNING,
device_class=BinarySensorDeviceClass.BATTERY,
key=AZD_BATTERY_LOW,
name="Battery Low",
),
AirzoneBinarySensorEntityDescription(
device_class=BinarySensorDeviceClass.RUNNING,
key=AZD_FLOOR_DEMAND,
name="Floor Demand",
),
@ -52,7 +57,7 @@ BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]] = (
attributes={
"errors": AZD_ERRORS,
},
device_class=DEVICE_CLASS_PROBLEM,
device_class=BinarySensorDeviceClass.PROBLEM,
entity_category=EntityCategory.DIAGNOSTIC,
key=AZD_PROBLEMS,
name="Problem",
@ -66,12 +71,12 @@ async def async_setup_entry(
"""Add Airzone binary sensors from a config_entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]
binary_sensors = []
binary_sensors: list[AirzoneBinarySensor] = []
for system_zone_id, zone_data in coordinator.data[AZD_ZONES].items():
for description in BINARY_SENSOR_TYPES:
for description in ZONE_BINARY_SENSOR_TYPES:
if description.key in zone_data:
binary_sensors.append(
AirzoneBinarySensor(
AirzoneZoneBinarySensor(
coordinator,
description,
entry,
@ -84,7 +89,28 @@ async def async_setup_entry(
class AirzoneBinarySensor(AirzoneEntity, BinarySensorEntity):
"""Define an Airzone sensor."""
"""Define an Airzone binary sensor."""
entity_description: AirzoneBinarySensorEntityDescription
@property
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return state attributes."""
if not self.entity_description.attributes:
return None
return {
key: self.get_airzone_value(val)
for key, val in self.entity_description.attributes.items()
}
@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self.get_airzone_value(self.entity_description.key)
class AirzoneZoneBinarySensor(AirzoneZoneEntity, AirzoneBinarySensor):
"""Define an Airzone Zone binary sensor."""
def __init__(
self,
@ -96,19 +122,9 @@ class AirzoneBinarySensor(AirzoneEntity, BinarySensorEntity):
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, system_zone_id, zone_data)
self._attr_name = f"{zone_data[AZD_NAME]} {description.name}"
self._attr_unique_id = f"{entry.entry_id}_{system_zone_id}_{description.key}"
self.attributes = description.attributes
self._attr_unique_id = (
f"{self._attr_unique_id}_{system_zone_id}_{description.key}"
)
self.entity_description = description
@property
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return state attributes."""
if not self.attributes:
return None
return {key: self.get_zone_value(val) for key, val in self.attributes.items()}
@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self.get_zone_value(self.entity_description.key)

View File

@ -2,7 +2,7 @@
from __future__ import annotations
import logging
from typing import Final
from typing import Any, Final
from aioairzone.common import OperationMode
from aioairzone.const import (
@ -26,23 +26,12 @@ from aioairzone.const import (
AZD_ZONES,
)
from aioairzone.exceptions import AirzoneError
from aiohttp.client_exceptions import ClientConnectorError
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
CURRENT_HVAC_COOL,
CURRENT_HVAC_DRY,
CURRENT_HVAC_FAN,
CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE,
CURRENT_HVAC_OFF,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
SUPPORT_TARGET_TEMPERATURE,
ClimateEntityFeature,
HVACAction,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE
@ -50,35 +39,35 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneEntity
from . import AirzoneZoneEntity
from .const import API_TEMPERATURE_STEP, DOMAIN, TEMP_UNIT_LIB_TO_HASS
from .coordinator import AirzoneUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
HVAC_ACTION_LIB_TO_HASS: Final[dict[OperationMode, str]] = {
OperationMode.STOP: CURRENT_HVAC_OFF,
OperationMode.COOLING: CURRENT_HVAC_COOL,
OperationMode.HEATING: CURRENT_HVAC_HEAT,
OperationMode.FAN: CURRENT_HVAC_FAN,
OperationMode.DRY: CURRENT_HVAC_DRY,
HVAC_ACTION_LIB_TO_HASS: Final[dict[OperationMode, HVACAction]] = {
OperationMode.STOP: HVACAction.OFF,
OperationMode.COOLING: HVACAction.COOLING,
OperationMode.HEATING: HVACAction.HEATING,
OperationMode.FAN: HVACAction.FAN,
OperationMode.DRY: HVACAction.DRYING,
}
HVAC_MODE_LIB_TO_HASS: Final[dict[OperationMode, str]] = {
OperationMode.STOP: HVAC_MODE_OFF,
OperationMode.COOLING: HVAC_MODE_COOL,
OperationMode.HEATING: HVAC_MODE_HEAT,
OperationMode.FAN: HVAC_MODE_FAN_ONLY,
OperationMode.DRY: HVAC_MODE_DRY,
OperationMode.AUTO: HVAC_MODE_HEAT_COOL,
HVAC_MODE_LIB_TO_HASS: Final[dict[OperationMode, HVACMode]] = {
OperationMode.STOP: HVACMode.OFF,
OperationMode.COOLING: HVACMode.COOL,
OperationMode.HEATING: HVACMode.HEAT,
OperationMode.FAN: HVACMode.FAN_ONLY,
OperationMode.DRY: HVACMode.DRY,
OperationMode.AUTO: HVACMode.HEAT_COOL,
}
HVAC_MODE_HASS_TO_LIB: Final[dict[str, OperationMode]] = {
HVAC_MODE_OFF: OperationMode.STOP,
HVAC_MODE_COOL: OperationMode.COOLING,
HVAC_MODE_HEAT: OperationMode.HEATING,
HVAC_MODE_FAN_ONLY: OperationMode.FAN,
HVAC_MODE_DRY: OperationMode.DRY,
HVAC_MODE_HEAT_COOL: OperationMode.AUTO,
HVAC_MODE_HASS_TO_LIB: Final[dict[HVACMode, OperationMode]] = {
HVACMode.OFF: OperationMode.STOP,
HVACMode.COOL: OperationMode.COOLING,
HVACMode.HEAT: OperationMode.HEATING,
HVACMode.FAN_ONLY: OperationMode.FAN,
HVACMode.DRY: OperationMode.DRY,
HVACMode.HEAT_COOL: OperationMode.AUTO,
}
@ -98,7 +87,7 @@ async def async_setup_entry(
)
class AirzoneClimate(AirzoneEntity, ClimateEntity):
class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
"""Define an Airzone sensor."""
def __init__(
@ -110,61 +99,74 @@ class AirzoneClimate(AirzoneEntity, ClimateEntity):
) -> None:
"""Initialize Airzone climate entity."""
super().__init__(coordinator, entry, system_zone_id, zone_data)
self._attr_name = f"{zone_data[AZD_NAME]}"
self._attr_unique_id = f"{entry.entry_id}_{system_zone_id}"
self._attr_supported_features = SUPPORT_TARGET_TEMPERATURE
self._attr_unique_id = f"{self._attr_unique_id}_{system_zone_id}"
self._attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
self._attr_target_temperature_step = API_TEMPERATURE_STEP
self._attr_max_temp = self.get_zone_value(AZD_TEMP_MAX)
self._attr_min_temp = self.get_zone_value(AZD_TEMP_MIN)
self._attr_max_temp = self.get_airzone_value(AZD_TEMP_MAX)
self._attr_min_temp = self.get_airzone_value(AZD_TEMP_MIN)
self._attr_temperature_unit = TEMP_UNIT_LIB_TO_HASS[
self.get_zone_value(AZD_TEMP_UNIT)
self.get_airzone_value(AZD_TEMP_UNIT)
]
self._attr_hvac_modes = [
HVAC_MODE_LIB_TO_HASS[mode] for mode in self.get_zone_value(AZD_MODES)
HVAC_MODE_LIB_TO_HASS[mode] for mode in self.get_airzone_value(AZD_MODES)
]
self._async_update_attrs()
async def _async_update_hvac_params(self, params) -> None:
async def _async_update_hvac_params(self, params: dict[str, Any]) -> None:
"""Send HVAC parameters to API."""
_params = {
API_SYSTEM_ID: self.system_id,
API_ZONE_ID: self.zone_id,
**params,
}
_LOGGER.debug("update_hvac_params=%s", _params)
try:
await self.coordinator.airzone.put_hvac(params)
except (AirzoneError, ClientConnectorError) as error:
await self.coordinator.airzone.put_hvac(_params)
except AirzoneError as error:
raise HomeAssistantError(
f"Failed to set zone {self.name}: {error}"
) from error
else:
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
"""Set hvac mode."""
async def async_turn_on(self) -> None:
"""Turn the entity on."""
params = {
API_SYSTEM_ID: self.system_id,
API_ZONE_ID: self.zone_id,
API_ON: 1,
}
if hvac_mode == HVAC_MODE_OFF:
await self._async_update_hvac_params(params)
async def async_turn_off(self) -> None:
"""Turn the entity off."""
params = {
API_ON: 0,
}
await self._async_update_hvac_params(params)
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
params = {}
if hvac_mode == HVACMode.OFF:
params[API_ON] = 0
else:
mode = HVAC_MODE_HASS_TO_LIB[hvac_mode]
if mode != self.get_zone_value(AZD_MODE):
if self.get_zone_value(AZD_MASTER):
if mode != self.get_airzone_value(AZD_MODE):
if self.get_airzone_value(AZD_MASTER):
params[API_MODE] = mode
else:
raise HomeAssistantError(
f"Mode can't be changed on slave zone {self.name}"
)
params[API_ON] = 1
_LOGGER.debug("Set hvac_mode=%s params=%s", hvac_mode, params)
await self._async_update_hvac_params(params)
async def async_set_temperature(self, **kwargs) -> None:
"""Set new target temperature."""
temp = kwargs.get(ATTR_TEMPERATURE)
params = {
API_SYSTEM_ID: self.system_id,
API_ZONE_ID: self.zone_id,
API_SET_POINT: temp,
API_SET_POINT: kwargs.get(ATTR_TEMPERATURE),
}
_LOGGER.debug("Set temp=%s params=%s", temp, params)
await self._async_update_hvac_params(params)
@callback
@ -176,16 +178,16 @@ class AirzoneClimate(AirzoneEntity, ClimateEntity):
@callback
def _async_update_attrs(self) -> None:
"""Update climate attributes."""
self._attr_current_temperature = self.get_zone_value(AZD_TEMP)
self._attr_current_humidity = self.get_zone_value(AZD_HUMIDITY)
if self.get_zone_value(AZD_ON):
mode = self.get_zone_value(AZD_MODE)
self._attr_current_temperature = self.get_airzone_value(AZD_TEMP)
self._attr_current_humidity = self.get_airzone_value(AZD_HUMIDITY)
if self.get_airzone_value(AZD_ON):
mode = self.get_airzone_value(AZD_MODE)
self._attr_hvac_mode = HVAC_MODE_LIB_TO_HASS[mode]
if self.get_zone_value(AZD_DEMAND):
if self.get_airzone_value(AZD_DEMAND):
self._attr_hvac_action = HVAC_ACTION_LIB_TO_HASS[mode]
else:
self._attr_hvac_action = CURRENT_HVAC_IDLE
self._attr_hvac_action = HVACAction.IDLE
else:
self._attr_hvac_action = CURRENT_HVAC_OFF
self._attr_hvac_mode = HVAC_MODE_OFF
self._attr_target_temperature = self.get_zone_value(AZD_TEMP_SET)
self._attr_hvac_action = HVACAction.OFF
self._attr_hvac_mode = HVACMode.OFF
self._attr_target_temperature = self.get_airzone_value(AZD_TEMP_SET)

View File

@ -3,18 +3,30 @@ from __future__ import annotations
from typing import Any
from aioairzone.common import ConnectionOptions
from aioairzone.exceptions import InvalidHost
from aioairzone.localapi import AirzoneLocalApi
from aiohttp.client_exceptions import ClientConnectorError
from aioairzone.const import DEFAULT_PORT, DEFAULT_SYSTEM_ID
from aioairzone.exceptions import AirzoneError, InvalidSystem
from aioairzone.localapi import AirzoneLocalApi, ConnectionOptions
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PORT
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.device_registry import format_mac
from .const import DEFAULT_LOCAL_API_PORT, DOMAIN
from .const import DOMAIN
CONFIG_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
}
)
SYSTEM_ID_SCHEMA = CONFIG_SCHEMA.extend(
{
vol.Required(CONF_ID, default=1): int,
}
)
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
@ -24,39 +36,43 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
data_schema = CONFIG_SCHEMA
errors = {}
if user_input is not None:
self._async_abort_entries_match(
{
CONF_HOST: user_input[CONF_HOST],
CONF_PORT: user_input[CONF_PORT],
}
)
self._async_abort_entries_match(user_input)
airzone = AirzoneLocalApi(
aiohttp_client.async_get_clientsession(self.hass),
ConnectionOptions(
user_input[CONF_HOST],
user_input[CONF_PORT],
user_input.get(CONF_ID, DEFAULT_SYSTEM_ID),
),
)
try:
await airzone.validate_airzone()
except (ClientConnectorError, InvalidHost):
mac = await airzone.validate()
except InvalidSystem:
data_schema = SYSTEM_ID_SCHEMA
errors[CONF_ID] = "invalid_system_id"
except AirzoneError:
errors["base"] = "cannot_connect"
else:
if mac:
await self.async_set_unique_id(format_mac(mac))
self._abort_if_unique_id_configured(
updates={
CONF_HOST: user_input[CONF_HOST],
CONF_PORT: user_input[CONF_PORT],
}
)
title = f"Airzone {user_input[CONF_HOST]}:{user_input[CONF_PORT]}"
return self.async_create_entry(title=title, data=user_input)
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_LOCAL_API_PORT): int,
}
),
data_schema=data_schema,
errors=errors,
)

View File

@ -11,7 +11,6 @@ MANUFACTURER: Final = "Airzone"
AIOAIRZONE_DEVICE_TIMEOUT_SEC: Final = 10
API_TEMPERATURE_STEP: Final = 0.5
DEFAULT_LOCAL_API_PORT: Final = 3000
TEMP_UNIT_LIB_TO_HASS: Final[dict[TemperatureUnit, str]] = {
TemperatureUnit.CELSIUS: TEMP_CELSIUS,

View File

@ -4,8 +4,8 @@ from __future__ import annotations
from datetime import timedelta
import logging
from aioairzone.exceptions import AirzoneError
from aioairzone.localapi import AirzoneLocalApi
from aiohttp.client_exceptions import ClientConnectorError
import async_timeout
from homeassistant.core import HomeAssistant
@ -36,7 +36,7 @@ class AirzoneUpdateCoordinator(DataUpdateCoordinator):
"""Update data via library."""
async with async_timeout.timeout(AIOAIRZONE_DEVICE_TIMEOUT_SEC):
try:
await self.airzone.update_airzone()
except ClientConnectorError as error:
await self.airzone.update()
except AirzoneError as error:
raise UpdateFailed(error) from error
return self.airzone.data()

View File

@ -0,0 +1,29 @@
"""Support for the Airzone diagnostics."""
from __future__ import annotations
from typing import Any
from aioairzone.const import AZD_MAC
from homeassistant.components.diagnostics.util import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from .const import DOMAIN
from .coordinator import AirzoneUpdateCoordinator
TO_REDACT = [
AZD_MAC,
]
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator: AirzoneUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
return {
"info": async_redact_data(config_entry.data, TO_REDACT),
"data": async_redact_data(coordinator.data, TO_REDACT),
}

View File

@ -3,7 +3,7 @@
"name": "Airzone",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airzone",
"requirements": ["aioairzone==0.3.3"],
"requirements": ["aioairzone==0.4.2"],
"codeowners": ["@Noltari"],
"iot_class": "local_polling",
"loggers": ["aioairzone"]

View File

@ -6,38 +6,34 @@ from typing import Any, Final
from aioairzone.const import AZD_HUMIDITY, AZD_NAME, AZD_TEMP, AZD_TEMP_UNIT, AZD_ZONES
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
TEMP_CELSIUS,
)
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneEntity
from . import AirzoneEntity, AirzoneZoneEntity
from .const import DOMAIN, TEMP_UNIT_LIB_TO_HASS
from .coordinator import AirzoneUpdateCoordinator
SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
SensorEntityDescription(
device_class=DEVICE_CLASS_TEMPERATURE,
device_class=SensorDeviceClass.TEMPERATURE,
key=AZD_TEMP,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
state_class=STATE_CLASS_MEASUREMENT,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
device_class=DEVICE_CLASS_HUMIDITY,
device_class=SensorDeviceClass.HUMIDITY,
key=AZD_HUMIDITY,
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
state_class=STATE_CLASS_MEASUREMENT,
state_class=SensorStateClass.MEASUREMENT,
),
)
@ -48,12 +44,12 @@ async def async_setup_entry(
"""Add Airzone sensors from a config_entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]
sensors = []
sensors: list[AirzoneSensor] = []
for system_zone_id, zone_data in coordinator.data[AZD_ZONES].items():
for description in SENSOR_TYPES:
for description in ZONE_SENSOR_TYPES:
if description.key in zone_data:
sensors.append(
AirzoneSensor(
AirzoneZoneSensor(
coordinator,
description,
entry,
@ -68,6 +64,15 @@ async def async_setup_entry(
class AirzoneSensor(AirzoneEntity, SensorEntity):
"""Define an Airzone sensor."""
@property
def native_value(self):
"""Return the state."""
return self.get_airzone_value(self.entity_description.key)
class AirzoneZoneSensor(AirzoneZoneEntity, AirzoneSensor):
"""Define an Airzone Zone sensor."""
def __init__(
self,
coordinator: AirzoneUpdateCoordinator,
@ -78,16 +83,14 @@ class AirzoneSensor(AirzoneEntity, SensorEntity):
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, system_zone_id, zone_data)
self._attr_name = f"{zone_data[AZD_NAME]} {description.name}"
self._attr_unique_id = f"{entry.entry_id}_{system_zone_id}_{description.key}"
self._attr_unique_id = (
f"{self._attr_unique_id}_{system_zone_id}_{description.key}"
)
self.entity_description = description
if description.key == AZD_TEMP:
self._attr_native_unit_of_measurement = TEMP_UNIT_LIB_TO_HASS.get(
self.get_zone_value(AZD_TEMP_UNIT)
self.get_airzone_value(AZD_TEMP_UNIT)
)
@property
def native_value(self):
"""Return the state."""
return self.get_zone_value(self.entity_description.key)

View File

@ -4,7 +4,8 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_system_id": "Invalid Airzone System ID"
},
"step": {
"user": {

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