mirror of
https://github.com/home-assistant/core.git
synced 2025-07-31 09:17:10 +00:00
2022.9.0 (#77968)
This commit is contained in:
commit
910f27f3a2
62
.coveragerc
62
.coveragerc
@ -56,7 +56,9 @@ omit =
|
||||
homeassistant/components/ambient_station/sensor.py
|
||||
homeassistant/components/amcrest/*
|
||||
homeassistant/components/ampio/*
|
||||
homeassistant/components/android_ip_webcam/*
|
||||
homeassistant/components/android_ip_webcam/binary_sensor.py
|
||||
homeassistant/components/android_ip_webcam/sensor.py
|
||||
homeassistant/components/android_ip_webcam/switch.py
|
||||
homeassistant/components/androidtv/diagnostics.py
|
||||
homeassistant/components/anel_pwrctrl/switch.py
|
||||
homeassistant/components/anthemav/media_player.py
|
||||
@ -137,6 +139,7 @@ omit =
|
||||
homeassistant/components/bosch_shc/switch.py
|
||||
homeassistant/components/braviatv/__init__.py
|
||||
homeassistant/components/braviatv/const.py
|
||||
homeassistant/components/braviatv/coordinator.py
|
||||
homeassistant/components/braviatv/entity.py
|
||||
homeassistant/components/braviatv/media_player.py
|
||||
homeassistant/components/braviatv/remote.py
|
||||
@ -257,6 +260,11 @@ omit =
|
||||
homeassistant/components/econet/const.py
|
||||
homeassistant/components/econet/sensor.py
|
||||
homeassistant/components/econet/water_heater.py
|
||||
homeassistant/components/ecowitt/__init__.py
|
||||
homeassistant/components/ecowitt/binary_sensor.py
|
||||
homeassistant/components/ecowitt/diagnostics.py
|
||||
homeassistant/components/ecowitt/entity.py
|
||||
homeassistant/components/ecowitt/sensor.py
|
||||
homeassistant/components/ecovacs/*
|
||||
homeassistant/components/edl21/*
|
||||
homeassistant/components/eddystone_temperature/sensor.py
|
||||
@ -309,8 +317,12 @@ omit =
|
||||
homeassistant/components/epson/media_player.py
|
||||
homeassistant/components/epsonworkforce/sensor.py
|
||||
homeassistant/components/eq3btsmart/climate.py
|
||||
homeassistant/components/escea/climate.py
|
||||
homeassistant/components/escea/discovery.py
|
||||
homeassistant/components/escea/__init__.py
|
||||
homeassistant/components/esphome/__init__.py
|
||||
homeassistant/components/esphome/binary_sensor.py
|
||||
homeassistant/components/esphome/bluetooth.py
|
||||
homeassistant/components/esphome/button.py
|
||||
homeassistant/components/esphome/camera.py
|
||||
homeassistant/components/esphome/climate.py
|
||||
@ -386,6 +398,8 @@ omit =
|
||||
homeassistant/components/flick_electric/sensor.py
|
||||
homeassistant/components/flock/notify.py
|
||||
homeassistant/components/flume/__init__.py
|
||||
homeassistant/components/flume/coordinator.py
|
||||
homeassistant/components/flume/entity.py
|
||||
homeassistant/components/flume/sensor.py
|
||||
homeassistant/components/flunearyou/__init__.py
|
||||
homeassistant/components/flunearyou/repairs.py
|
||||
@ -432,10 +446,10 @@ omit =
|
||||
homeassistant/components/gitlab_ci/sensor.py
|
||||
homeassistant/components/gitter/sensor.py
|
||||
homeassistant/components/glances/__init__.py
|
||||
homeassistant/components/glances/const.py
|
||||
homeassistant/components/glances/sensor.py
|
||||
homeassistant/components/goalfeed/*
|
||||
homeassistant/components/goodwe/__init__.py
|
||||
homeassistant/components/goodwe/button.py
|
||||
homeassistant/components/goodwe/const.py
|
||||
homeassistant/components/goodwe/number.py
|
||||
homeassistant/components/goodwe/select.py
|
||||
@ -470,7 +484,6 @@ omit =
|
||||
homeassistant/components/harmony/remote.py
|
||||
homeassistant/components/harmony/util.py
|
||||
homeassistant/components/haveibeenpwned/sensor.py
|
||||
homeassistant/components/hdmi_cec/*
|
||||
homeassistant/components/heatmiser/climate.py
|
||||
homeassistant/components/hikvision/binary_sensor.py
|
||||
homeassistant/components/hikvisioncam/switch.py
|
||||
@ -574,7 +587,7 @@ omit =
|
||||
homeassistant/components/iqvia/sensor.py
|
||||
homeassistant/components/irish_rail_transport/sensor.py
|
||||
homeassistant/components/iss/__init__.py
|
||||
homeassistant/components/iss/binary_sensor.py
|
||||
homeassistant/components/iss/sensor.py
|
||||
homeassistant/components/isy994/__init__.py
|
||||
homeassistant/components/isy994/binary_sensor.py
|
||||
homeassistant/components/isy994/climate.py
|
||||
@ -600,6 +613,10 @@ omit =
|
||||
homeassistant/components/juicenet/number.py
|
||||
homeassistant/components/juicenet/sensor.py
|
||||
homeassistant/components/juicenet/switch.py
|
||||
homeassistant/components/justnimbus/const.py
|
||||
homeassistant/components/justnimbus/coordinator.py
|
||||
homeassistant/components/justnimbus/entity.py
|
||||
homeassistant/components/justnimbus/sensor.py
|
||||
homeassistant/components/kaiterra/*
|
||||
homeassistant/components/kankun/switch.py
|
||||
homeassistant/components/keba/*
|
||||
@ -630,7 +647,12 @@ omit =
|
||||
homeassistant/components/kostal_plenticore/switch.py
|
||||
homeassistant/components/kwb/sensor.py
|
||||
homeassistant/components/lacrosse/sensor.py
|
||||
homeassistant/components/lametric/*
|
||||
homeassistant/components/lametric/__init__.py
|
||||
homeassistant/components/lametric/button.py
|
||||
homeassistant/components/lametric/coordinator.py
|
||||
homeassistant/components/lametric/entity.py
|
||||
homeassistant/components/lametric/notify.py
|
||||
homeassistant/components/lametric/number.py
|
||||
homeassistant/components/lannouncer/notify.py
|
||||
homeassistant/components/lastfm/sensor.py
|
||||
homeassistant/components/launch_library/__init__.py
|
||||
@ -641,6 +663,9 @@ omit =
|
||||
homeassistant/components/lcn/helpers.py
|
||||
homeassistant/components/lcn/scene.py
|
||||
homeassistant/components/lcn/services.py
|
||||
homeassistant/components/led_ble/__init__.py
|
||||
homeassistant/components/led_ble/light.py
|
||||
homeassistant/components/led_ble/util.py
|
||||
homeassistant/components/lg_netcast/media_player.py
|
||||
homeassistant/components/lg_soundbar/media_player.py
|
||||
homeassistant/components/life360/__init__.py
|
||||
@ -700,6 +725,10 @@ omit =
|
||||
homeassistant/components/melcloud/const.py
|
||||
homeassistant/components/melcloud/sensor.py
|
||||
homeassistant/components/melcloud/water_heater.py
|
||||
homeassistant/components/melnor/__init__.py
|
||||
homeassistant/components/melnor/const.py
|
||||
homeassistant/components/melnor/models.py
|
||||
homeassistant/components/melnor/switch.py
|
||||
homeassistant/components/message_bird/notify.py
|
||||
homeassistant/components/met/weather.py
|
||||
homeassistant/components/met_eireann/__init__.py
|
||||
@ -851,6 +880,8 @@ omit =
|
||||
homeassistant/components/open_meteo/weather.py
|
||||
homeassistant/components/opencv/*
|
||||
homeassistant/components/openevse/sensor.py
|
||||
homeassistant/components/openexchangerates/__init__.py
|
||||
homeassistant/components/openexchangerates/coordinator.py
|
||||
homeassistant/components/openexchangerates/sensor.py
|
||||
homeassistant/components/opengarage/__init__.py
|
||||
homeassistant/components/opengarage/binary_sensor.py
|
||||
@ -976,9 +1007,11 @@ omit =
|
||||
homeassistant/components/raincloud/*
|
||||
homeassistant/components/rainmachine/__init__.py
|
||||
homeassistant/components/rainmachine/binary_sensor.py
|
||||
homeassistant/components/rainmachine/button.py
|
||||
homeassistant/components/rainmachine/model.py
|
||||
homeassistant/components/rainmachine/sensor.py
|
||||
homeassistant/components/rainmachine/switch.py
|
||||
homeassistant/components/rainmachine/update.py
|
||||
homeassistant/components/rainmachine/util.py
|
||||
homeassistant/components/raspyrfm/*
|
||||
homeassistant/components/recollect_waste/__init__.py
|
||||
@ -1183,6 +1216,7 @@ omit =
|
||||
homeassistant/components/switchbot/const.py
|
||||
homeassistant/components/switchbot/entity.py
|
||||
homeassistant/components/switchbot/cover.py
|
||||
homeassistant/components/switchbot/light.py
|
||||
homeassistant/components/switchbot/sensor.py
|
||||
homeassistant/components/switchbot/coordinator.py
|
||||
homeassistant/components/switchmate/switch.py
|
||||
@ -1210,6 +1244,7 @@ omit =
|
||||
homeassistant/components/system_bridge/binary_sensor.py
|
||||
homeassistant/components/system_bridge/const.py
|
||||
homeassistant/components/system_bridge/coordinator.py
|
||||
homeassistant/components/system_bridge/media_source.py
|
||||
homeassistant/components/system_bridge/sensor.py
|
||||
homeassistant/components/systemmonitor/sensor.py
|
||||
homeassistant/components/tado/__init__.py
|
||||
@ -1408,7 +1443,14 @@ omit =
|
||||
homeassistant/components/volumio/__init__.py
|
||||
homeassistant/components/volumio/browse_media.py
|
||||
homeassistant/components/volumio/media_player.py
|
||||
homeassistant/components/volvooncall/*
|
||||
homeassistant/components/volvooncall/__init__.py
|
||||
homeassistant/components/volvooncall/binary_sensor.py
|
||||
homeassistant/components/volvooncall/const.py
|
||||
homeassistant/components/volvooncall/device_tracker.py
|
||||
homeassistant/components/volvooncall/errors.py
|
||||
homeassistant/components/volvooncall/lock.py
|
||||
homeassistant/components/volvooncall/sensor.py
|
||||
homeassistant/components/volvooncall/switch.py
|
||||
homeassistant/components/vulcan/__init__.py
|
||||
homeassistant/components/vulcan/calendar.py
|
||||
homeassistant/components/vulcan/fetch_data.py
|
||||
@ -1464,12 +1506,17 @@ omit =
|
||||
homeassistant/components/xiaomi_miio/light.py
|
||||
homeassistant/components/xiaomi_miio/number.py
|
||||
homeassistant/components/xiaomi_miio/remote.py
|
||||
homeassistant/components/xiaomi_miio/select.py
|
||||
homeassistant/components/xiaomi_miio/sensor.py
|
||||
homeassistant/components/xiaomi_miio/switch.py
|
||||
homeassistant/components/xiaomi_tv/media_player.py
|
||||
homeassistant/components/xmpp/notify.py
|
||||
homeassistant/components/xs1/*
|
||||
homeassistant/components/yalexs_ble/__init__.py
|
||||
homeassistant/components/yalexs_ble/binary_sensor.py
|
||||
homeassistant/components/yalexs_ble/entity.py
|
||||
homeassistant/components/yalexs_ble/lock.py
|
||||
homeassistant/components/yalexs_ble/sensor.py
|
||||
homeassistant/components/yalexs_ble/util.py
|
||||
homeassistant/components/yale_smart_alarm/__init__.py
|
||||
homeassistant/components/yale_smart_alarm/alarm_control_panel.py
|
||||
homeassistant/components/yale_smart_alarm/binary_sensor.py
|
||||
@ -1519,7 +1566,6 @@ omit =
|
||||
homeassistant/components/zha/core/registries.py
|
||||
homeassistant/components/zha/entity.py
|
||||
homeassistant/components/zha/light.py
|
||||
homeassistant/components/zha/sensor.py
|
||||
homeassistant/components/zhong_hong/climate.py
|
||||
homeassistant/components/ziggo_mediabox_xl/media_player.py
|
||||
homeassistant/components/zoneminder/*
|
||||
|
38
.github/workflows/ci.yaml
vendored
38
.github/workflows/ci.yaml
vendored
@ -22,7 +22,7 @@ on:
|
||||
env:
|
||||
CACHE_VERSION: 1
|
||||
PIP_CACHE_VERSION: 1
|
||||
HA_SHORT_VERSION: 2022.8
|
||||
HA_SHORT_VERSION: 2022.9
|
||||
DEFAULT_PYTHON: 3.9
|
||||
PRE_COMMIT_CACHE: ~/.cache/pre-commit
|
||||
PIP_CACHE: /tmp/pip-cache
|
||||
@ -172,7 +172,7 @@ jobs:
|
||||
cache: "pip"
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -185,7 +185,7 @@ jobs:
|
||||
pip install "$(cat requirements_test.txt | grep pre-commit)"
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -211,7 +211,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -222,7 +222,7 @@ jobs:
|
||||
exit 1
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -260,7 +260,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -271,7 +271,7 @@ jobs:
|
||||
exit 1
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -312,7 +312,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -323,7 +323,7 @@ jobs:
|
||||
exit 1
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -353,7 +353,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -364,7 +364,7 @@ jobs:
|
||||
exit 1
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
||||
@ -480,7 +480,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.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -488,7 +488,7 @@ jobs:
|
||||
needs.info.outputs.python_cache_key }}
|
||||
- name: Restore pip wheel cache
|
||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: ${{ env.PIP_CACHE }}
|
||||
key: >-
|
||||
@ -538,7 +538,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -570,7 +570,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -603,7 +603,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -647,7 +647,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -695,7 +695,7 @@ jobs:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -749,7 +749,7 @@ jobs:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.0.5
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||
|
@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.37.2
|
||||
rev: v2.37.3
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py39-plus]
|
||||
@ -32,7 +32,7 @@ repos:
|
||||
- flake8-docstrings==1.6.0
|
||||
- pydocstyle==6.1.1
|
||||
- flake8-comprehensions==3.10.0
|
||||
- flake8-noqa==1.2.5
|
||||
- flake8-noqa==1.2.8
|
||||
- mccabe==0.6.1
|
||||
files: ^(homeassistant|script|tests)/.+\.py$
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
|
@ -1,4 +1,5 @@
|
||||
*.md
|
||||
.strict-typing
|
||||
azure-*.yml
|
||||
docs/source/_templates/*
|
||||
homeassistant/components/*/translations/*.json
|
||||
|
@ -56,9 +56,12 @@ homeassistant.components.ambee.*
|
||||
homeassistant.components.ambient_station.*
|
||||
homeassistant.components.amcrest.*
|
||||
homeassistant.components.ampio.*
|
||||
homeassistant.components.anthemav.*
|
||||
homeassistant.components.aseko_pool_live.*
|
||||
homeassistant.components.asuswrt.*
|
||||
homeassistant.components.auth.*
|
||||
homeassistant.components.automation.*
|
||||
homeassistant.components.awair.*
|
||||
homeassistant.components.backup.*
|
||||
homeassistant.components.baf.*
|
||||
homeassistant.components.binary_sensor.*
|
||||
@ -95,6 +98,8 @@ homeassistant.components.energy.*
|
||||
homeassistant.components.evil_genius_labs.*
|
||||
homeassistant.components.fan.*
|
||||
homeassistant.components.fastdotcom.*
|
||||
homeassistant.components.feedreader.*
|
||||
homeassistant.components.file_upload.*
|
||||
homeassistant.components.filesize.*
|
||||
homeassistant.components.fitbit.*
|
||||
homeassistant.components.flunearyou.*
|
||||
@ -105,6 +110,7 @@ homeassistant.components.fritzbox_callmonitor.*
|
||||
homeassistant.components.fronius.*
|
||||
homeassistant.components.frontend.*
|
||||
homeassistant.components.fritz.*
|
||||
homeassistant.components.fully_kiosk.*
|
||||
homeassistant.components.geo_location.*
|
||||
homeassistant.components.geocaching.*
|
||||
homeassistant.components.gios.*
|
||||
@ -149,6 +155,7 @@ homeassistant.components.jewish_calendar.*
|
||||
homeassistant.components.kaleidescape.*
|
||||
homeassistant.components.knx.*
|
||||
homeassistant.components.kraken.*
|
||||
homeassistant.components.lacrosse_view.*
|
||||
homeassistant.components.lametric.*
|
||||
homeassistant.components.laundrify.*
|
||||
homeassistant.components.lcn.*
|
||||
@ -164,6 +171,7 @@ homeassistant.components.mailbox.*
|
||||
homeassistant.components.media_player.*
|
||||
homeassistant.components.media_source.*
|
||||
homeassistant.components.metoffice.*
|
||||
homeassistant.components.mikrotik.*
|
||||
homeassistant.components.mjpeg.*
|
||||
homeassistant.components.modbus.*
|
||||
homeassistant.components.modem_callerid.*
|
||||
@ -185,6 +193,7 @@ homeassistant.components.nut.*
|
||||
homeassistant.components.oncue.*
|
||||
homeassistant.components.onewire.*
|
||||
homeassistant.components.open_meteo.*
|
||||
homeassistant.components.openexchangerates.*
|
||||
homeassistant.components.openuv.*
|
||||
homeassistant.components.peco.*
|
||||
homeassistant.components.overkiz.*
|
||||
@ -192,6 +201,7 @@ homeassistant.components.persistent_notification.*
|
||||
homeassistant.components.pi_hole.*
|
||||
homeassistant.components.powerwall.*
|
||||
homeassistant.components.proximity.*
|
||||
homeassistant.components.prusalink.*
|
||||
homeassistant.components.pvoutput.*
|
||||
homeassistant.components.pure_energie.*
|
||||
homeassistant.components.qnap_qsw.*
|
||||
@ -210,6 +220,7 @@ homeassistant.components.rpi_power.*
|
||||
homeassistant.components.rtsp_to_webrtc.*
|
||||
homeassistant.components.samsungtv.*
|
||||
homeassistant.components.scene.*
|
||||
homeassistant.components.schedule.*
|
||||
homeassistant.components.select.*
|
||||
homeassistant.components.sensibo.*
|
||||
homeassistant.components.sensor.*
|
||||
|
64
CODEOWNERS
64
CODEOWNERS
@ -72,6 +72,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/amcrest/ @flacjacket
|
||||
/homeassistant/components/analytics/ @home-assistant/core @ludeeus
|
||||
/tests/components/analytics/ @home-assistant/core @ludeeus
|
||||
/homeassistant/components/android_ip_webcam/ @engrbm87
|
||||
/tests/components/android_ip_webcam/ @engrbm87
|
||||
/homeassistant/components/androidtv/ @JeffLIrion @ollo69
|
||||
/tests/components/androidtv/ @JeffLIrion @ollo69
|
||||
/homeassistant/components/anthemav/ @hyralex
|
||||
@ -135,6 +137,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/blebox/ @bbx-a @riokuu
|
||||
/homeassistant/components/blink/ @fronzbot
|
||||
/tests/components/blink/ @fronzbot
|
||||
/homeassistant/components/bluemaestro/ @bdraco
|
||||
/tests/components/bluemaestro/ @bdraco
|
||||
/homeassistant/components/blueprint/ @home-assistant/core
|
||||
/tests/components/blueprint/ @home-assistant/core
|
||||
/homeassistant/components/bluesound/ @thrawnarn
|
||||
@ -157,6 +161,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/bsblan/ @liudger
|
||||
/tests/components/bsblan/ @liudger
|
||||
/homeassistant/components/bt_smarthub/ @jxwolstenholme
|
||||
/homeassistant/components/bthome/ @Ernst79
|
||||
/tests/components/bthome/ @Ernst79
|
||||
/homeassistant/components/buienradar/ @mjj4791 @ties @Robbie1221
|
||||
/tests/components/buienradar/ @mjj4791 @ties @Robbie1221
|
||||
/homeassistant/components/button/ @home-assistant/core
|
||||
@ -271,7 +277,9 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/ecobee/ @marthoc
|
||||
/homeassistant/components/econet/ @vangorra @w1ll1am23
|
||||
/tests/components/econet/ @vangorra @w1ll1am23
|
||||
/homeassistant/components/ecovacs/ @OverloadUT
|
||||
/homeassistant/components/ecovacs/ @OverloadUT @mib1185
|
||||
/homeassistant/components/ecowitt/ @pvizeli
|
||||
/tests/components/ecowitt/ @pvizeli
|
||||
/homeassistant/components/edl21/ @mtdcr
|
||||
/homeassistant/components/efergy/ @tkdrob
|
||||
/tests/components/efergy/ @tkdrob
|
||||
@ -309,6 +317,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/epson/ @pszafer
|
||||
/homeassistant/components/epsonworkforce/ @ThaStealth
|
||||
/homeassistant/components/eq3btsmart/ @rytilahti
|
||||
/homeassistant/components/escea/ @lazdavila
|
||||
/tests/components/escea/ @lazdavila
|
||||
/homeassistant/components/esphome/ @OttoWinter @jesserockz
|
||||
/tests/components/esphome/ @OttoWinter @jesserockz
|
||||
/homeassistant/components/evil_genius_labs/ @balloob
|
||||
@ -325,6 +335,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/fibaro/ @rappenze
|
||||
/homeassistant/components/file/ @fabaff
|
||||
/tests/components/file/ @fabaff
|
||||
/homeassistant/components/file_upload/ @home-assistant/core
|
||||
/tests/components/file_upload/ @home-assistant/core
|
||||
/homeassistant/components/filesize/ @gjohansson-ST
|
||||
/tests/components/filesize/ @gjohansson-ST
|
||||
/homeassistant/components/filter/ @dgomes
|
||||
@ -343,8 +355,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/flipr/ @cnico
|
||||
/homeassistant/components/flo/ @dmulcahey
|
||||
/tests/components/flo/ @dmulcahey
|
||||
/homeassistant/components/flume/ @ChrisMandich @bdraco
|
||||
/tests/components/flume/ @ChrisMandich @bdraco
|
||||
/homeassistant/components/flume/ @ChrisMandich @bdraco @jeeftor
|
||||
/tests/components/flume/ @ChrisMandich @bdraco @jeeftor
|
||||
/homeassistant/components/flunearyou/ @bachya
|
||||
/tests/components/flunearyou/ @bachya
|
||||
/homeassistant/components/flux_led/ @icemanch @bdraco
|
||||
@ -371,6 +383,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/frontend/ @home-assistant/frontend
|
||||
/tests/components/frontend/ @home-assistant/frontend
|
||||
/homeassistant/components/frontier_silicon/ @wlcrs
|
||||
/homeassistant/components/fully_kiosk/ @cgarwood
|
||||
/tests/components/fully_kiosk/ @cgarwood
|
||||
/homeassistant/components/garages_amsterdam/ @klaasnicolaas
|
||||
/tests/components/garages_amsterdam/ @klaasnicolaas
|
||||
/homeassistant/components/gdacs/ @exxamalte
|
||||
@ -434,6 +448,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/harmony/ @ehendrix23 @bramkragten @bdraco @mkeesey @Aohzan
|
||||
/homeassistant/components/hassio/ @home-assistant/supervisor
|
||||
/tests/components/hassio/ @home-assistant/supervisor
|
||||
/homeassistant/components/hdmi_cec/ @inytar
|
||||
/tests/components/hdmi_cec/ @inytar
|
||||
/homeassistant/components/heatmiser/ @andylockran
|
||||
/homeassistant/components/heos/ @andrewsayre
|
||||
/tests/components/heos/ @andrewsayre
|
||||
@ -457,6 +473,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/homeassistant/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_alerts/ @home-assistant/core
|
||||
/tests/components/homeassistant_alerts/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_sky_connect/ @home-assistant/core
|
||||
/tests/components/homeassistant_sky_connect/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_yellow/ @home-assistant/core
|
||||
/tests/components/homeassistant_yellow/ @home-assistant/core
|
||||
/homeassistant/components/homekit/ @bdraco
|
||||
@ -551,6 +569,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/jewish_calendar/ @tsvi
|
||||
/homeassistant/components/juicenet/ @jesserockz
|
||||
/tests/components/juicenet/ @jesserockz
|
||||
/homeassistant/components/justnimbus/ @kvanzuijlen
|
||||
/tests/components/justnimbus/ @kvanzuijlen
|
||||
/homeassistant/components/kaiterra/ @Michsior14
|
||||
/homeassistant/components/kaleidescape/ @SteveEasley
|
||||
/tests/components/kaleidescape/ @SteveEasley
|
||||
@ -573,13 +593,20 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/kraken/ @eifinger
|
||||
/homeassistant/components/kulersky/ @emlove
|
||||
/tests/components/kulersky/ @emlove
|
||||
/homeassistant/components/lacrosse_view/ @IceBotYT
|
||||
/tests/components/lacrosse_view/ @IceBotYT
|
||||
/homeassistant/components/lametric/ @robbiet480 @frenck
|
||||
/tests/components/lametric/ @robbiet480 @frenck
|
||||
/homeassistant/components/landisgyr_heat_meter/ @vpathuis
|
||||
/tests/components/landisgyr_heat_meter/ @vpathuis
|
||||
/homeassistant/components/launch_library/ @ludeeus @DurgNomis-drol
|
||||
/tests/components/launch_library/ @ludeeus @DurgNomis-drol
|
||||
/homeassistant/components/laundrify/ @xLarry
|
||||
/tests/components/laundrify/ @xLarry
|
||||
/homeassistant/components/lcn/ @alengwenus
|
||||
/tests/components/lcn/ @alengwenus
|
||||
/homeassistant/components/led_ble/ @bdraco
|
||||
/tests/components/led_ble/ @bdraco
|
||||
/homeassistant/components/lg_netcast/ @Drafteed
|
||||
/homeassistant/components/life360/ @pnbruckner
|
||||
/tests/components/life360/ @pnbruckner
|
||||
@ -590,8 +617,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/linux_battery/ @fabaff
|
||||
/homeassistant/components/litejet/ @joncar
|
||||
/tests/components/litejet/ @joncar
|
||||
/homeassistant/components/litterrobot/ @natekspencer
|
||||
/tests/components/litterrobot/ @natekspencer
|
||||
/homeassistant/components/litterrobot/ @natekspencer @tkdrob
|
||||
/tests/components/litterrobot/ @natekspencer @tkdrob
|
||||
/homeassistant/components/local_ip/ @issacg
|
||||
/tests/components/local_ip/ @issacg
|
||||
/homeassistant/components/lock/ @home-assistant/core
|
||||
@ -611,8 +638,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/luftdaten/ @fabaff @frenck
|
||||
/homeassistant/components/lupusec/ @majuss
|
||||
/homeassistant/components/lutron/ @JonGilmore
|
||||
/homeassistant/components/lutron_caseta/ @swails @bdraco
|
||||
/tests/components/lutron_caseta/ @swails @bdraco
|
||||
/homeassistant/components/lutron_caseta/ @swails @bdraco @danaues
|
||||
/tests/components/lutron_caseta/ @swails @bdraco @danaues
|
||||
/homeassistant/components/lyric/ @timmo001
|
||||
/tests/components/lyric/ @timmo001
|
||||
/homeassistant/components/mastodon/ @fabaff
|
||||
@ -630,6 +657,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/melcloud/ @vilppuvuorinen
|
||||
/homeassistant/components/melissa/ @kennedyshead
|
||||
/tests/components/melissa/ @kennedyshead
|
||||
/homeassistant/components/melnor/ @vanstinator
|
||||
/tests/components/melnor/ @vanstinator
|
||||
/homeassistant/components/met/ @danielhiversen @thimic
|
||||
/tests/components/met/ @danielhiversen @thimic
|
||||
/homeassistant/components/met_eireann/ @DylanGore
|
||||
@ -764,6 +793,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/open_meteo/ @frenck
|
||||
/homeassistant/components/openerz/ @misialq
|
||||
/tests/components/openerz/ @misialq
|
||||
/homeassistant/components/openexchangerates/ @MartinHjelmare
|
||||
/tests/components/openexchangerates/ @MartinHjelmare
|
||||
/homeassistant/components/opengarage/ @danielhiversen
|
||||
/tests/components/opengarage/ @danielhiversen
|
||||
/homeassistant/components/openhome/ @bazwilliams
|
||||
@ -821,17 +852,23 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/prosegur/ @dgomes
|
||||
/tests/components/prosegur/ @dgomes
|
||||
/homeassistant/components/proxmoxve/ @jhollowe @Corbeno
|
||||
/homeassistant/components/prusalink/ @balloob
|
||||
/tests/components/prusalink/ @balloob
|
||||
/homeassistant/components/ps4/ @ktnrg45
|
||||
/tests/components/ps4/ @ktnrg45
|
||||
/homeassistant/components/pure_energie/ @klaasnicolaas
|
||||
/tests/components/pure_energie/ @klaasnicolaas
|
||||
/homeassistant/components/push/ @dgomes
|
||||
/tests/components/push/ @dgomes
|
||||
/homeassistant/components/pushover/ @engrbm87
|
||||
/tests/components/pushover/ @engrbm87
|
||||
/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/qingping/ @bdraco
|
||||
/tests/components/qingping/ @bdraco
|
||||
/homeassistant/components/qld_bushfire/ @exxamalte
|
||||
/tests/components/qld_bushfire/ @exxamalte
|
||||
/homeassistant/components/qnap_qsw/ @Noltari
|
||||
@ -909,6 +946,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/samsungtv/ @chemelli74 @epenet
|
||||
/homeassistant/components/scene/ @home-assistant/core
|
||||
/tests/components/scene/ @home-assistant/core
|
||||
/homeassistant/components/schedule/ @home-assistant/core
|
||||
/tests/components/schedule/ @home-assistant/core
|
||||
/homeassistant/components/schluter/ @prairieapps
|
||||
/homeassistant/components/scrape/ @fabaff
|
||||
/tests/components/scrape/ @fabaff
|
||||
@ -930,6 +969,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/sensibo/ @andrey-git @gjohansson-ST
|
||||
/homeassistant/components/sensor/ @home-assistant/core
|
||||
/tests/components/sensor/ @home-assistant/core
|
||||
/homeassistant/components/sensorpro/ @bdraco
|
||||
/tests/components/sensorpro/ @bdraco
|
||||
/homeassistant/components/sensorpush/ @bdraco
|
||||
/tests/components/sensorpush/ @bdraco
|
||||
/homeassistant/components/sentry/ @dcramer @frenck
|
||||
@ -1078,6 +1119,10 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/tesla_wall_connector/ @einarhauks
|
||||
/tests/components/tesla_wall_connector/ @einarhauks
|
||||
/homeassistant/components/tfiac/ @fredrike @mellado
|
||||
/homeassistant/components/thermobeacon/ @bdraco
|
||||
/tests/components/thermobeacon/ @bdraco
|
||||
/homeassistant/components/thermopro/ @bdraco
|
||||
/tests/components/thermopro/ @bdraco
|
||||
/homeassistant/components/thethingsnetwork/ @fabaff
|
||||
/homeassistant/components/threshold/ @fabaff
|
||||
/tests/components/threshold/ @fabaff
|
||||
@ -1173,7 +1218,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/vlc_telnet/ @rodripf @MartinHjelmare
|
||||
/homeassistant/components/volumio/ @OnFreund
|
||||
/tests/components/volumio/ @OnFreund
|
||||
/homeassistant/components/volvooncall/ @molobrakos @decompil3d
|
||||
/homeassistant/components/volvooncall/ @molobrakos
|
||||
/tests/components/volvooncall/ @molobrakos
|
||||
/homeassistant/components/vulcan/ @Antoni-Czaplicki
|
||||
/tests/components/vulcan/ @Antoni-Czaplicki
|
||||
/homeassistant/components/wake_on_lan/ @ntilley905
|
||||
@ -1234,6 +1280,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/xmpp/ @fabaff @flowolf
|
||||
/homeassistant/components/yale_smart_alarm/ @gjohansson-ST
|
||||
/tests/components/yale_smart_alarm/ @gjohansson-ST
|
||||
/homeassistant/components/yalexs_ble/ @bdraco
|
||||
/tests/components/yalexs_ble/ @bdraco
|
||||
/homeassistant/components/yamaha_musiccast/ @vigonotion @micha91
|
||||
/tests/components/yamaha_musiccast/ @vigonotion @micha91
|
||||
/homeassistant/components/yandex_transport/ @rishatik92 @devbis
|
||||
|
@ -12,7 +12,7 @@ demo <https://home-assistant.io/demo/>`__, `installation instructions <https://h
|
||||
Featured integrations
|
||||
---------------------
|
||||
|
||||
|screenshot-components|
|
||||
|screenshot-integrations|
|
||||
|
||||
The system is built using a modular approach so support for other devices or actions can be implemented easily. See also the `section on architecture <https://developers.home-assistant.io/docs/architecture_index/>`__ and the `section on creating your own
|
||||
components <https://developers.home-assistant.io/docs/creating_component_index/>`__.
|
||||
@ -24,5 +24,5 @@ of a component, check the `Home Assistant help section <https://home-assistant.i
|
||||
:target: https://discord.gg/c5DvZ4e
|
||||
.. |screenshot-states| image:: https://raw.githubusercontent.com/home-assistant/core/master/docs/screenshots.png
|
||||
:target: https://home-assistant.io/demo/
|
||||
.. |screenshot-components| image:: https://raw.githubusercontent.com/home-assistant/core/dev/docs/screenshot-components.png
|
||||
.. |screenshot-integrations| image:: https://raw.githubusercontent.com/home-assistant/core/dev/docs/screenshot-integrations.png
|
||||
:target: https://home-assistant.io/integrations/
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 118 KiB |
BIN
docs/screenshot-integrations.png
Normal file
BIN
docs/screenshot-integrations.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
@ -24,7 +24,13 @@ from .const import (
|
||||
SIGNAL_BOOTSTRAP_INTEGRATONS,
|
||||
)
|
||||
from .exceptions import HomeAssistantError
|
||||
from .helpers import area_registry, device_registry, entity_registry, recorder
|
||||
from .helpers import (
|
||||
area_registry,
|
||||
device_registry,
|
||||
entity_registry,
|
||||
issue_registry,
|
||||
recorder,
|
||||
)
|
||||
from .helpers.dispatcher import async_dispatcher_send
|
||||
from .helpers.typing import ConfigType
|
||||
from .setup import (
|
||||
@ -521,9 +527,10 @@ async def _async_set_up_integrations(
|
||||
|
||||
# Load the registries and cache the result of platform.uname().processor
|
||||
await asyncio.gather(
|
||||
area_registry.async_load(hass),
|
||||
device_registry.async_load(hass),
|
||||
entity_registry.async_load(hass),
|
||||
area_registry.async_load(hass),
|
||||
issue_registry.async_load(hass),
|
||||
hass.async_add_executor_job(_cache_uname_processor),
|
||||
)
|
||||
|
||||
|
@ -248,6 +248,7 @@ class AbodeEntity(entity.Entity):
|
||||
"""Representation of an Abode entity."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, data: AbodeSystem) -> None:
|
||||
"""Initialize Abode entity."""
|
||||
@ -283,7 +284,6 @@ class AbodeDevice(AbodeEntity):
|
||||
"""Initialize Abode device."""
|
||||
super().__init__(data)
|
||||
self._device = device
|
||||
self._attr_name = device.name
|
||||
self._attr_unique_id = device.device_uuid
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
|
@ -30,12 +30,10 @@ async def async_setup_entry(
|
||||
CONST.TYPE_OPENING,
|
||||
]
|
||||
|
||||
entities = []
|
||||
|
||||
for device in data.abode.get_devices(generic_type=device_types):
|
||||
entities.append(AbodeBinarySensor(data, device))
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AbodeBinarySensor(data, device)
|
||||
for device in data.abode.get_devices(generic_type=device_types)
|
||||
)
|
||||
|
||||
|
||||
class AbodeBinarySensor(AbodeDevice, BinarySensorEntity):
|
||||
|
@ -28,12 +28,11 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up Abode camera devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
entities = []
|
||||
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_CAMERA):
|
||||
entities.append(AbodeCamera(data, device, TIMELINE.CAPTURE_IMAGE))
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AbodeCamera(data, device, TIMELINE.CAPTURE_IMAGE)
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_CAMERA)
|
||||
)
|
||||
|
||||
|
||||
class AbodeCamera(AbodeDevice, Camera):
|
||||
@ -75,7 +74,9 @@ class AbodeCamera(AbodeDevice, Camera):
|
||||
"""Attempt to download the most recent capture."""
|
||||
if self._device.image_url:
|
||||
try:
|
||||
self._response = requests.get(self._device.image_url, stream=True)
|
||||
self._response = requests.get(
|
||||
self._device.image_url, stream=True, timeout=10
|
||||
)
|
||||
|
||||
self._response.raise_for_status()
|
||||
except requests.HTTPError as err:
|
||||
|
@ -19,12 +19,10 @@ async def async_setup_entry(
|
||||
"""Set up Abode cover devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
||||
entities = []
|
||||
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_COVER):
|
||||
entities.append(AbodeCover(data, device))
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AbodeCover(data, device)
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_COVER)
|
||||
)
|
||||
|
||||
|
||||
class AbodeCover(AbodeDevice, CoverEntity):
|
||||
|
@ -32,12 +32,10 @@ async def async_setup_entry(
|
||||
"""Set up Abode light devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
||||
entities = []
|
||||
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_LIGHT):
|
||||
entities.append(AbodeLight(data, device))
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AbodeLight(data, device)
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_LIGHT)
|
||||
)
|
||||
|
||||
|
||||
class AbodeLight(AbodeDevice, LightEntity):
|
||||
|
@ -19,12 +19,10 @@ async def async_setup_entry(
|
||||
"""Set up Abode lock devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
||||
entities = []
|
||||
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_LOCK):
|
||||
entities.append(AbodeLock(data, device))
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AbodeLock(data, device)
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_LOCK)
|
||||
)
|
||||
|
||||
|
||||
class AbodeLock(AbodeDevice, LockEntity):
|
||||
|
@ -42,19 +42,12 @@ async def async_setup_entry(
|
||||
"""Set up Abode sensor devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
||||
entities = []
|
||||
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_SENSOR):
|
||||
conditions = device.get_value(CONST.STATUSES_KEY)
|
||||
entities.extend(
|
||||
[
|
||||
AbodeSensor(data, device, description)
|
||||
for description in SENSOR_TYPES
|
||||
if description.key in conditions
|
||||
]
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AbodeSensor(data, device, description)
|
||||
for description in SENSOR_TYPES
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_SENSOR)
|
||||
if description.key in device.get_value(CONST.STATUSES_KEY)
|
||||
)
|
||||
|
||||
|
||||
class AbodeSensor(AbodeDevice, SensorEntity):
|
||||
@ -71,7 +64,6 @@ class AbodeSensor(AbodeDevice, SensorEntity):
|
||||
"""Initialize a sensor for an Abode device."""
|
||||
super().__init__(data, device)
|
||||
self.entity_description = description
|
||||
self._attr_name = f"{device.name} {description.name}"
|
||||
self._attr_unique_id = f"{device.device_uuid}-{description.key}"
|
||||
if description.key == CONST.TEMP_STATUS_KEY:
|
||||
self._attr_native_unit_of_measurement = device.temp_unit
|
||||
|
@ -25,14 +25,16 @@ async def async_setup_entry(
|
||||
"""Set up Abode switch devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
||||
entities: list[SwitchEntity] = []
|
||||
entities: list[SwitchEntity] = [
|
||||
AbodeSwitch(data, device)
|
||||
for device_type in DEVICE_TYPES
|
||||
for device in data.abode.get_devices(generic_type=device_type)
|
||||
]
|
||||
|
||||
for device_type in DEVICE_TYPES:
|
||||
for device in data.abode.get_devices(generic_type=device_type):
|
||||
entities.append(AbodeSwitch(data, device))
|
||||
|
||||
for automation in data.abode.get_automations():
|
||||
entities.append(AbodeAutomationSwitch(data, automation))
|
||||
entities.extend(
|
||||
AbodeAutomationSwitch(data, automation)
|
||||
for automation in data.abode.get_automations()
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
"error": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"invalid_auth": "Autenticaci\u00f3n no v\u00e1lida",
|
||||
"invalid_mfa_code": "C\u00f3digo MFA inv\u00e1lido"
|
||||
"invalid_mfa_code": "C\u00f3digo MFA no v\u00e1lido"
|
||||
},
|
||||
"step": {
|
||||
"mfa": {
|
||||
@ -21,14 +21,14 @@
|
||||
"password": "Contrase\u00f1a",
|
||||
"username": "Correo electr\u00f3nico"
|
||||
},
|
||||
"title": "Rellene su informaci\u00f3n de inicio de sesi\u00f3n de Abode"
|
||||
"title": "Completa tu informaci\u00f3n de inicio de sesi\u00f3n de Abode"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"password": "Contrase\u00f1a",
|
||||
"username": "Correo electr\u00f3nico"
|
||||
},
|
||||
"title": "Rellene la informaci\u00f3n de acceso Abode"
|
||||
"title": "Completa tu informaci\u00f3n de inicio de sesi\u00f3n de Abode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,27 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"reauth_successful": "\u00c5terautentisering lyckades",
|
||||
"single_instance_allowed": "Endast en enda konfiguration av Abode \u00e4r till\u00e5ten."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"invalid_auth": "Ogiltig autentisering",
|
||||
"invalid_mfa_code": "Ogiltig MFA-kod"
|
||||
},
|
||||
"step": {
|
||||
"mfa": {
|
||||
"data": {
|
||||
"mfa_code": "MFA-kod (6 siffror)"
|
||||
},
|
||||
"title": "Ange din MFA-kod f\u00f6r Abode"
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"data": {
|
||||
"password": "L\u00f6senord",
|
||||
"username": "E-postadress"
|
||||
}
|
||||
},
|
||||
"title": "Fyll i din Abode-inloggningsinformation"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
|
@ -81,7 +81,6 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Initialize."""
|
||||
self.location_key = location_key
|
||||
self.forecast = forecast
|
||||
self.is_metric = hass.config.units.is_metric
|
||||
self.accuweather = AccuWeather(api_key, session, location_key=location_key)
|
||||
self.device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
@ -116,7 +115,9 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
async with timeout(10):
|
||||
current = await self.accuweather.async_get_current_conditions()
|
||||
forecast = (
|
||||
await self.accuweather.async_get_forecast(metric=self.is_metric)
|
||||
await self.accuweather.async_get_forecast(
|
||||
metric=self.hass.config.units.is_metric
|
||||
)
|
||||
if self.forecast
|
||||
else {}
|
||||
)
|
||||
|
@ -23,7 +23,13 @@ from homeassistant.components.weather import (
|
||||
API_IMPERIAL: Final = "Imperial"
|
||||
API_METRIC: Final = "Metric"
|
||||
ATTRIBUTION: Final = "Data provided by AccuWeather"
|
||||
ATTR_CATEGORY: Final = "Category"
|
||||
ATTR_DIRECTION: Final = "Direction"
|
||||
ATTR_ENGLISH: Final = "English"
|
||||
ATTR_LEVEL: Final = "level"
|
||||
ATTR_FORECAST: Final = "forecast"
|
||||
ATTR_SPEED: Final = "Speed"
|
||||
ATTR_VALUE: Final = "Value"
|
||||
CONF_FORECAST: Final = "forecast"
|
||||
DOMAIN: Final = "accuweather"
|
||||
MANUFACTURER: Final = "AccuWeather, Inc."
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "accuweather",
|
||||
"name": "AccuWeather",
|
||||
"documentation": "https://www.home-assistant.io/integrations/accuweather/",
|
||||
"requirements": ["accuweather==0.3.0"],
|
||||
"requirements": ["accuweather==0.4.0"],
|
||||
"codeowners": ["@bieniu"],
|
||||
"config_flow": true,
|
||||
"quality_scale": "platinum",
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Support for the AccuWeather service."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, cast
|
||||
|
||||
@ -34,7 +35,13 @@ from . import AccuWeatherDataUpdateCoordinator
|
||||
from .const import (
|
||||
API_IMPERIAL,
|
||||
API_METRIC,
|
||||
ATTR_CATEGORY,
|
||||
ATTR_DIRECTION,
|
||||
ATTR_ENGLISH,
|
||||
ATTR_FORECAST,
|
||||
ATTR_LEVEL,
|
||||
ATTR_SPEED,
|
||||
ATTR_VALUE,
|
||||
ATTRIBUTION,
|
||||
DOMAIN,
|
||||
MAX_FORECAST_DAYS,
|
||||
@ -44,11 +51,20 @@ PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
@dataclass
|
||||
class AccuWeatherSensorDescription(SensorEntityDescription):
|
||||
class AccuWeatherSensorDescriptionMixin:
|
||||
"""Mixin for AccuWeather sensor."""
|
||||
|
||||
value_fn: Callable[[dict[str, Any], str], StateType]
|
||||
|
||||
|
||||
@dataclass
|
||||
class AccuWeatherSensorDescription(
|
||||
SensorEntityDescription, AccuWeatherSensorDescriptionMixin
|
||||
):
|
||||
"""Class describing AccuWeather sensor entities."""
|
||||
|
||||
unit_metric: str | None = None
|
||||
unit_imperial: str | None = None
|
||||
attr_fn: Callable[[dict[str, Any]], dict[str, StateType]] = lambda _: {}
|
||||
unit_fn: Callable[[bool], str | None] = lambda _: None
|
||||
|
||||
|
||||
FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||
@ -56,145 +72,162 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||
key="CloudCoverDay",
|
||||
icon="mdi:weather-cloudy",
|
||||
name="Cloud cover day",
|
||||
unit_metric=PERCENTAGE,
|
||||
unit_imperial=PERCENTAGE,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda _: PERCENTAGE,
|
||||
value_fn=lambda data, _: cast(int, data),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="CloudCoverNight",
|
||||
icon="mdi:weather-cloudy",
|
||||
name="Cloud cover night",
|
||||
unit_metric=PERCENTAGE,
|
||||
unit_imperial=PERCENTAGE,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda _: PERCENTAGE,
|
||||
value_fn=lambda data, _: cast(int, data),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Grass",
|
||||
icon="mdi:grass",
|
||||
name="Grass pollen",
|
||||
unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda _: CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="HoursOfSun",
|
||||
icon="mdi:weather-partly-cloudy",
|
||||
name="Hours of sun",
|
||||
unit_metric=TIME_HOURS,
|
||||
unit_imperial=TIME_HOURS,
|
||||
unit_fn=lambda _: TIME_HOURS,
|
||||
value_fn=lambda data, _: cast(float, data),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Mold",
|
||||
icon="mdi:blur",
|
||||
name="Mold pollen",
|
||||
unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda _: CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Ozone",
|
||||
icon="mdi:vector-triangle",
|
||||
name="Ozone",
|
||||
unit_metric=None,
|
||||
unit_imperial=None,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Ragweed",
|
||||
icon="mdi:sprout",
|
||||
name="Ragweed pollen",
|
||||
unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
unit_fn=lambda _: CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="RealFeelTemperatureMax",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="RealFeel temperature max",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="RealFeelTemperatureMin",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="RealFeel temperature min",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="RealFeelTemperatureShadeMax",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="RealFeel temperature shade max",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="RealFeelTemperatureShadeMin",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="RealFeel temperature shade min",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="ThunderstormProbabilityDay",
|
||||
icon="mdi:weather-lightning",
|
||||
name="Thunderstorm probability day",
|
||||
unit_metric=PERCENTAGE,
|
||||
unit_imperial=PERCENTAGE,
|
||||
unit_fn=lambda _: PERCENTAGE,
|
||||
value_fn=lambda data, _: cast(int, data),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="ThunderstormProbabilityNight",
|
||||
icon="mdi:weather-lightning",
|
||||
name="Thunderstorm probability night",
|
||||
unit_metric=PERCENTAGE,
|
||||
unit_imperial=PERCENTAGE,
|
||||
unit_fn=lambda _: PERCENTAGE,
|
||||
value_fn=lambda data, _: cast(int, data),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Tree",
|
||||
icon="mdi:tree-outline",
|
||||
name="Tree pollen",
|
||||
unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
unit_fn=lambda _: CONCENTRATION_PARTS_PER_CUBIC_METER,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="UVIndex",
|
||||
icon="mdi:weather-sunny",
|
||||
name="UV index",
|
||||
unit_metric=UV_INDEX,
|
||||
unit_imperial=UV_INDEX,
|
||||
unit_fn=lambda _: UV_INDEX,
|
||||
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WindGustDay",
|
||||
icon="mdi:weather-windy",
|
||||
name="Wind gust day",
|
||||
unit_metric=SPEED_KILOMETERS_PER_HOUR,
|
||||
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||
if metric
|
||||
else SPEED_MILES_PER_HOUR,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
|
||||
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WindGustNight",
|
||||
icon="mdi:weather-windy",
|
||||
name="Wind gust night",
|
||||
unit_metric=SPEED_KILOMETERS_PER_HOUR,
|
||||
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||
entity_registry_enabled_default=False,
|
||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||
if metric
|
||||
else SPEED_MILES_PER_HOUR,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
|
||||
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WindDay",
|
||||
icon="mdi:weather-windy",
|
||||
name="Wind day",
|
||||
unit_metric=SPEED_KILOMETERS_PER_HOUR,
|
||||
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||
if metric
|
||||
else SPEED_MILES_PER_HOUR,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
|
||||
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WindNight",
|
||||
icon="mdi:weather-windy",
|
||||
name="Wind night",
|
||||
unit_metric=SPEED_KILOMETERS_PER_HOUR,
|
||||
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||
if metric
|
||||
else SPEED_MILES_PER_HOUR,
|
||||
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
|
||||
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
|
||||
),
|
||||
)
|
||||
|
||||
@ -203,112 +236,117 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||
key="ApparentTemperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="Apparent temperature",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Ceiling",
|
||||
icon="mdi:weather-fog",
|
||||
name="Cloud ceiling",
|
||||
unit_metric=LENGTH_METERS,
|
||||
unit_imperial=LENGTH_FEET,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: LENGTH_METERS if metric else LENGTH_FEET,
|
||||
value_fn=lambda data, unit: round(data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="CloudCover",
|
||||
icon="mdi:weather-cloudy",
|
||||
name="Cloud cover",
|
||||
unit_metric=PERCENTAGE,
|
||||
unit_imperial=PERCENTAGE,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda _: PERCENTAGE,
|
||||
value_fn=lambda data, _: cast(int, data),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="DewPoint",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="Dew point",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="RealFeelTemperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="RealFeel temperature",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="RealFeelTemperatureShade",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="RealFeel temperature shade",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Precipitation",
|
||||
icon="mdi:weather-rainy",
|
||||
name="Precipitation",
|
||||
unit_metric=LENGTH_MILLIMETERS,
|
||||
unit_imperial=LENGTH_INCHES,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: LENGTH_MILLIMETERS if metric else LENGTH_INCHES,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
attr_fn=lambda data: {"type": data["PrecipitationType"]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="PressureTendency",
|
||||
device_class="accuweather__pressure_tendency",
|
||||
icon="mdi:gauge",
|
||||
name="Pressure tendency",
|
||||
unit_metric=None,
|
||||
unit_imperial=None,
|
||||
value_fn=lambda data, _: cast(str, data["LocalizedText"]).lower(),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="UVIndex",
|
||||
icon="mdi:weather-sunny",
|
||||
name="UV index",
|
||||
unit_metric=UV_INDEX,
|
||||
unit_imperial=UV_INDEX,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda _: UV_INDEX,
|
||||
value_fn=lambda data, _: cast(int, data),
|
||||
attr_fn=lambda data: {ATTR_LEVEL: data["UVIndexText"]},
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WetBulbTemperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="Wet bulb temperature",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WindChillTemperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
name="Wind chill temperature",
|
||||
unit_metric=TEMP_CELSIUS,
|
||||
unit_imperial=TEMP_FAHRENHEIT,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: TEMP_CELSIUS if metric else TEMP_FAHRENHEIT,
|
||||
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="Wind",
|
||||
icon="mdi:weather-windy",
|
||||
name="Wind",
|
||||
unit_metric=SPEED_KILOMETERS_PER_HOUR,
|
||||
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||
if metric
|
||||
else SPEED_MILES_PER_HOUR,
|
||||
value_fn=lambda data, unit: cast(float, data[ATTR_SPEED][unit][ATTR_VALUE]),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="WindGust",
|
||||
icon="mdi:weather-windy",
|
||||
name="Wind gust",
|
||||
unit_metric=SPEED_KILOMETERS_PER_HOUR,
|
||||
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||
entity_registry_enabled_default=False,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||
if metric
|
||||
else SPEED_MILES_PER_HOUR,
|
||||
value_fn=lambda data, unit: cast(float, data[ATTR_SPEED][unit][ATTR_VALUE]),
|
||||
),
|
||||
)
|
||||
|
||||
@ -320,19 +358,19 @@ async def async_setup_entry(
|
||||
|
||||
coordinator: AccuWeatherDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
sensors: list[AccuWeatherSensor] = []
|
||||
for description in SENSOR_TYPES:
|
||||
sensors.append(AccuWeatherSensor(coordinator, description))
|
||||
sensors = [
|
||||
AccuWeatherSensor(coordinator, description) for description in SENSOR_TYPES
|
||||
]
|
||||
|
||||
if coordinator.forecast:
|
||||
for description in FORECAST_SENSOR_TYPES:
|
||||
for day in range(MAX_FORECAST_DAYS + 1):
|
||||
# Some air quality/allergy sensors are only available for certain
|
||||
# locations.
|
||||
if description.key in coordinator.data[ATTR_FORECAST][0]:
|
||||
sensors.append(
|
||||
AccuWeatherSensor(coordinator, description, forecast_day=day)
|
||||
)
|
||||
# Some air quality/allergy sensors are only available for certain
|
||||
# locations.
|
||||
sensors.extend(
|
||||
AccuWeatherForecastSensor(coordinator, description, forecast_day=day)
|
||||
for day in range(MAX_FORECAST_DAYS + 1)
|
||||
for description in FORECAST_SENSOR_TYPES
|
||||
if description.key in coordinator.data[ATTR_FORECAST][0]
|
||||
)
|
||||
|
||||
async_add_entities(sensors)
|
||||
|
||||
@ -356,9 +394,8 @@ class AccuWeatherSensor(
|
||||
super().__init__(coordinator)
|
||||
self.entity_description = description
|
||||
self._sensor_data = _get_sensor_data(
|
||||
coordinator.data, forecast_day, description.key
|
||||
coordinator.data, description.key, forecast_day
|
||||
)
|
||||
self._attrs: dict[str, Any] = {}
|
||||
if forecast_day is not None:
|
||||
self._attr_name = f"{description.name} {forecast_day}d"
|
||||
self._attr_unique_id = (
|
||||
@ -368,82 +405,40 @@ class AccuWeatherSensor(
|
||||
self._attr_unique_id = (
|
||||
f"{coordinator.location_key}-{description.key}".lower()
|
||||
)
|
||||
if coordinator.is_metric:
|
||||
if self.coordinator.hass.config.units.is_metric:
|
||||
self._unit_system = API_METRIC
|
||||
self._attr_native_unit_of_measurement = description.unit_metric
|
||||
else:
|
||||
self._unit_system = API_IMPERIAL
|
||||
self._attr_native_unit_of_measurement = description.unit_imperial
|
||||
self._attr_native_unit_of_measurement = self.entity_description.unit_fn(
|
||||
self.coordinator.hass.config.units.is_metric
|
||||
)
|
||||
self._attr_device_info = coordinator.device_info
|
||||
self.forecast_day = forecast_day
|
||||
if forecast_day is not None:
|
||||
self.forecast_day = forecast_day
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the state."""
|
||||
if self.forecast_day is not None:
|
||||
if self.entity_description.device_class == SensorDeviceClass.TEMPERATURE:
|
||||
return cast(float, self._sensor_data["Value"])
|
||||
if self.entity_description.key == "UVIndex":
|
||||
return cast(int, self._sensor_data["Value"])
|
||||
if self.entity_description.key in ("Grass", "Mold", "Ragweed", "Tree", "Ozone"):
|
||||
return cast(int, self._sensor_data["Value"])
|
||||
if self.entity_description.key == "Ceiling":
|
||||
return round(self._sensor_data[self._unit_system]["Value"])
|
||||
if self.entity_description.key == "PressureTendency":
|
||||
return cast(str, self._sensor_data["LocalizedText"].lower())
|
||||
if self.entity_description.device_class == SensorDeviceClass.TEMPERATURE:
|
||||
return cast(float, self._sensor_data[self._unit_system]["Value"])
|
||||
if self.entity_description.key == "Precipitation":
|
||||
return cast(float, self._sensor_data[self._unit_system]["Value"])
|
||||
if self.entity_description.key in ("Wind", "WindGust"):
|
||||
return cast(float, self._sensor_data["Speed"][self._unit_system]["Value"])
|
||||
if self.entity_description.key in (
|
||||
"WindDay",
|
||||
"WindNight",
|
||||
"WindGustDay",
|
||||
"WindGustNight",
|
||||
):
|
||||
return cast(StateType, self._sensor_data["Speed"]["Value"])
|
||||
return cast(StateType, self._sensor_data)
|
||||
return self.entity_description.value_fn(self._sensor_data, self._unit_system)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
if self.forecast_day is not None:
|
||||
if self.entity_description.key in (
|
||||
"WindDay",
|
||||
"WindNight",
|
||||
"WindGustDay",
|
||||
"WindGustNight",
|
||||
):
|
||||
self._attrs["direction"] = self._sensor_data["Direction"]["English"]
|
||||
elif self.entity_description.key in (
|
||||
"Grass",
|
||||
"Mold",
|
||||
"Ozone",
|
||||
"Ragweed",
|
||||
"Tree",
|
||||
"UVIndex",
|
||||
):
|
||||
self._attrs["level"] = self._sensor_data["Category"]
|
||||
return self._attrs
|
||||
if self.entity_description.key == "UVIndex":
|
||||
self._attrs["level"] = self.coordinator.data["UVIndexText"]
|
||||
elif self.entity_description.key == "Precipitation":
|
||||
self._attrs["type"] = self.coordinator.data["PrecipitationType"]
|
||||
return self._attrs
|
||||
return self.entity_description.attr_fn(self.coordinator.data)
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle data update."""
|
||||
self._sensor_data = _get_sensor_data(
|
||||
self.coordinator.data, self.forecast_day, self.entity_description.key
|
||||
self.coordinator.data, self.entity_description.key
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
def _get_sensor_data(
|
||||
sensors: dict[str, Any], forecast_day: int | None, kind: str
|
||||
sensors: dict[str, Any],
|
||||
kind: str,
|
||||
forecast_day: int | None = None,
|
||||
) -> Any:
|
||||
"""Get sensor data."""
|
||||
if forecast_day is not None:
|
||||
@ -453,3 +448,20 @@ def _get_sensor_data(
|
||||
return sensors["PrecipitationSummary"][kind]
|
||||
|
||||
return sensors[kind]
|
||||
|
||||
|
||||
class AccuWeatherForecastSensor(AccuWeatherSensor):
|
||||
"""Define an AccuWeather forecast entity."""
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
return self.entity_description.attr_fn(self._sensor_data)
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle data update."""
|
||||
self._sensor_data = _get_sensor_data(
|
||||
self.coordinator.data, self.entity_description.key, self.forecast_day
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
@ -3,6 +3,9 @@
|
||||
"abort": {
|
||||
"single_instance_allowed": "Ya configurado. Solo es posible una \u00fanica configuraci\u00f3n."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "Algunos sensores no est\u00e1n habilitados de forma predeterminada. Puede habilitarlos en el registro de la entidad despu\u00e9s de la configuraci\u00f3n de la integraci\u00f3n. \nEl pron\u00f3stico del tiempo no est\u00e1 habilitado de forma predeterminada. Puedes habilitarlo en las opciones de integraci\u00f3n."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"invalid_api_key": "Clave de API no v\u00e1lida",
|
||||
@ -21,6 +24,7 @@
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Llegar al servidor de AccuWeather",
|
||||
"remaining_requests": "Solicitudes permitidas restantes"
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
"single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "Algunos sensores no est\u00e1n habilitados de forma predeterminada. Puede habilitarlos en el registro de la entidad despu\u00e9s de la configuraci\u00f3n de la integraci\u00f3n.\n El pron\u00f3stico del tiempo no est\u00e1 habilitado de forma predeterminada. Puedes habilitarlo en las opciones de integraci\u00f3n."
|
||||
"default": "Algunos sensores no est\u00e1n habilitados de forma predeterminada. Puedes habilitarlos en el registro de la entidad despu\u00e9s de la configuraci\u00f3n de la integraci\u00f3n.\nEl pron\u00f3stico del tiempo no est\u00e1 habilitado de forma predeterminada. Puedes habilitarlo en las opciones de integraci\u00f3n."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
@ -28,13 +28,13 @@
|
||||
"data": {
|
||||
"forecast": "Pron\u00f3stico del tiempo"
|
||||
},
|
||||
"description": "Debido a las limitaciones de la versi\u00f3n gratuita de la clave API de AccuWeather, cuando habilitas el pron\u00f3stico del tiempo, las actualizaciones de datos se realizar\u00e1n cada 64 minutos en lugar de cada 32 minutos."
|
||||
"description": "Debido a las limitaciones de la versi\u00f3n gratuita de la clave API de AccuWeather, cuando habilitas el pron\u00f3stico del tiempo, las actualizaciones de datos se realizar\u00e1n cada 80 minutos en lugar de cada 40 minutos."
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Alcanzar el servidor AccuWeather",
|
||||
"can_reach_server": "Se puede llegar al servidor AccuWeather",
|
||||
"remaining_requests": "Solicitudes permitidas restantes"
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,8 @@
|
||||
"state": {
|
||||
"accuweather__pressure_tendency": {
|
||||
"falling": "Fallande",
|
||||
"rising": "Stigande"
|
||||
"rising": "Stigande",
|
||||
"steady": "Stadig"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,41 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"single_instance_allowed": "Redan konfigurerad. Endast en konfiguration m\u00f6jlig."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "Vissa sensorer \u00e4r inte aktiverade som standard. Du kan aktivera dem i entitetsregistret efter integrationskonfigurationen.\n V\u00e4derprognos \u00e4r inte aktiverat som standard. Du kan aktivera det i integrationsalternativen."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"invalid_api_key": "Ogiltig API-nyckel",
|
||||
"requests_exceeded": "Det till\u00e5tna antalet f\u00f6rfr\u00e5gningar till Accuweather API har \u00f6verskridits. Du m\u00e5ste v\u00e4nta eller \u00e4ndra API-nyckel."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "API-nyckel"
|
||||
"api_key": "API-nyckel",
|
||||
"latitude": "Latitud",
|
||||
"longitude": "Longitud",
|
||||
"name": "Namn"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "V\u00e4derprognos"
|
||||
},
|
||||
"description": "P\u00e5 grund av begr\u00e4nsningarna f\u00f6r den kostnadsfria versionen av AccuWeather API-nyckeln, n\u00e4r du aktiverar v\u00e4derprognos, kommer datauppdateringar att utf\u00f6ras var 80:e minut ist\u00e4llet f\u00f6r var 40:e minut."
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "N\u00e5 AccuWeather-servern",
|
||||
"remaining_requests": "\u00c5terst\u00e5ende till\u00e5tna f\u00f6rfr\u00e5gningar"
|
||||
}
|
||||
}
|
||||
}
|
@ -70,7 +70,7 @@ class AccuWeatherEntity(
|
||||
# Coordinator data is used also for sensors which don't have units automatically
|
||||
# converted, hence the weather entity's native units follow the configured unit
|
||||
# system
|
||||
if coordinator.is_metric:
|
||||
if coordinator.hass.config.units.is_metric:
|
||||
self._attr_native_precipitation_unit = LENGTH_MILLIMETERS
|
||||
self._attr_native_pressure_unit = PRESSURE_HPA
|
||||
self._attr_native_temperature_unit = TEMP_CELSIUS
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""Base class for Acmeda Roller Blinds."""
|
||||
from __future__ import annotations
|
||||
|
||||
import aiopulse
|
||||
|
||||
from homeassistant.core import callback
|
||||
@ -11,11 +13,13 @@ from .const import ACMEDA_ENTITY_REMOVE, DOMAIN, LOGGER
|
||||
class AcmedaBase(entity.Entity):
|
||||
"""Base representation of an Acmeda roller."""
|
||||
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, roller: aiopulse.Roller) -> None:
|
||||
"""Initialize the roller."""
|
||||
self.roller = roller
|
||||
|
||||
async def async_remove_and_unregister(self):
|
||||
async def async_remove_and_unregister(self) -> None:
|
||||
"""Unregister from entity and device registry and call entity remove function."""
|
||||
LOGGER.error("Removing %s %s", self.__class__.__name__, self.unique_id)
|
||||
|
||||
@ -25,14 +29,18 @@ class AcmedaBase(entity.Entity):
|
||||
|
||||
dev_registry = dr.async_get(self.hass)
|
||||
device = dev_registry.async_get_device(identifiers={(DOMAIN, self.unique_id)})
|
||||
if device is not None:
|
||||
if (
|
||||
device is not None
|
||||
and self.registry_entry is not None
|
||||
and self.registry_entry.config_entry_id is not None
|
||||
):
|
||||
dev_registry.async_update_device(
|
||||
device.id, remove_config_entry_id=self.registry_entry.config_entry_id
|
||||
)
|
||||
|
||||
await self.async_remove(force_remove=True)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Entity has been added to hass."""
|
||||
self.roller.callback_subscribe(self.notify_update)
|
||||
|
||||
@ -44,33 +52,28 @@ class AcmedaBase(entity.Entity):
|
||||
)
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
"""Entity being removed from hass."""
|
||||
self.roller.callback_unsubscribe(self.notify_update)
|
||||
|
||||
@callback
|
||||
def notify_update(self):
|
||||
def notify_update(self) -> None:
|
||||
"""Write updated device state information."""
|
||||
LOGGER.debug("Device update notification received: %s", self.name)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Report that Acmeda entities do not need polling."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID of this roller."""
|
||||
return self.roller.id
|
||||
|
||||
@property
|
||||
def device_id(self):
|
||||
def device_id(self) -> str:
|
||||
"""Return the ID of this roller."""
|
||||
return self.roller.id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> str | None:
|
||||
"""Return the name of roller."""
|
||||
return self.roller.name
|
||||
|
||||
|
@ -11,6 +11,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from .base import AcmedaBase
|
||||
from .const import ACMEDA_HUB_UPDATE, DOMAIN
|
||||
from .helpers import async_add_acmeda_entities
|
||||
from .hub import PulseHub
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -19,7 +20,7 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Acmeda Rollers from a config entry."""
|
||||
hub = hass.data[DOMAIN][config_entry.entry_id]
|
||||
hub: PulseHub = hass.data[DOMAIN][config_entry.entry_id]
|
||||
|
||||
current: set[int] = set()
|
||||
|
||||
@ -41,15 +42,15 @@ async def async_setup_entry(
|
||||
class AcmedaBattery(AcmedaBase, SensorEntity):
|
||||
"""Representation of a Acmeda cover device."""
|
||||
|
||||
device_class = SensorDeviceClass.BATTERY
|
||||
_attr_device_class = SensorDeviceClass.BATTERY
|
||||
_attr_native_unit_of_measurement = PERCENTAGE
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> str:
|
||||
"""Return the name of roller."""
|
||||
return f"{super().name} Battery"
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> float | int | None:
|
||||
"""Return the state of the device."""
|
||||
return self.roller.battery
|
||||
|
@ -8,7 +8,7 @@
|
||||
"data": {
|
||||
"id": "ID de host"
|
||||
},
|
||||
"title": "Elige un hub para a\u00f1adir"
|
||||
"title": "Elige un concentrador para a\u00f1adir"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
homeassistant/components/acmeda/translations/sv.json
Normal file
15
homeassistant/components/acmeda/translations/sv.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"no_devices_found": "Inga enheter hittades i n\u00e4tverket"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"id": "V\u00e4rd-ID"
|
||||
},
|
||||
"title": "V\u00e4lj en hubb att l\u00e4gga till"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -80,7 +80,7 @@ class AdaxDevice(ClimateEntity):
|
||||
manufacturer="Adax",
|
||||
)
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set hvac mode."""
|
||||
if hvac_mode == HVACMode.HEAT:
|
||||
temperature = max(self.min_temp, self.target_temperature or self.min_temp)
|
||||
@ -140,7 +140,7 @@ class LocalAdaxDevice(ClimateEntity):
|
||||
manufacturer="Adax",
|
||||
)
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
|
||||
return
|
||||
|
@ -2,8 +2,8 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "El dispositivo ya est\u00e1 configurado",
|
||||
"heater_not_available": "Calentador no disponible. Intente restablecer el calentador pulsando + y OK durante algunos segundos.",
|
||||
"heater_not_found": "No se encuentra el calefactor. Intente acercar el calefactor al ordenador del Asistente de Hogar.",
|
||||
"heater_not_available": "Calefactor no disponible. Intenta reiniciar el calentador presionando + y OK durante unos segundos.",
|
||||
"heater_not_found": "No se encontr\u00f3 el calentador. Intenta acercar el calentador al ordenador con Home Assistant.",
|
||||
"invalid_auth": "Autenticaci\u00f3n no v\u00e1lida"
|
||||
},
|
||||
"error": {
|
||||
@ -21,13 +21,13 @@
|
||||
"wifi_pswd": "Contrase\u00f1a Wi-Fi",
|
||||
"wifi_ssid": "SSID Wi-Fi"
|
||||
},
|
||||
"description": "Reinicie el calentador presionando + y OK hasta que la pantalla muestre 'Reiniciar'. Luego presione y mantenga presionado el bot\u00f3n OK en el calentador hasta que el LED azul comience a parpadear antes de presionar Enviar. La configuraci\u00f3n del calentador puede llevar algunos minutos."
|
||||
"description": "Reinicia el calentador pulsando + y OK hasta que la pantalla muestre 'Restablecer'. Luego mant\u00e9n pulsado el bot\u00f3n OK en el calentador hasta que el led azul comience a parpadear antes de pulsar Enviar. La configuraci\u00f3n del calentador puede tardar algunos minutos."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"connection_type": "Seleccione el tipo de conexi\u00f3n"
|
||||
"connection_type": "Selecciona el tipo de conexi\u00f3n"
|
||||
},
|
||||
"description": "Seleccione el tipo de conexi\u00f3n. Local requiere calentadores con bluetooth"
|
||||
"description": "Selecciona el tipo de conexi\u00f3n. Local requiere calefactores con bluetooth"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
homeassistant/components/adax/translations/sv.json
Normal file
34
homeassistant/components/adax/translations/sv.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad",
|
||||
"heater_not_available": "V\u00e4rmare inte tillg\u00e4nglig. F\u00f6rs\u00f6k att \u00e5terst\u00e4lla v\u00e4rmaren genom att trycka p\u00e5 + och OK i n\u00e5gra sekunder.",
|
||||
"heater_not_found": "V\u00e4rmare hittades inte. F\u00f6rs\u00f6k att flytta v\u00e4rmaren n\u00e4rmare Home Assistant-datorn.",
|
||||
"invalid_auth": "Ogiltig autentisering"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta."
|
||||
},
|
||||
"step": {
|
||||
"cloud": {
|
||||
"data": {
|
||||
"account_id": "Konto-ID",
|
||||
"password": "L\u00f6senord"
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"data": {
|
||||
"wifi_pswd": "Wi-Fi l\u00f6senord",
|
||||
"wifi_ssid": "Wi-Fi SSID"
|
||||
},
|
||||
"description": "\u00c5terst\u00e4ll v\u00e4rmaren genom att trycka p\u00e5 + och OK tills displayen visar 'Reset'. Tryck sedan och h\u00e5ll ner OK-knappen p\u00e5 v\u00e4rmaren tills den bl\u00e5 lysdioden b\u00f6rjar blinka innan du trycker p\u00e5 Skicka. Det kan ta n\u00e5gra minuter att konfigurera v\u00e4rmaren."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"connection_type": "V\u00e4lj anslutningstyp"
|
||||
},
|
||||
"description": "V\u00e4lj anslutningstyp. Lokalt kr\u00e4ver v\u00e4rmare med bluetooth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@
|
||||
"data": {
|
||||
"connection_type": "\u9078\u64c7\u9023\u7dda\u985e\u5225"
|
||||
},
|
||||
"description": "\u9078\u64c7\u9023\u7dda\u985e\u5225\u3002\u672c\u5730\u7aef\u5c07\u9700\u8981\u5177\u5099\u85cd\u82bd\u52a0\u71b1\u5668"
|
||||
"description": "\u9078\u64c7\u9023\u7dda\u985e\u5225\u3002\u672c\u5730\u7aef\u5c07\u9700\u8981\u5177\u5099\u85cd\u7259\u52a0\u71b1\u5668"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@
|
||||
},
|
||||
"step": {
|
||||
"hassio_confirm": {
|
||||
"description": "\u00bfDesea configurar Home Assistant para conectarse al AdGuard Home proporcionado por el complemento Supervisor: {addon} ?",
|
||||
"title": "AdGuard Home v\u00eda complemento de Home Assistant"
|
||||
"description": "\u00bfQuieres configurar Home Assistant para conectarse al AdGuard Home proporcionado por el complemento: {addon}?",
|
||||
"title": "AdGuard Home a trav\u00e9s del complemento Home Assistant"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
@ -18,10 +18,10 @@
|
||||
"password": "Contrase\u00f1a",
|
||||
"port": "Puerto",
|
||||
"ssl": "Utiliza un certificado SSL",
|
||||
"username": "Usuario",
|
||||
"verify_ssl": "Verificar certificado SSL"
|
||||
"username": "Nombre de usuario",
|
||||
"verify_ssl": "Verificar el certificado SSL"
|
||||
},
|
||||
"description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control."
|
||||
"description": "Configura tu instancia AdGuard Home para permitir la supervisi\u00f3n y el control."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Tj\u00e4nsten \u00e4r redan konfigurerad",
|
||||
"existing_instance_updated": "Uppdaterade existerande konfiguration."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta."
|
||||
},
|
||||
"step": {
|
||||
"hassio_confirm": {
|
||||
"description": "Vill du konfigurera Home Assistant f\u00f6r att ansluta till AdGuard Home som tillhandah\u00e5lls av Supervisor Add-on: {addon}?",
|
||||
@ -10,7 +14,9 @@
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "V\u00e4rd",
|
||||
"password": "L\u00f6senord",
|
||||
"port": "Port",
|
||||
"ssl": "AdGuard Home anv\u00e4nder ett SSL-certifikat",
|
||||
"username": "Anv\u00e4ndarnamn",
|
||||
"verify_ssl": "AdGuard Home anv\u00e4nder ett korrekt certifikat"
|
||||
|
@ -53,7 +53,7 @@ class AdsBinarySensor(AdsEntity, BinarySensorEntity):
|
||||
super().__init__(ads_hub, name, ads_var)
|
||||
self._attr_device_class = device_class or BinarySensorDeviceClass.MOVING
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register device notification."""
|
||||
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""Support for ADS light sources."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pyads
|
||||
import voluptuous as vol
|
||||
|
||||
@ -66,7 +68,7 @@ class AdsLight(AdsEntity, LightEntity):
|
||||
self._attr_color_mode = ColorMode.ONOFF
|
||||
self._attr_supported_color_modes = {ColorMode.ONOFF}
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register device notification."""
|
||||
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
|
||||
|
||||
@ -87,7 +89,7 @@ class AdsLight(AdsEntity, LightEntity):
|
||||
"""Return True if the entity is on."""
|
||||
return self._state_dict[STATE_KEY_STATE]
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on or set a specific dimmer value."""
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||
self._ads_hub.write_by_name(self._ads_var, True, pyads.PLCTYPE_BOOL)
|
||||
@ -97,6 +99,6 @@ class AdsLight(AdsEntity, LightEntity):
|
||||
self._ads_var_brightness, brightness, pyads.PLCTYPE_UINT
|
||||
)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the light off."""
|
||||
self._ads_hub.write_by_name(self._ads_var, False, pyads.PLCTYPE_BOOL)
|
||||
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import ads
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
|
||||
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -19,6 +18,7 @@ from . import (
|
||||
STATE_KEY_STATE,
|
||||
AdsEntity,
|
||||
)
|
||||
from .. import ads
|
||||
|
||||
DEFAULT_NAME = "ADS sensor"
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
@ -70,7 +70,7 @@ class AdsSensor(AdsEntity, SensorEntity):
|
||||
self._ads_type = ads_type
|
||||
self._factor = factor
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register device notification."""
|
||||
await self.async_initialize_device(
|
||||
self._ads_var,
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""Support for ADS switch platform."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pyads
|
||||
import voluptuous as vol
|
||||
|
||||
@ -41,7 +43,7 @@ def setup_platform(
|
||||
class AdsSwitch(AdsEntity, SwitchEntity):
|
||||
"""Representation of an ADS switch device."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register device notification."""
|
||||
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
|
||||
|
||||
@ -50,10 +52,10 @@ class AdsSwitch(AdsEntity, SwitchEntity):
|
||||
"""Return True if the entity is on."""
|
||||
return self._state_dict[STATE_KEY_STATE]
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch on."""
|
||||
self._ads_hub.write_by_name(self._ads_var, True, pyads.PLCTYPE_BOOL)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch off."""
|
||||
self._ads_hub.write_by_name(self._ads_var, False, pyads.PLCTYPE_BOOL)
|
||||
|
@ -20,6 +20,8 @@ PLATFORMS = [
|
||||
Platform.SELECT,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
Platform.UPDATE,
|
||||
Platform.LIGHT,
|
||||
]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -50,19 +52,25 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
update_interval=timedelta(seconds=ADVANTAGE_AIR_SYNC_INTERVAL),
|
||||
)
|
||||
|
||||
async def async_change(change):
|
||||
try:
|
||||
if await api.async_change(change):
|
||||
await coordinator.async_refresh()
|
||||
except ApiError as err:
|
||||
_LOGGER.warning(err)
|
||||
def error_handle_factory(func):
|
||||
"""Return the provided API function wrapped in an error handler and coordinator refresh."""
|
||||
|
||||
async def error_handle(param):
|
||||
try:
|
||||
if await func(param):
|
||||
await coordinator.async_refresh()
|
||||
except ApiError as err:
|
||||
_LOGGER.warning(err)
|
||||
|
||||
return error_handle
|
||||
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
hass.data[DOMAIN][entry.entry_id] = {
|
||||
"coordinator": coordinator,
|
||||
"async_change": async_change,
|
||||
"async_change": error_handle_factory(api.aircon.async_set),
|
||||
"async_set_light": error_handle_factory(api.lights.async_set),
|
||||
}
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.climate import ClimateEntity
|
||||
from homeassistant.components.climate.const import (
|
||||
@ -44,7 +45,7 @@ AC_HVAC_MODES = [
|
||||
]
|
||||
|
||||
ADVANTAGE_AIR_FAN_MODES = {
|
||||
"auto": FAN_AUTO,
|
||||
"autoAA": FAN_AUTO,
|
||||
"low": FAN_LOW,
|
||||
"medium": FAN_MEDIUM,
|
||||
"high": FAN_HIGH,
|
||||
@ -114,7 +115,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
"""Return the current fan modes."""
|
||||
return ADVANTAGE_AIR_FAN_MODES.get(self._ac["fan"])
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the HVAC Mode and State."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.async_change(
|
||||
@ -132,13 +133,13 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
}
|
||||
)
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode):
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set the Fan Mode."""
|
||||
await self.async_change(
|
||||
{self.ac_key: {"info": {"fan": HASS_FAN_MODES.get(fan_mode)}}}
|
||||
)
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the Temperature."""
|
||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
await self.async_change({self.ac_key: {"info": {"setTemp": temp}}})
|
||||
@ -179,7 +180,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
"""Return the target temperature."""
|
||||
return self._zone["setTemp"]
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the HVAC Mode and State."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.async_change(
|
||||
@ -198,7 +199,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
}
|
||||
)
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the Temperature."""
|
||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
await self.async_change(
|
||||
|
90
homeassistant/components/advantage_air/light.py
Normal file
90
homeassistant/components/advantage_air/light.py
Normal file
@ -0,0 +1,90 @@
|
||||
"""Light platform for Advantage Air integration."""
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
ADVANTAGE_AIR_STATE_OFF,
|
||||
ADVANTAGE_AIR_STATE_ON,
|
||||
DOMAIN as ADVANTAGE_AIR_DOMAIN,
|
||||
)
|
||||
from .entity import AdvantageAirEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir light platform."""
|
||||
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities = []
|
||||
if "myLights" in instance["coordinator"].data:
|
||||
for light in instance["coordinator"].data["myLights"]["lights"].values():
|
||||
if light.get("relay"):
|
||||
entities.append(AdvantageAirLight(instance, light))
|
||||
else:
|
||||
entities.append(AdvantageAirLightDimmable(instance, light))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class AdvantageAirLight(AdvantageAirEntity, LightEntity):
|
||||
"""Representation of Advantage Air Light."""
|
||||
|
||||
_attr_supported_color_modes = {ColorMode.ONOFF}
|
||||
|
||||
def __init__(self, instance, light):
|
||||
"""Initialize an Advantage Air Light."""
|
||||
super().__init__(instance)
|
||||
self.async_set_light = instance["async_set_light"]
|
||||
self._id = light["id"]
|
||||
self._attr_unique_id += f"-{self._id}"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(ADVANTAGE_AIR_DOMAIN, self._attr_unique_id)},
|
||||
via_device=(ADVANTAGE_AIR_DOMAIN, self.coordinator.data["system"]["rid"]),
|
||||
manufacturer="Advantage Air",
|
||||
model=light.get("moduleType"),
|
||||
name=light["name"],
|
||||
)
|
||||
|
||||
@property
|
||||
def _light(self):
|
||||
"""Return the light object."""
|
||||
return self.coordinator.data["myLights"]["lights"][self._id]
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return if the light is on."""
|
||||
return self._light["state"] == ADVANTAGE_AIR_STATE_ON
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on."""
|
||||
await self.async_set_light({"id": self._id, "state": ADVANTAGE_AIR_STATE_ON})
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the light off."""
|
||||
await self.async_set_light({"id": self._id, "state": ADVANTAGE_AIR_STATE_OFF})
|
||||
|
||||
|
||||
class AdvantageAirLightDimmable(AdvantageAirLight):
|
||||
"""Representation of Advantage Air Dimmable Light."""
|
||||
|
||||
_attr_supported_color_modes = {ColorMode.ONOFF, ColorMode.BRIGHTNESS}
|
||||
|
||||
@property
|
||||
def brightness(self) -> int:
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
return round(self._light["value"] * 255 / 100)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on and optionally set the brightness."""
|
||||
data = {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
data["value"] = round(kwargs[ATTR_BRIGHTNESS] * 100 / 255)
|
||||
await self.async_set_light(data)
|
@ -4,7 +4,7 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/advantage_air",
|
||||
"codeowners": ["@Bre77"],
|
||||
"requirements": ["advantage_air==0.3.1"],
|
||||
"requirements": ["advantage_air==0.4.1"],
|
||||
"quality_scale": "platinum",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["advantage_air"]
|
||||
|
@ -29,15 +29,15 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity):
|
||||
"""Representation of Advantage Air MyZone control."""
|
||||
|
||||
_attr_icon = "mdi:home-thermometer"
|
||||
_attr_options = [ADVANTAGE_AIR_INACTIVE]
|
||||
_number_to_name = {0: ADVANTAGE_AIR_INACTIVE}
|
||||
_name_to_number = {ADVANTAGE_AIR_INACTIVE: 0}
|
||||
_attr_name = "MyZone"
|
||||
|
||||
def __init__(self, instance, ac_key):
|
||||
"""Initialize an Advantage Air MyZone control."""
|
||||
super().__init__(instance, ac_key)
|
||||
self._attr_unique_id += "-myzone"
|
||||
self._attr_options = [ADVANTAGE_AIR_INACTIVE]
|
||||
self._number_to_name = {0: ADVANTAGE_AIR_INACTIVE}
|
||||
self._name_to_number = {ADVANTAGE_AIR_INACTIVE: 0}
|
||||
|
||||
for zone in instance["coordinator"].data["aircons"][ac_key]["zones"].values():
|
||||
if zone["type"] > 0:
|
||||
@ -46,11 +46,11 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity):
|
||||
self._attr_options.append(zone["name"])
|
||||
|
||||
@property
|
||||
def current_option(self):
|
||||
def current_option(self) -> str:
|
||||
"""Return the current MyZone."""
|
||||
return self._number_to_name[self._ac["myZone"]]
|
||||
|
||||
async def async_select_option(self, option):
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Set the MyZone."""
|
||||
await self.async_change(
|
||||
{self.ac_key: {"info": {"myZone": self._name_to_number[option]}}}
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""Switch platform for Advantage Air integration."""
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -44,13 +46,13 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity):
|
||||
"""Return the fresh air status."""
|
||||
return self._ac["freshAirStatus"] == ADVANTAGE_AIR_STATE_ON
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn fresh air on."""
|
||||
await self.async_change(
|
||||
{self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_ON}}}
|
||||
)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn fresh air off."""
|
||||
await self.async_change(
|
||||
{self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_OFF}}}
|
||||
|
20
homeassistant/components/advantage_air/translations/sv.json
Normal file
20
homeassistant/components/advantage_air/translations/sv.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP-adress",
|
||||
"port": "Port"
|
||||
},
|
||||
"description": "Anslut till API:et f\u00f6r din Advantage Air v\u00e4ggmonterade surfplatta.",
|
||||
"title": "Anslut"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
homeassistant/components/advantage_air/update.py
Normal file
52
homeassistant/components/advantage_air/update.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""Advantage Air Update platform."""
|
||||
from homeassistant.components.update import UpdateEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN as ADVANTAGE_AIR_DOMAIN
|
||||
from .entity import AdvantageAirEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir update platform."""
|
||||
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
async_add_entities([AdvantageAirApp(instance)])
|
||||
|
||||
|
||||
class AdvantageAirApp(AdvantageAirEntity, UpdateEntity):
|
||||
"""Representation of Advantage Air App."""
|
||||
|
||||
_attr_name = "App"
|
||||
|
||||
def __init__(self, instance):
|
||||
"""Initialize the Advantage Air App."""
|
||||
super().__init__(instance)
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={
|
||||
(ADVANTAGE_AIR_DOMAIN, self.coordinator.data["system"]["rid"])
|
||||
},
|
||||
manufacturer="Advantage Air",
|
||||
model=self.coordinator.data["system"]["sysType"],
|
||||
name=self.coordinator.data["system"]["name"],
|
||||
sw_version=self.coordinator.data["system"]["myAppRev"],
|
||||
)
|
||||
|
||||
@property
|
||||
def installed_version(self):
|
||||
"""Return the current app version."""
|
||||
return self.coordinator.data["system"]["myAppRev"]
|
||||
|
||||
@property
|
||||
def latest_version(self):
|
||||
"""Return if there is an update."""
|
||||
if self.coordinator.data["system"]["needsUpdate"]:
|
||||
return "Needs Update"
|
||||
return self.installed_version
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_ATTRIBUTION
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
@ -63,7 +62,7 @@ async def async_setup_entry(
|
||||
class AbstractAemetSensor(CoordinatorEntity[WeatherUpdateCoordinator], SensorEntity):
|
||||
"""Abstract class for an AEMET OpenData sensor."""
|
||||
|
||||
_attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||
_attr_attribution = ATTRIBUTION
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -14,7 +14,7 @@
|
||||
"longitude": "Longitud",
|
||||
"name": "Nombre de la integraci\u00f3n"
|
||||
},
|
||||
"description": "Configurar la integraci\u00f3n de AEMET OpenData. Para generar la clave API, ve a https://opendata.aemet.es/centrodedescargas/altaUsuario"
|
||||
"description": "Para generar la clave API, ve a https://opendata.aemet.es/centrodedescargas/altaUsuario"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1,9 +1,28 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Platsen \u00e4r redan konfigurerad"
|
||||
},
|
||||
"error": {
|
||||
"invalid_api_key": "Ogiltig API-nyckel"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "API-nyckel"
|
||||
"api_key": "API-nyckel",
|
||||
"latitude": "Latitud",
|
||||
"longitude": "Longitud",
|
||||
"name": "Integrationens namn"
|
||||
},
|
||||
"description": "F\u00f6r att generera API-nyckel g\u00e5 till https://opendata.aemet.es/centrodedescargas/altaUsuario"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"station_updates": "Samla data fr\u00e5n AEMET v\u00e4derstationer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ from agent import AgentError
|
||||
from homeassistant.components.camera import CameraEntityFeature
|
||||
from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_ATTRIBUTION
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
@ -70,6 +69,8 @@ async def async_setup_entry(
|
||||
class AgentCamera(MjpegCamera):
|
||||
"""Representation of an Agent Device Stream."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
_attr_should_poll = True # Cameras default to False
|
||||
_attr_supported_features = CameraEntityFeature.ON_OFF
|
||||
|
||||
def __init__(self, device):
|
||||
@ -91,7 +92,7 @@ class AgentCamera(MjpegCamera):
|
||||
sw_version=device.client.version,
|
||||
)
|
||||
|
||||
async def async_update(self):
|
||||
async def async_update(self) -> None:
|
||||
"""Update our state from the Agent API."""
|
||||
try:
|
||||
await self.device.update()
|
||||
@ -108,7 +109,6 @@ class AgentCamera(MjpegCamera):
|
||||
self._attr_icon = "mdi:camcorder"
|
||||
self._attr_available = self.device.client.is_available
|
||||
self._attr_extra_state_attributes = {
|
||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||
"editable": False,
|
||||
"enabled": self.is_on,
|
||||
"connected": self.connected,
|
||||
@ -118,11 +118,6 @@ class AgentCamera(MjpegCamera):
|
||||
"alerts_enabled": self.device.alerts_active,
|
||||
}
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""Update the state periodically."""
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_recording(self) -> bool:
|
||||
"""Return whether the monitor is recording."""
|
||||
@ -149,7 +144,7 @@ class AgentCamera(MjpegCamera):
|
||||
return self.device.online
|
||||
|
||||
@property
|
||||
def motion_detection_enabled(self):
|
||||
def motion_detection_enabled(self) -> bool:
|
||||
"""Return the camera motion detection status."""
|
||||
return self.device.detector_active
|
||||
|
||||
@ -161,11 +156,11 @@ class AgentCamera(MjpegCamera):
|
||||
"""Disable alerts."""
|
||||
await self.device.alerts_off()
|
||||
|
||||
async def async_enable_motion_detection(self):
|
||||
async def async_enable_motion_detection(self) -> None:
|
||||
"""Enable motion detection."""
|
||||
await self.device.detector_on()
|
||||
|
||||
async def async_disable_motion_detection(self):
|
||||
async def async_disable_motion_detection(self) -> None:
|
||||
"""Disable motion detection."""
|
||||
await self.device.detector_off()
|
||||
|
||||
@ -177,7 +172,7 @@ class AgentCamera(MjpegCamera):
|
||||
"""Stop recording."""
|
||||
await self.device.record_stop()
|
||||
|
||||
async def async_turn_on(self):
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Enable the camera."""
|
||||
await self.device.enable()
|
||||
|
||||
@ -185,6 +180,6 @@ class AgentCamera(MjpegCamera):
|
||||
"""Take a snapshot."""
|
||||
await self.device.snapshot()
|
||||
|
||||
async def async_turn_off(self):
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Disable the camera."""
|
||||
await self.device.disable()
|
||||
|
@ -4,7 +4,7 @@
|
||||
"already_configured": "El dispositivo ya est\u00e1 configurado"
|
||||
},
|
||||
"error": {
|
||||
"already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso",
|
||||
"already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en curso",
|
||||
"cannot_connect": "No se pudo conectar"
|
||||
},
|
||||
"step": {
|
||||
@ -13,7 +13,7 @@
|
||||
"host": "Host",
|
||||
"port": "Puerto"
|
||||
},
|
||||
"title": "Configurar el Agente de DVR"
|
||||
"title": "Configurar Agent DVR"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "\u05de\u05d0\u05e8\u05d7",
|
||||
"port": "\u05e4\u05d5\u05e8\u05d8"
|
||||
"port": "\u05e4\u05ea\u05d7\u05d4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad"
|
||||
},
|
||||
"error": {
|
||||
"already_in_progress": "Konfigurationsfl\u00f6de f\u00f6r enhet p\u00e5g\u00e5r redan."
|
||||
"already_in_progress": "Konfigurationsfl\u00f6de f\u00f6r enhet p\u00e5g\u00e5r redan.",
|
||||
"cannot_connect": "Det gick inte att ansluta."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
|
@ -13,7 +13,6 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONF_NAME,
|
||||
PERCENTAGE,
|
||||
@ -136,6 +135,7 @@ async def async_setup_entry(
|
||||
class AirlySensor(CoordinatorEntity[AirlyDataUpdateCoordinator], SensorEntity):
|
||||
"""Define an Airly sensor."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
_attr_has_entity_name = True
|
||||
entity_description: AirlySensorEntityDescription
|
||||
|
||||
@ -159,7 +159,7 @@ class AirlySensor(CoordinatorEntity[AirlyDataUpdateCoordinator], SensorEntity):
|
||||
self._attr_unique_id = (
|
||||
f"{coordinator.latitude}-{coordinator.longitude}-{description.key}".lower()
|
||||
)
|
||||
self._attrs: dict[str, Any] = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||
self._attrs: dict[str, Any] = {}
|
||||
self.entity_description = description
|
||||
|
||||
@property
|
||||
|
@ -20,6 +20,7 @@
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Llegar al servidor de Airly",
|
||||
"requests_per_day": "Solicitudes permitidas por d\u00eda",
|
||||
"requests_remaining": "Solicitudes permitidas restantes"
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
},
|
||||
"error": {
|
||||
"invalid_api_key": "Clave API no v\u00e1lida",
|
||||
"wrong_location": "No hay estaciones de medici\u00f3n Airly en esta zona."
|
||||
"wrong_location": "No hay estaciones de medici\u00f3n Airly en esta \u00e1rea."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
@ -15,13 +15,13 @@
|
||||
"longitude": "Longitud",
|
||||
"name": "Nombre"
|
||||
},
|
||||
"description": "Establecer la integraci\u00f3n de la calidad del aire de Airly. Para generar la clave de la API vaya a https://developer.airly.eu/register"
|
||||
"description": "Para generar la clave API, ve a https://developer.airly.eu/register"
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Alcanzar el servidor Airly",
|
||||
"can_reach_server": "Se puede llegar al servidor Airly",
|
||||
"requests_per_day": "Solicitudes permitidas por d\u00eda",
|
||||
"requests_remaining": "Solicitudes permitidas restantes"
|
||||
}
|
||||
|
@ -18,5 +18,12 @@
|
||||
"description": "Konfigurera integration av luftkvalitet. F\u00f6r att skapa API-nyckel, g\u00e5 till https://developer.airly.eu/register"
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "N\u00e5 Airly-servern",
|
||||
"requests_per_day": "Till\u00e5tna f\u00f6rfr\u00e5gningar per dag",
|
||||
"requests_remaining": "\u00c5terst\u00e5ende till\u00e5tna f\u00f6rfr\u00e5gningar"
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
)
|
||||
@ -73,6 +72,8 @@ async def async_setup_entry(
|
||||
class AirNowSensor(CoordinatorEntity[AirNowDataUpdateCoordinator], SensorEntity):
|
||||
"""Define an AirNow sensor."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirNowDataUpdateCoordinator,
|
||||
@ -82,7 +83,7 @@ class AirNowSensor(CoordinatorEntity[AirNowDataUpdateCoordinator], SensorEntity)
|
||||
super().__init__(coordinator)
|
||||
self.entity_description = description
|
||||
self._state = None
|
||||
self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||
self._attrs: dict[str, str] = {}
|
||||
self._attr_name = f"AirNow {description.name}"
|
||||
self._attr_unique_id = (
|
||||
f"{coordinator.latitude}-{coordinator.longitude}-{description.key.lower()}"
|
||||
|
@ -17,7 +17,7 @@
|
||||
"longitude": "Longitud",
|
||||
"radius": "Radio de la estaci\u00f3n (millas; opcional)"
|
||||
},
|
||||
"description": "Configurar la integraci\u00f3n de calidad del aire de AirNow. Para generar una clave API, ve a https://docs.airnowapi.org/account/request/"
|
||||
"description": "Para generar la clave API, ve a https://docs.airnowapi.org/account/request/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,23 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"invalid_auth": "Ogiltig autentisering",
|
||||
"invalid_location": "Inga resultat hittades f\u00f6r den platsen",
|
||||
"unknown": "Ov\u00e4ntat fel"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "API-nyckel"
|
||||
}
|
||||
"api_key": "API-nyckel",
|
||||
"latitude": "Latitud",
|
||||
"longitude": "Longitud",
|
||||
"radius": "Stationsradie (miles; valfritt)"
|
||||
},
|
||||
"description": "F\u00f6r att generera API-nyckel g\u00e5 till https://docs.airnowapi.org/account/request/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"description": "Inicie sesi\u00f3n en {url} para encontrar sus credenciales",
|
||||
"description": "Inicia sesi\u00f3n en {url} para encontrar tus credenciales",
|
||||
"id": "ID",
|
||||
"secret": "Secreto"
|
||||
}
|
||||
|
21
homeassistant/components/airthings/translations/sv.json
Normal file
21
homeassistant/components/airthings/translations/sv.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Konto har redan konfigurerats"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"invalid_auth": "Ogiltig autentisering",
|
||||
"unknown": "Ov\u00e4ntat fel"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"description": "Logga in p\u00e5 {url} f\u00f6r att hitta dina autentiseringsuppgifter",
|
||||
"id": "ID",
|
||||
"secret": "Hemlighet"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.climate import ClimateEntity
|
||||
from homeassistant.components.climate.const import (
|
||||
@ -154,7 +155,7 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
|
||||
modes.append(HVACMode.OFF)
|
||||
return modes
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new operation mode."""
|
||||
if hvac_mode not in HA_STATE_TO_AT:
|
||||
raise ValueError(f"Unsupported HVAC mode: {hvac_mode}")
|
||||
@ -170,7 +171,7 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
|
||||
_LOGGER.debug("Setting operation mode of %s to %s", self._ac_number, hvac_mode)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode):
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new fan mode."""
|
||||
if fan_mode not in self.fan_modes:
|
||||
raise ValueError(f"Unsupported fan mode: {fan_mode}")
|
||||
@ -182,14 +183,14 @@ class AirtouchAC(CoordinatorEntity, ClimateEntity):
|
||||
self._unit = self._airtouch.GetAcs()[self._ac_number]
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_on(self):
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn on."""
|
||||
_LOGGER.debug("Turning %s on", self.unique_id)
|
||||
# in case ac is not on. Airtouch turns itself off if no groups are turned on
|
||||
# (even if groups turned back on)
|
||||
await self._airtouch.TurnAcOn(self._ac_number)
|
||||
|
||||
async def async_turn_off(self):
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn off."""
|
||||
_LOGGER.debug("Turning %s off", self.unique_id)
|
||||
await self._airtouch.TurnAcOff(self._ac_number)
|
||||
@ -266,7 +267,7 @@ class AirtouchGroup(CoordinatorEntity, ClimateEntity):
|
||||
|
||||
return HVACMode.FAN_ONLY
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new operation mode."""
|
||||
if hvac_mode not in HA_STATE_TO_AT:
|
||||
raise ValueError(f"Unsupported HVAC mode: {hvac_mode}")
|
||||
@ -294,9 +295,11 @@ class AirtouchGroup(CoordinatorEntity, ClimateEntity):
|
||||
)
|
||||
return [AT_TO_HA_FAN_SPEED[speed] for speed in airtouch_fan_speeds]
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperatures."""
|
||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
if (temp := kwargs.get(ATTR_TEMPERATURE)) is None:
|
||||
_LOGGER.debug("Argument `temperature` is missing in set_temperature")
|
||||
return
|
||||
|
||||
_LOGGER.debug("Setting temp of %s to %s", self._group_number, str(temp))
|
||||
self._unit = await self._airtouch.SetGroupToTemperature(
|
||||
@ -304,7 +307,7 @@ class AirtouchGroup(CoordinatorEntity, ClimateEntity):
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode):
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new fan mode."""
|
||||
if fan_mode not in self.fan_modes:
|
||||
raise ValueError(f"Unsupported fan mode: {fan_mode}")
|
||||
@ -315,7 +318,7 @@ class AirtouchGroup(CoordinatorEntity, ClimateEntity):
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_on(self):
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn on."""
|
||||
_LOGGER.debug("Turning %s on", self.unique_id)
|
||||
await self._airtouch.TurnGroupOn(self._group_number)
|
||||
@ -330,7 +333,7 @@ class AirtouchGroup(CoordinatorEntity, ClimateEntity):
|
||||
await self.coordinator.async_request_refresh()
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self):
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn off."""
|
||||
_LOGGER.debug("Turning %s off", self.unique_id)
|
||||
await self._airtouch.TurnGroupOff(self._group_number)
|
||||
|
@ -12,7 +12,7 @@
|
||||
"data": {
|
||||
"host": "Host"
|
||||
},
|
||||
"title": "Configura los detalles de conexi\u00f3n de tu AirTouch 4."
|
||||
"title": "Configurar los detalles de conexi\u00f3n de tu AirTouch 4."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
homeassistant/components/airtouch4/translations/sv.json
Normal file
19
homeassistant/components/airtouch4/translations/sv.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"no_units": "Det gick inte att hitta n\u00e5gra AirTouch 4-grupper."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "V\u00e4rd"
|
||||
},
|
||||
"title": "St\u00e4ll in dina AirTouch 4-anslutningsdetaljer."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"general_error": "Se ha producido un error desconocido.",
|
||||
"general_error": "Error inesperado",
|
||||
"invalid_api_key": "Clave API no v\u00e1lida",
|
||||
"location_not_found": "Ubicaci\u00f3n no encontrada"
|
||||
},
|
||||
@ -17,7 +17,7 @@
|
||||
"latitude": "Latitud",
|
||||
"longitude": "Longitud"
|
||||
},
|
||||
"description": "Utilice la API de la nube de AirVisual para supervisar una latitud/longitud.",
|
||||
"description": "Usar la API de la nube de AirVisual para supervisar una latitud/longitud.",
|
||||
"title": "Configurar una geograf\u00eda"
|
||||
},
|
||||
"geography_by_name": {
|
||||
@ -27,7 +27,7 @@
|
||||
"country": "Pa\u00eds",
|
||||
"state": "estado"
|
||||
},
|
||||
"description": "Utilice la API de la nube de AirVisual para supervisar una ciudad/estado/pa\u00eds.",
|
||||
"description": "Usar la API de la nube de AirVisual para supervisar una ciudad/estado/pa\u00eds.",
|
||||
"title": "Configurar una geograf\u00eda"
|
||||
},
|
||||
"node_pro": {
|
||||
@ -35,7 +35,7 @@
|
||||
"ip_address": "Host",
|
||||
"password": "Contrase\u00f1a"
|
||||
},
|
||||
"description": "Monitorizar una unidad personal AirVisual. La contrase\u00f1a puede ser recuperada desde la interfaz de la unidad.",
|
||||
"description": "Supervisar una unidad AirVisual personal. La contrase\u00f1a se puede recuperar desde la IU de la unidad.",
|
||||
"title": "Configurar un AirVisual Node/Pro"
|
||||
},
|
||||
"reauth_confirm": {
|
||||
@ -45,7 +45,7 @@
|
||||
"title": "Volver a autenticar AirVisual"
|
||||
},
|
||||
"user": {
|
||||
"description": "Elige qu\u00e9 tipo de datos de AirVisual quieres monitorizar.",
|
||||
"description": "Elige qu\u00e9 tipo de datos de AirVisual quieres supervisar.",
|
||||
"title": "Configurar AirVisual"
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,7 @@
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"show_on_map": "Mostrar geograf\u00eda monitorizada en el mapa"
|
||||
"show_on_map": "Mostrar geograf\u00eda supervisada en el mapa"
|
||||
},
|
||||
"title": "Configurar AirVisual"
|
||||
}
|
||||
|
@ -12,8 +12,8 @@
|
||||
"good": "Bueno",
|
||||
"hazardous": "Da\u00f1ino",
|
||||
"moderate": "Moderado",
|
||||
"unhealthy": "Insalubre",
|
||||
"unhealthy_sensitive": "Insalubre para grupos sensibles",
|
||||
"unhealthy": "Poco saludable",
|
||||
"unhealthy_sensitive": "Poco saludable para grupos sensibles",
|
||||
"very_unhealthy": "Muy poco saludable"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,20 @@
|
||||
{
|
||||
"state": {
|
||||
"airvisual__pollutant_label": {
|
||||
"co": "Kolmonoxid"
|
||||
"co": "Kolmonoxid",
|
||||
"n2": "Kv\u00e4vedioxid",
|
||||
"o3": "Ozon",
|
||||
"p1": "PM10",
|
||||
"p2": "PM2,5",
|
||||
"s2": "Svaveldioxid"
|
||||
},
|
||||
"airvisual__pollutant_level": {
|
||||
"good": "Bra",
|
||||
"hazardous": "Farlig",
|
||||
"moderate": "M\u00e5ttlig",
|
||||
"unhealthy": "Oh\u00e4lsosam",
|
||||
"unhealthy_sensitive": "Oh\u00e4lsosamt f\u00f6r k\u00e4nsliga grupper",
|
||||
"very_unhealthy": "Mycket oh\u00e4lsosamt"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,61 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Platsen \u00e4r redan konfigurerad eller Node/Pro ID \u00e4r redan regristrerat.",
|
||||
"reauth_successful": "\u00c5terautentisering lyckades"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"general_error": "Ett ok\u00e4nt fel intr\u00e4ffade.",
|
||||
"invalid_api_key": "Ogiltig API-nyckel"
|
||||
"invalid_api_key": "Ogiltig API-nyckel",
|
||||
"location_not_found": "Platsen hittades inte"
|
||||
},
|
||||
"step": {
|
||||
"geography_by_coords": {
|
||||
"data": {
|
||||
"api_key": "API-nyckel",
|
||||
"latitude": "Latitud",
|
||||
"longitude": "Longitud"
|
||||
},
|
||||
"description": "Anv\u00e4nd AirVisuals moln-API f\u00f6r att \u00f6vervaka en latitud/longitud.",
|
||||
"title": "Konfigurera en geografi"
|
||||
},
|
||||
"geography_by_name": {
|
||||
"data": {
|
||||
"api_key": "API-nyckel"
|
||||
}
|
||||
"api_key": "API-nyckel",
|
||||
"city": "Stad",
|
||||
"country": "Land",
|
||||
"state": "stat"
|
||||
},
|
||||
"description": "Anv\u00e4nd AirVisuals moln-API f\u00f6r att \u00f6vervaka en stad/stat/land.",
|
||||
"title": "Konfigurera en geografi"
|
||||
},
|
||||
"node_pro": {
|
||||
"data": {
|
||||
"ip_address": "Enhets IP-adress / v\u00e4rdnamn",
|
||||
"password": "Enhetsl\u00f6senord"
|
||||
}
|
||||
},
|
||||
"description": "\u00d6vervaka en personlig AirVisual-enhet. L\u00f6senordet kan h\u00e4mtas fr\u00e5n enhetens anv\u00e4ndargr\u00e4nssnitt.",
|
||||
"title": "Konfigurera en AirVisual Node/Pro"
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"data": {
|
||||
"api_key": "API-nyckel"
|
||||
},
|
||||
"title": "Autentisera AirVisual igen"
|
||||
},
|
||||
"user": {
|
||||
"description": "V\u00e4lj typ av AirVisual data att \u00f6vervaka.",
|
||||
"title": "Konfigurera AirVisual"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"show_on_map": "Visa \u00f6vervakad geografi p\u00e5 kartan"
|
||||
},
|
||||
"title": "Konfigurera AirVisual"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Airzone",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone",
|
||||
"requirements": ["aioairzone==0.4.6"],
|
||||
"requirements": ["aioairzone==0.4.8"],
|
||||
"codeowners": ["@Noltari"],
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairzone"]
|
||||
|
12
homeassistant/components/airzone/translations/es-419.json
Normal file
12
homeassistant/components/airzone/translations/es-419.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"config": {
|
||||
"error": {
|
||||
"invalid_system_id": "ID del sistema Airzone no v\u00e1lido"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"description": "Configurar la integraci\u00f3n de Airzone."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
"already_configured": "El dispositivo ya est\u00e1 configurado"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Fall\u00f3 la conexi\u00f3n",
|
||||
"invalid_system_id": "ID de sistema Airzone inv\u00e1lido"
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"invalid_system_id": "ID del sistema Airzone no v\u00e1lido"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
|
20
homeassistant/components/airzone/translations/sv.json
Normal file
20
homeassistant/components/airzone/translations/sv.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta.",
|
||||
"invalid_system_id": "Ogiltigt Airzone System ID"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "V\u00e4rd",
|
||||
"port": "Port"
|
||||
},
|
||||
"description": "St\u00e4ll in Airzone-integration."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,6 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> None:
|
||||
CLIENT_ID,
|
||||
)
|
||||
login = await acc.login()
|
||||
await acc.close()
|
||||
if not login:
|
||||
raise InvalidAuth
|
||||
|
||||
|
@ -111,7 +111,7 @@ class AladdinDevice(CoverEntity):
|
||||
"""Schedule a state update."""
|
||||
self.async_write_ha_state()
|
||||
|
||||
self._acc.register_callback(update_callback, self._serial)
|
||||
self._acc.register_callback(update_callback, self._serial, self._number)
|
||||
await self._acc.get_doors(self._serial)
|
||||
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "aladdin_connect",
|
||||
"name": "Aladdin Connect",
|
||||
"documentation": "https://www.home-assistant.io/integrations/aladdin_connect",
|
||||
"requirements": ["AIOAladdinConnect==0.1.41"],
|
||||
"requirements": ["AIOAladdinConnect==0.1.44"],
|
||||
"codeowners": ["@mkmer"],
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["aladdin_connect"],
|
||||
|
@ -83,7 +83,7 @@ async def async_setup_entry(
|
||||
[AladdinConnectSensor(acc, door, description) for description in SENSORS]
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class AladdinConnectSensor(SensorEntity):
|
||||
|
@ -2,10 +2,10 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "El dispositivo ya est\u00e1 configurado",
|
||||
"reauth_successful": "La reautenticaci\u00f3n fue exitosa"
|
||||
"reauth_successful": "La reautenticaci\u00f3n se realiz\u00f3 correctamente"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Error al conectar",
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"invalid_auth": "Autenticaci\u00f3n no v\u00e1lida"
|
||||
},
|
||||
"step": {
|
||||
@ -13,8 +13,8 @@
|
||||
"data": {
|
||||
"password": "Contrase\u00f1a"
|
||||
},
|
||||
"description": "La integraci\u00f3n de Aladdin Connect necesita volver a autenticar su cuenta",
|
||||
"title": "Reautenticaci\u00f3n de la integraci\u00f3n"
|
||||
"description": "La integraci\u00f3n Aladdin Connect necesita volver a autenticar tu cuenta",
|
||||
"title": "Volver a autenticar la integraci\u00f3n"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
|
@ -13,6 +13,7 @@
|
||||
"data": {
|
||||
"password": "L\u00f6senord"
|
||||
},
|
||||
"description": "Aladdin Connect-integrationen m\u00e5ste autentisera ditt konto igen",
|
||||
"title": "\u00c5terautenticera integration"
|
||||
},
|
||||
"user": {
|
||||
|
@ -5,10 +5,6 @@ from typing import Final
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.automation import (
|
||||
AutomationActionType,
|
||||
AutomationTriggerInfo,
|
||||
)
|
||||
from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
|
||||
from homeassistant.components.homeassistant.triggers import state as state_trigger
|
||||
from homeassistant.const import (
|
||||
@ -29,6 +25,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from . import DOMAIN
|
||||
@ -131,8 +128,8 @@ async def async_get_trigger_capabilities(
|
||||
async def async_attach_trigger(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
action: AutomationActionType,
|
||||
automation_info: AutomationTriggerInfo,
|
||||
action: TriggerActionType,
|
||||
trigger_info: TriggerInfo,
|
||||
) -> CALLBACK_TYPE:
|
||||
"""Attach a trigger."""
|
||||
if config[CONF_TYPE] == "triggered":
|
||||
@ -159,5 +156,5 @@ async def async_attach_trigger(
|
||||
state_config[CONF_FOR] = config[CONF_FOR]
|
||||
state_config = await state_trigger.async_validate_trigger_config(hass, state_config)
|
||||
return await state_trigger.async_attach_trigger(
|
||||
hass, state_config, action, automation_info, platform_type="device"
|
||||
hass, state_config, action, trigger_info, platform_type="device"
|
||||
)
|
||||
|
@ -1,18 +1,18 @@
|
||||
{
|
||||
"device_automation": {
|
||||
"action_type": {
|
||||
"arm_away": "Armar {entity_name} exterior",
|
||||
"arm_home": "Armar {entity_name} modo casa",
|
||||
"arm_night": "Armar {entity_name} por la noche",
|
||||
"arm_vacation": "Armar las vacaciones de {entity_name}",
|
||||
"arm_away": "Armar ausente en {entity_name}",
|
||||
"arm_home": "Armar en casa en {entity_name}",
|
||||
"arm_night": "Armar noche en {entity_name}",
|
||||
"arm_vacation": "Armar de vacaciones {entity_name}",
|
||||
"disarm": "Desarmar {entity_name}",
|
||||
"trigger": "Lanzar {entity_name}"
|
||||
"trigger": "Disparar {entity_name}"
|
||||
},
|
||||
"condition_type": {
|
||||
"is_armed_away": "{entity_name} est\u00e1 armada ausente",
|
||||
"is_armed_home": "{entity_name} est\u00e1 armada en casa",
|
||||
"is_armed_night": "{entity_name} est\u00e1 armada noche",
|
||||
"is_armed_vacation": "{entity_name} est\u00e1 armado de vacaciones",
|
||||
"is_armed_vacation": "{entity_name} est\u00e1 armada de vacaciones",
|
||||
"is_disarmed": "{entity_name} est\u00e1 desarmada",
|
||||
"is_triggered": "{entity_name} est\u00e1 disparada"
|
||||
},
|
||||
@ -20,9 +20,9 @@
|
||||
"armed_away": "{entity_name} armada ausente",
|
||||
"armed_home": "{entity_name} armada en casa",
|
||||
"armed_night": "{entity_name} armada noche",
|
||||
"armed_vacation": "Vacaciones armadas de {entity_name}",
|
||||
"armed_vacation": "{entity_name} en armada de vacaciones",
|
||||
"disarmed": "{entity_name} desarmada",
|
||||
"triggered": "{entity_name} activado"
|
||||
"triggered": "{entity_name} disparada"
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
@ -32,7 +32,7 @@
|
||||
"armed_custom_bypass": "Armada personalizada",
|
||||
"armed_home": "Armada en casa",
|
||||
"armed_night": "Armada noche",
|
||||
"armed_vacation": "Vacaciones armadas",
|
||||
"armed_vacation": "Armada de vacaciones",
|
||||
"arming": "Armando",
|
||||
"disarmed": "Desarmada",
|
||||
"disarming": "Desarmando",
|
||||
|
@ -4,16 +4,23 @@
|
||||
"arm_away": "Larma {entity_name} borta",
|
||||
"arm_home": "Larma {entity_name} hemma",
|
||||
"arm_night": "Larma {entity_name} natt",
|
||||
"arm_vacation": "Larma semesterl\u00e4ge {entity_name}",
|
||||
"disarm": "Avlarma {entity_name}",
|
||||
"trigger": "Utl\u00f6sare {entity_name}"
|
||||
},
|
||||
"condition_type": {
|
||||
"is_armed_away": "{entity_name} \u00e4r bortalarmat",
|
||||
"is_armed_home": "{entity_name} \u00e4r hemmalarmat",
|
||||
"is_armed_night": "{entity_name} \u00e4r nattlarmat",
|
||||
"is_armed_vacation": "{entity_name} \u00e4r larmad i semesterl\u00e4ge",
|
||||
"is_disarmed": "{entity_name} \u00e4r bortkopplad",
|
||||
"is_triggered": "har utl\u00f6sts"
|
||||
},
|
||||
"trigger_type": {
|
||||
"armed_away": "{entity_name} larmad borta",
|
||||
"armed_home": "{entity_name} larmad hemma",
|
||||
"armed_night": "{entity_name} larmad natt",
|
||||
"armed_vacation": "{entity_name} larmad i semesterl\u00e4ge",
|
||||
"disarmed": "{entity_name} bortkopplad",
|
||||
"triggered": "{entity_name} utl\u00f6st"
|
||||
}
|
||||
@ -25,6 +32,7 @@
|
||||
"armed_custom_bypass": "Larm f\u00f6rbikopplat",
|
||||
"armed_home": "Hemmalarmat",
|
||||
"armed_night": "Nattlarmat",
|
||||
"armed_vacation": "Larmad semesterl\u00e4ge",
|
||||
"arming": "Tillkopplar",
|
||||
"disarmed": "Avlarmat",
|
||||
"disarming": "Fr\u00e5nkopplar",
|
||||
|
@ -29,6 +29,7 @@
|
||||
"armed_custom_bypass": "\u041e\u0445\u043e\u0440\u043e\u043d\u0430 \u0437 \u0432\u0438\u043d\u044f\u0442\u043a\u0430\u043c\u0438",
|
||||
"armed_home": "\u041e\u0445\u043e\u0440\u043e\u043d\u0430 (\u0412\u0434\u043e\u043c\u0430)",
|
||||
"armed_night": "\u041d\u0456\u0447\u043d\u0430 \u043e\u0445\u043e\u0440\u043e\u043d\u0430",
|
||||
"armed_vacation": "\u041e\u0445\u043e\u0440\u043e\u043d\u0430 (\u0432\u0456\u0434\u043f\u0443\u0441\u0442\u043a\u0430)",
|
||||
"arming": "\u0421\u0442\u0430\u0432\u043b\u044e \u043d\u0430 \u043e\u0445\u043e\u0440\u043e\u043d\u0443",
|
||||
"disarmed": "\u0417\u043d\u044f\u0442\u043e \u0437 \u043e\u0445\u043e\u0440\u043e\u043d\u0438",
|
||||
"disarming": "\u0417\u043d\u044f\u0442\u0442\u044f",
|
||||
|
@ -88,7 +88,7 @@ class AlarmDecoderBinarySensor(BinarySensorEntity):
|
||||
CONF_ZONE_NUMBER: self._zone_number,
|
||||
}
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(self.hass, SIGNAL_ZONE_FAULT, self._fault_callback)
|
||||
|
@ -24,7 +24,7 @@ class AlarmDecoderSensor(SensorEntity):
|
||||
_attr_name = "Alarm Panel Display"
|
||||
_attr_should_poll = False
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
|
@ -23,23 +23,23 @@
|
||||
"data": {
|
||||
"protocol": "Protocolo"
|
||||
},
|
||||
"title": "Elige el protocolo del AlarmDecoder"
|
||||
"title": "Elige el protocolo AlarmDecoder"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"error": {
|
||||
"int": "El campo siguiente debe ser un n\u00famero entero.",
|
||||
"loop_range": "El bucle RF debe ser un n\u00famero entero entre 1 y 4.",
|
||||
"loop_rfid": "El bucle de RF no puede utilizarse sin el serie RF.",
|
||||
"relay_inclusive": "La direcci\u00f3n de retransmisi\u00f3n y el canal de retransmisi\u00f3n son codependientes y deben incluirse a la vez."
|
||||
"int": "El siguiente campo debe ser un n\u00famero entero.",
|
||||
"loop_range": "RF Loop debe ser un n\u00famero entero entre 1 y 4.",
|
||||
"loop_rfid": "RF Loop no se puede utilizar sin RF Serial.",
|
||||
"relay_inclusive": "La direcci\u00f3n de retransmisi\u00f3n y el canal de retransmisi\u00f3n son c\u00f3digopendientes y deben incluirse a la vez."
|
||||
},
|
||||
"step": {
|
||||
"arm_settings": {
|
||||
"data": {
|
||||
"alt_night_mode": "Modo noche alternativo",
|
||||
"auto_bypass": "Desv\u00edo autom\u00e1tico al armar",
|
||||
"code_arm_required": "C\u00f3digo requerido para el armado"
|
||||
"alt_night_mode": "Modo nocturno alternativo",
|
||||
"auto_bypass": "Anulaci\u00f3n autom\u00e1tica en armado",
|
||||
"code_arm_required": "C\u00f3digo Requerido para Armar"
|
||||
},
|
||||
"title": "Configurar AlarmDecoder"
|
||||
},
|
||||
@ -52,14 +52,14 @@
|
||||
},
|
||||
"zone_details": {
|
||||
"data": {
|
||||
"zone_loop": "Bucle RF",
|
||||
"zone_loop": "RF Loop",
|
||||
"zone_name": "Nombre de zona",
|
||||
"zone_relayaddr": "Direcci\u00f3n de retransmisi\u00f3n",
|
||||
"zone_relaychan": "Canal de retransmisi\u00f3n",
|
||||
"zone_rfid": "Serie RF",
|
||||
"zone_rfid": "RF Serial",
|
||||
"zone_type": "Tipo de zona"
|
||||
},
|
||||
"description": "Introduce los detalles para la zona {zona_number}. Para borrar la zona {zone_number}, deja el nombre de la zona en blanco.",
|
||||
"description": "Introduce los detalles para la zona {zone_number}. Para eliminar la zona {zone_number}, deja el nombre de la zona en blanco.",
|
||||
"title": "Configurar AlarmDecoder"
|
||||
},
|
||||
"zone_select": {
|
||||
|
@ -1,26 +1,73 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten \u00e4r redan konfigurerad"
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "Ansluten till AlarmDecoder."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Det gick inte att ansluta."
|
||||
},
|
||||
"step": {
|
||||
"protocol": {
|
||||
"data": {
|
||||
"device_path": "Enhetsv\u00e4g"
|
||||
"device_baudrate": "Enhetens Baud Rate",
|
||||
"device_path": "Enhetsv\u00e4g",
|
||||
"host": "V\u00e4rd",
|
||||
"port": "Port"
|
||||
},
|
||||
"title": "Konfigurera anslutningsinst\u00e4llningar"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"protocol": "Protokoll"
|
||||
}
|
||||
},
|
||||
"title": "V\u00e4lj AlarmDecoder Protocol"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"error": {
|
||||
"int": "F\u00e4ltet nedan m\u00e5ste vara ett heltal.",
|
||||
"loop_range": "RF Loop m\u00e5ste vara ett heltal mellan 1 och 4.",
|
||||
"loop_rfid": "RF Loop kan inte anv\u00e4ndas utan RF Serial.",
|
||||
"relay_inclusive": "Rel\u00e4adress och rel\u00e4kanal \u00e4r beroende av varandra och m\u00e5ste inkluderas tillsammans."
|
||||
},
|
||||
"step": {
|
||||
"arm_settings": {
|
||||
"data": {
|
||||
"alt_night_mode": "Alternativt nattl\u00e4ge",
|
||||
"auto_bypass": "Automatisk f\u00f6rbikoppling p\u00e5 arm",
|
||||
"code_arm_required": "Kod kr\u00e4vs f\u00f6r tillkoppling"
|
||||
},
|
||||
"title": "Konfigurera AlarmDecoder"
|
||||
},
|
||||
"init": {
|
||||
"data": {
|
||||
"edit_select": "Redigera"
|
||||
},
|
||||
"description": "Vad vill du redigera?"
|
||||
"description": "Vad vill du redigera?",
|
||||
"title": "Konfigurera AlarmDecoder"
|
||||
},
|
||||
"zone_details": {
|
||||
"data": {
|
||||
"zone_loop": "RF loop",
|
||||
"zone_name": "Zonnamn",
|
||||
"zone_relayaddr": "Rel\u00e4adress",
|
||||
"zone_relaychan": "Rel\u00e4kanal",
|
||||
"zone_rfid": "RF seriell",
|
||||
"zone_type": "Zontyp"
|
||||
},
|
||||
"description": "Ange detaljer f\u00f6r zon {zone_number} . F\u00f6r att ta bort zon {zone_number} l\u00e4mnar du Zonnamn tomt.",
|
||||
"title": "Konfigurera AlarmDecoder"
|
||||
},
|
||||
"zone_select": {
|
||||
"data": {
|
||||
"zone_number": "Zonnummer"
|
||||
},
|
||||
"description": "Ange zonnumret du vill l\u00e4gga till, redigera eller ta bort.",
|
||||
"title": "Konfigurera AlarmDecoder"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -269,6 +269,7 @@ class Alexa(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -277,10 +278,13 @@ class Alexa(AlexaCapability):
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
@ -295,6 +299,7 @@ class AlexaEndpointHealth(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -302,9 +307,14 @@ class AlexaEndpointHealth(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def __init__(self, hass, entity):
|
||||
@ -345,6 +355,7 @@ class AlexaPowerController(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -352,9 +363,14 @@ class AlexaPowerController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
@ -379,7 +395,7 @@ class AlexaPowerController(AlexaCapability):
|
||||
raise UnsupportedProperty(name)
|
||||
|
||||
if self.entity.domain == climate.DOMAIN:
|
||||
is_on = self.entity.state != climate.HVAC_MODE_OFF
|
||||
is_on = self.entity.state != climate.HVACMode.OFF
|
||||
elif self.entity.domain == fan.DOMAIN:
|
||||
is_on = self.entity.state == fan.STATE_ON
|
||||
elif self.entity.domain == vacuum.DOMAIN:
|
||||
@ -400,6 +416,7 @@ class AlexaLockController(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -461,9 +478,14 @@ class AlexaSceneController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def __init__(self, entity, supports_deactivation):
|
||||
@ -483,6 +505,7 @@ class AlexaBrightnessController(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -490,6 +513,9 @@ class AlexaBrightnessController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
@ -536,6 +562,9 @@ class AlexaColorController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
@ -587,6 +616,9 @@ class AlexaColorTemperatureController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
@ -635,9 +667,13 @@ class AlexaPercentageController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
@ -758,7 +794,24 @@ class AlexaPlaybackController(AlexaCapability):
|
||||
https://developer.amazon.com/docs/device-apis/alexa-playbackcontroller.html
|
||||
"""
|
||||
|
||||
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US", "fr-FR"}
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
"""Return the Alexa API name of this interface."""
|
||||
@ -792,7 +845,24 @@ class AlexaInputController(AlexaCapability):
|
||||
https://developer.amazon.com/docs/device-apis/alexa-inputcontroller.html
|
||||
"""
|
||||
|
||||
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US"}
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
"""Return the Alexa API name of this interface."""
|
||||
@ -830,6 +900,7 @@ class AlexaTemperatureSensor(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -837,9 +908,14 @@ class AlexaTemperatureSensor(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def __init__(self, hass, entity):
|
||||
@ -901,12 +977,18 @@ class AlexaContactSensor(AlexaCapability):
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"en-GB",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def __init__(self, hass, entity):
|
||||
@ -950,10 +1032,15 @@ class AlexaMotionSensor(AlexaCapability):
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"en-GB",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
@ -997,6 +1084,7 @@ class AlexaThermostatController(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -1004,7 +1092,11 @@ class AlexaThermostatController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
@ -1127,6 +1219,8 @@ class AlexaPowerLevelController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
@ -1260,10 +1354,13 @@ class AlexaModeController(AlexaCapability):
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def __init__(self, entity, instance, non_controllable=False):
|
||||
@ -1446,10 +1543,13 @@ class AlexaRangeController(AlexaCapability):
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def __init__(self, entity, instance, non_controllable=False):
|
||||
@ -1691,8 +1791,10 @@ class AlexaToggleController(AlexaCapability):
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
@ -1753,6 +1855,7 @@ class AlexaChannelController(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -1761,6 +1864,8 @@ class AlexaChannelController(AlexaCapability):
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
@ -1780,6 +1885,7 @@ class AlexaDoorbellEventSource(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -1794,6 +1900,7 @@ class AlexaDoorbellEventSource(AlexaCapability):
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
@ -1811,7 +1918,24 @@ class AlexaPlaybackStateReporter(AlexaCapability):
|
||||
https://developer.amazon.com/docs/device-apis/alexa-playbackstatereporter.html
|
||||
"""
|
||||
|
||||
supported_locales = {"de-DE", "en-GB", "en-US", "es-MX", "fr-FR"}
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
"""Return the Alexa API name of this interface."""
|
||||
@ -1849,7 +1973,24 @@ class AlexaSeekController(AlexaCapability):
|
||||
https://developer.amazon.com/docs/device-apis/alexa-seekcontroller.html
|
||||
"""
|
||||
|
||||
supported_locales = {"de-DE", "en-GB", "en-US", "es-MX"}
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
def name(self):
|
||||
"""Return the Alexa API name of this interface."""
|
||||
@ -1925,7 +2066,24 @@ class AlexaEqualizerController(AlexaCapability):
|
||||
https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-equalizercontroller.html
|
||||
"""
|
||||
|
||||
supported_locales = {"de-DE", "en-IN", "en-US", "es-ES", "it-IT", "ja-JP", "pt-BR"}
|
||||
supported_locales = {
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"pt-BR",
|
||||
}
|
||||
|
||||
VALID_SOUND_MODES = {
|
||||
"MOVIE",
|
||||
"MUSIC",
|
||||
@ -2017,6 +2175,7 @@ class AlexaCameraStreamController(AlexaCapability):
|
||||
"""
|
||||
|
||||
supported_locales = {
|
||||
"ar-SA",
|
||||
"de-DE",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
@ -2024,6 +2183,9 @@ class AlexaCameraStreamController(AlexaCapability):
|
||||
"en-IN",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-US",
|
||||
"fr-CA",
|
||||
"fr-FR",
|
||||
"hi-IN",
|
||||
"it-IT",
|
||||
|
@ -460,7 +460,7 @@ class ClimateCapabilities(AlexaEntity):
|
||||
def interfaces(self):
|
||||
"""Yield the supported interfaces."""
|
||||
# If we support two modes, one being off, we allow turning on too.
|
||||
if climate.HVAC_MODE_OFF in self.entity.attributes.get(
|
||||
if climate.HVACMode.OFF in self.entity.attributes.get(
|
||||
climate.ATTR_HVAC_MODES, []
|
||||
):
|
||||
yield AlexaPowerController(self.entity)
|
||||
|
@ -1,6 +1,10 @@
|
||||
"""Alexa message handlers."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Coroutine
|
||||
import logging
|
||||
import math
|
||||
from typing import Any
|
||||
|
||||
from homeassistant import core as ha
|
||||
from homeassistant.components import (
|
||||
@ -51,6 +55,7 @@ from homeassistant.util.decorator import Registry
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.util.temperature import convert as convert_temperature
|
||||
|
||||
from .config import AbstractConfig
|
||||
from .const import (
|
||||
API_TEMP_UNITS,
|
||||
API_THERMOSTAT_MODES,
|
||||
@ -70,14 +75,27 @@ from .errors import (
|
||||
AlexaUnsupportedThermostatModeError,
|
||||
AlexaVideoActionNotPermittedForContentError,
|
||||
)
|
||||
from .messages import AlexaDirective, AlexaResponse
|
||||
from .state_report import async_enable_proactive_mode
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
HANDLERS = Registry() # type: ignore[var-annotated]
|
||||
DIRECTIVE_NOT_SUPPORTED = "Entity does not support directive"
|
||||
HANDLERS: Registry[
|
||||
tuple[str, str],
|
||||
Callable[
|
||||
[ha.HomeAssistant, AbstractConfig, AlexaDirective, ha.Context],
|
||||
Coroutine[Any, Any, AlexaResponse],
|
||||
],
|
||||
] = Registry()
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.Discovery", "Discover"))
|
||||
async def async_api_discovery(hass, config, directive, context):
|
||||
async def async_api_discovery(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Create a API formatted discovery response.
|
||||
|
||||
Async friendly.
|
||||
@ -96,7 +114,12 @@ async def async_api_discovery(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.Authorization", "AcceptGrant"))
|
||||
async def async_api_accept_grant(hass, config, directive, context):
|
||||
async def async_api_accept_grant(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Create a API formatted AcceptGrant response.
|
||||
|
||||
Async friendly.
|
||||
@ -116,7 +139,12 @@ async def async_api_accept_grant(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PowerController", "TurnOn"))
|
||||
async def async_api_turn_on(hass, config, directive, context):
|
||||
async def async_api_turn_on(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a turn on request."""
|
||||
entity = directive.entity
|
||||
if (domain := entity.domain) == group.DOMAIN:
|
||||
@ -157,7 +185,12 @@ async def async_api_turn_on(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PowerController", "TurnOff"))
|
||||
async def async_api_turn_off(hass, config, directive, context):
|
||||
async def async_api_turn_off(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a turn off request."""
|
||||
entity = directive.entity
|
||||
domain = entity.domain
|
||||
@ -199,7 +232,12 @@ async def async_api_turn_off(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.BrightnessController", "SetBrightness"))
|
||||
async def async_api_set_brightness(hass, config, directive, context):
|
||||
async def async_api_set_brightness(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set brightness request."""
|
||||
entity = directive.entity
|
||||
brightness = int(directive.payload["brightness"])
|
||||
@ -216,7 +254,12 @@ async def async_api_set_brightness(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.BrightnessController", "AdjustBrightness"))
|
||||
async def async_api_adjust_brightness(hass, config, directive, context):
|
||||
async def async_api_adjust_brightness(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an adjust brightness request."""
|
||||
entity = directive.entity
|
||||
brightness_delta = int(directive.payload["brightnessDelta"])
|
||||
@ -237,7 +280,12 @@ async def async_api_adjust_brightness(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ColorController", "SetColor"))
|
||||
async def async_api_set_color(hass, config, directive, context):
|
||||
async def async_api_set_color(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set color request."""
|
||||
entity = directive.entity
|
||||
rgb = color_util.color_hsb_to_RGB(
|
||||
@ -258,7 +306,12 @@ async def async_api_set_color(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ColorTemperatureController", "SetColorTemperature"))
|
||||
async def async_api_set_color_temperature(hass, config, directive, context):
|
||||
async def async_api_set_color_temperature(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set color temperature request."""
|
||||
entity = directive.entity
|
||||
kelvin = int(directive.payload["colorTemperatureInKelvin"])
|
||||
@ -275,7 +328,12 @@ async def async_api_set_color_temperature(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ColorTemperatureController", "DecreaseColorTemperature"))
|
||||
async def async_api_decrease_color_temp(hass, config, directive, context):
|
||||
async def async_api_decrease_color_temp(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a decrease color temperature request."""
|
||||
entity = directive.entity
|
||||
current = int(entity.attributes.get(light.ATTR_COLOR_TEMP))
|
||||
@ -294,7 +352,12 @@ async def async_api_decrease_color_temp(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ColorTemperatureController", "IncreaseColorTemperature"))
|
||||
async def async_api_increase_color_temp(hass, config, directive, context):
|
||||
async def async_api_increase_color_temp(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an increase color temperature request."""
|
||||
entity = directive.entity
|
||||
current = int(entity.attributes.get(light.ATTR_COLOR_TEMP))
|
||||
@ -313,7 +376,12 @@ async def async_api_increase_color_temp(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.SceneController", "Activate"))
|
||||
async def async_api_activate(hass, config, directive, context):
|
||||
async def async_api_activate(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an activate request."""
|
||||
entity = directive.entity
|
||||
domain = entity.domain
|
||||
@ -343,7 +411,12 @@ async def async_api_activate(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.SceneController", "Deactivate"))
|
||||
async def async_api_deactivate(hass, config, directive, context):
|
||||
async def async_api_deactivate(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a deactivate request."""
|
||||
entity = directive.entity
|
||||
domain = entity.domain
|
||||
@ -367,16 +440,24 @@ async def async_api_deactivate(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PercentageController", "SetPercentage"))
|
||||
async def async_api_set_percentage(hass, config, directive, context):
|
||||
async def async_api_set_percentage(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set percentage request."""
|
||||
entity = directive.entity
|
||||
service = None
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
|
||||
if entity.domain == fan.DOMAIN:
|
||||
service = fan.SERVICE_SET_PERCENTAGE
|
||||
percentage = int(directive.payload["percentage"])
|
||||
data[fan.ATTR_PERCENTAGE] = percentage
|
||||
if entity.domain != fan.DOMAIN:
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
percentage = int(directive.payload["percentage"])
|
||||
service = fan.SERVICE_SET_PERCENTAGE
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id,
|
||||
fan.ATTR_PERCENTAGE: percentage,
|
||||
}
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, service, data, blocking=False, context=context
|
||||
@ -386,20 +467,27 @@ async def async_api_set_percentage(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PercentageController", "AdjustPercentage"))
|
||||
async def async_api_adjust_percentage(hass, config, directive, context):
|
||||
async def async_api_adjust_percentage(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an adjust percentage request."""
|
||||
entity = directive.entity
|
||||
|
||||
if entity.domain != fan.DOMAIN:
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
percentage_delta = int(directive.payload["percentageDelta"])
|
||||
service = None
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
|
||||
if entity.domain == fan.DOMAIN:
|
||||
service = fan.SERVICE_SET_PERCENTAGE
|
||||
current = entity.attributes.get(fan.ATTR_PERCENTAGE) or 0
|
||||
|
||||
# set percentage
|
||||
percentage = min(100, max(0, percentage_delta + current))
|
||||
data[fan.ATTR_PERCENTAGE] = percentage
|
||||
current = entity.attributes.get(fan.ATTR_PERCENTAGE) or 0
|
||||
# set percentage
|
||||
percentage = min(100, max(0, percentage_delta + current))
|
||||
service = fan.SERVICE_SET_PERCENTAGE
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id,
|
||||
fan.ATTR_PERCENTAGE: percentage,
|
||||
}
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, service, data, blocking=False, context=context
|
||||
@ -409,7 +497,12 @@ async def async_api_adjust_percentage(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.LockController", "Lock"))
|
||||
async def async_api_lock(hass, config, directive, context):
|
||||
async def async_api_lock(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a lock request."""
|
||||
entity = directive.entity
|
||||
await hass.services.async_call(
|
||||
@ -428,7 +521,12 @@ async def async_api_lock(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.LockController", "Unlock"))
|
||||
async def async_api_unlock(hass, config, directive, context):
|
||||
async def async_api_unlock(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an unlock request."""
|
||||
if config.locale not in {"de-DE", "en-US", "ja-JP"}:
|
||||
msg = f"The unlock directive is not supported for the following locales: {config.locale}"
|
||||
@ -452,7 +550,12 @@ async def async_api_unlock(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.Speaker", "SetVolume"))
|
||||
async def async_api_set_volume(hass, config, directive, context):
|
||||
async def async_api_set_volume(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set volume request."""
|
||||
volume = round(float(directive.payload["volume"] / 100), 2)
|
||||
entity = directive.entity
|
||||
@ -470,7 +573,12 @@ async def async_api_set_volume(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.InputController", "SelectInput"))
|
||||
async def async_api_select_input(hass, config, directive, context):
|
||||
async def async_api_select_input(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set input request."""
|
||||
media_input = directive.payload["input"]
|
||||
entity = directive.entity
|
||||
@ -514,7 +622,12 @@ async def async_api_select_input(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.Speaker", "AdjustVolume"))
|
||||
async def async_api_adjust_volume(hass, config, directive, context):
|
||||
async def async_api_adjust_volume(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an adjust volume request."""
|
||||
volume_delta = int(directive.payload["volume"])
|
||||
|
||||
@ -542,7 +655,12 @@ async def async_api_adjust_volume(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.StepSpeaker", "AdjustVolume"))
|
||||
async def async_api_adjust_volume_step(hass, config, directive, context):
|
||||
async def async_api_adjust_volume_step(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an adjust volume step request."""
|
||||
# media_player volume up/down service does not support specifying steps
|
||||
# each component handles it differently e.g. via config.
|
||||
@ -575,7 +693,12 @@ async def async_api_adjust_volume_step(hass, config, directive, context):
|
||||
|
||||
@HANDLERS.register(("Alexa.StepSpeaker", "SetMute"))
|
||||
@HANDLERS.register(("Alexa.Speaker", "SetMute"))
|
||||
async def async_api_set_mute(hass, config, directive, context):
|
||||
async def async_api_set_mute(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set mute request."""
|
||||
mute = bool(directive.payload["mute"])
|
||||
entity = directive.entity
|
||||
@ -592,7 +715,12 @@ async def async_api_set_mute(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PlaybackController", "Play"))
|
||||
async def async_api_play(hass, config, directive, context):
|
||||
async def async_api_play(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a play request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -605,7 +733,12 @@ async def async_api_play(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PlaybackController", "Pause"))
|
||||
async def async_api_pause(hass, config, directive, context):
|
||||
async def async_api_pause(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a pause request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -618,7 +751,12 @@ async def async_api_pause(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PlaybackController", "Stop"))
|
||||
async def async_api_stop(hass, config, directive, context):
|
||||
async def async_api_stop(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a stop request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -631,7 +769,12 @@ async def async_api_stop(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PlaybackController", "Next"))
|
||||
async def async_api_next(hass, config, directive, context):
|
||||
async def async_api_next(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a next request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -644,7 +787,12 @@ async def async_api_next(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.PlaybackController", "Previous"))
|
||||
async def async_api_previous(hass, config, directive, context):
|
||||
async def async_api_previous(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a previous request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -676,7 +824,12 @@ def temperature_from_object(hass, temp_obj, interval=False):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ThermostatController", "SetTargetTemperature"))
|
||||
async def async_api_set_target_temp(hass, config, directive, context):
|
||||
async def async_api_set_target_temp(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set target temperature request."""
|
||||
entity = directive.entity
|
||||
min_temp = entity.attributes.get(climate.ATTR_MIN_TEMP)
|
||||
@ -736,7 +889,12 @@ async def async_api_set_target_temp(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ThermostatController", "AdjustTargetTemperature"))
|
||||
async def async_api_adjust_target_temp(hass, config, directive, context):
|
||||
async def async_api_adjust_target_temp(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process an adjust target temperature request."""
|
||||
entity = directive.entity
|
||||
min_temp = entity.attributes.get(climate.ATTR_MIN_TEMP)
|
||||
@ -773,7 +931,12 @@ async def async_api_adjust_target_temp(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ThermostatController", "SetThermostatMode"))
|
||||
async def async_api_set_thermostat_mode(hass, config, directive, context):
|
||||
async def async_api_set_thermostat_mode(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a set thermostat mode request."""
|
||||
entity = directive.entity
|
||||
mode = directive.payload["thermostatMode"]
|
||||
@ -836,13 +999,23 @@ async def async_api_set_thermostat_mode(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa", "ReportState"))
|
||||
async def async_api_reportstate(hass, config, directive, context):
|
||||
async def async_api_reportstate(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a ReportState request."""
|
||||
return directive.response(name="StateReport")
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.SecurityPanelController", "Arm"))
|
||||
async def async_api_arm(hass, config, directive, context):
|
||||
async def async_api_arm(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a Security Panel Arm request."""
|
||||
entity = directive.entity
|
||||
service = None
|
||||
@ -859,6 +1032,8 @@ async def async_api_arm(hass, config, directive, context):
|
||||
service = SERVICE_ALARM_ARM_NIGHT
|
||||
elif arm_state == "ARMED_STAY":
|
||||
service = SERVICE_ALARM_ARM_HOME
|
||||
else:
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, service, data, blocking=False, context=context
|
||||
@ -883,7 +1058,12 @@ async def async_api_arm(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.SecurityPanelController", "Disarm"))
|
||||
async def async_api_disarm(hass, config, directive, context):
|
||||
async def async_api_disarm(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a Security Panel Disarm request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -916,7 +1096,12 @@ async def async_api_disarm(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ModeController", "SetMode"))
|
||||
async def async_api_set_mode(hass, config, directive, context):
|
||||
async def async_api_set_mode(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a SetMode directive."""
|
||||
entity = directive.entity
|
||||
instance = directive.instance
|
||||
@ -955,9 +1140,8 @@ async def async_api_set_mode(hass, config, directive, context):
|
||||
elif position == "custom":
|
||||
service = cover.SERVICE_STOP_COVER
|
||||
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
if not service:
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
await hass.services.async_call(
|
||||
domain, service, data, blocking=False, context=context
|
||||
@ -977,7 +1161,12 @@ async def async_api_set_mode(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ModeController", "AdjustMode"))
|
||||
async def async_api_adjust_mode(hass, config, directive, context):
|
||||
async def async_api_adjust_mode(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a AdjustMode request.
|
||||
|
||||
Requires capabilityResources supportedModes to be ordered.
|
||||
@ -985,26 +1174,30 @@ async def async_api_adjust_mode(hass, config, directive, context):
|
||||
"""
|
||||
|
||||
# Currently no supportedModes are configured with ordered=True to support this request.
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ToggleController", "TurnOn"))
|
||||
async def async_api_toggle_on(hass, config, directive, context):
|
||||
async def async_api_toggle_on(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a toggle on request."""
|
||||
entity = directive.entity
|
||||
instance = directive.instance
|
||||
domain = entity.domain
|
||||
service = None
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
|
||||
# Fan Oscillating
|
||||
if instance == f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}":
|
||||
service = fan.SERVICE_OSCILLATE
|
||||
data[fan.ATTR_OSCILLATING] = True
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
if instance != f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}":
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
service = fan.SERVICE_OSCILLATE
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id,
|
||||
fan.ATTR_OSCILLATING: True,
|
||||
}
|
||||
|
||||
await hass.services.async_call(
|
||||
domain, service, data, blocking=False, context=context
|
||||
@ -1024,21 +1217,26 @@ async def async_api_toggle_on(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ToggleController", "TurnOff"))
|
||||
async def async_api_toggle_off(hass, config, directive, context):
|
||||
async def async_api_toggle_off(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a toggle off request."""
|
||||
entity = directive.entity
|
||||
instance = directive.instance
|
||||
domain = entity.domain
|
||||
service = None
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
|
||||
# Fan Oscillating
|
||||
if instance == f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}":
|
||||
service = fan.SERVICE_OSCILLATE
|
||||
data[fan.ATTR_OSCILLATING] = False
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
if instance != f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}":
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
service = fan.SERVICE_OSCILLATE
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id,
|
||||
fan.ATTR_OSCILLATING: False,
|
||||
}
|
||||
|
||||
await hass.services.async_call(
|
||||
domain, service, data, blocking=False, context=context
|
||||
@ -1058,7 +1256,12 @@ async def async_api_toggle_off(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.RangeController", "SetRangeValue"))
|
||||
async def async_api_set_range(hass, config, directive, context):
|
||||
async def async_api_set_range(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a next request."""
|
||||
entity = directive.entity
|
||||
instance = directive.instance
|
||||
@ -1125,8 +1328,7 @@ async def async_api_set_range(hass, config, directive, context):
|
||||
data[vacuum.ATTR_FAN_SPEED] = speed
|
||||
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
await hass.services.async_call(
|
||||
domain, service, data, blocking=False, context=context
|
||||
@ -1146,16 +1348,21 @@ async def async_api_set_range(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.RangeController", "AdjustRangeValue"))
|
||||
async def async_api_adjust_range(hass, config, directive, context):
|
||||
async def async_api_adjust_range(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a next request."""
|
||||
entity = directive.entity
|
||||
instance = directive.instance
|
||||
domain = entity.domain
|
||||
service = None
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
data: dict[str, Any] = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
range_delta = directive.payload["rangeValueDelta"]
|
||||
range_delta_default = bool(directive.payload["rangeValueDeltaDefault"])
|
||||
response_value = 0
|
||||
response_value: int | None = 0
|
||||
|
||||
# Cover Position
|
||||
if instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
|
||||
@ -1232,12 +1439,10 @@ async def async_api_adjust_range(hass, config, directive, context):
|
||||
speed = next(
|
||||
(v for i, v in enumerate(speed_list) if i == new_speed_index), None
|
||||
)
|
||||
|
||||
data[vacuum.ATTR_FAN_SPEED] = response_value = speed
|
||||
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
await hass.services.async_call(
|
||||
domain, service, data, blocking=False, context=context
|
||||
@ -1257,7 +1462,12 @@ async def async_api_adjust_range(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ChannelController", "ChangeChannel"))
|
||||
async def async_api_changechannel(hass, config, directive, context):
|
||||
async def async_api_changechannel(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a change channel request."""
|
||||
channel = "0"
|
||||
entity = directive.entity
|
||||
@ -1309,7 +1519,12 @@ async def async_api_changechannel(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.ChannelController", "SkipChannels"))
|
||||
async def async_api_skipchannel(hass, config, directive, context):
|
||||
async def async_api_skipchannel(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a skipchannel request."""
|
||||
channel = int(directive.payload["channelCount"])
|
||||
entity = directive.entity
|
||||
@ -1340,7 +1555,12 @@ async def async_api_skipchannel(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.SeekController", "AdjustSeekPosition"))
|
||||
async def async_api_seek(hass, config, directive, context):
|
||||
async def async_api_seek(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a seek request."""
|
||||
entity = directive.entity
|
||||
position_delta = int(directive.payload["deltaPositionMilliseconds"])
|
||||
@ -1379,7 +1599,12 @@ async def async_api_seek(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.EqualizerController", "SetMode"))
|
||||
async def async_api_set_eq_mode(hass, config, directive, context):
|
||||
async def async_api_set_eq_mode(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a SetMode request for EqualizerController."""
|
||||
mode = directive.payload["mode"]
|
||||
entity = directive.entity
|
||||
@ -1406,18 +1631,27 @@ async def async_api_set_eq_mode(hass, config, directive, context):
|
||||
@HANDLERS.register(("Alexa.EqualizerController", "AdjustBands"))
|
||||
@HANDLERS.register(("Alexa.EqualizerController", "ResetBands"))
|
||||
@HANDLERS.register(("Alexa.EqualizerController", "SetBands"))
|
||||
async def async_api_bands_directive(hass, config, directive, context):
|
||||
async def async_api_bands_directive(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Handle an AdjustBands, ResetBands, SetBands request.
|
||||
|
||||
Only mode directives are currently supported for the EqualizerController.
|
||||
"""
|
||||
# Currently bands directives are not supported.
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.TimeHoldController", "Hold"))
|
||||
async def async_api_hold(hass, config, directive, context):
|
||||
async def async_api_hold(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a TimeHoldController Hold request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -1429,8 +1663,7 @@ async def async_api_hold(hass, config, directive, context):
|
||||
service = vacuum.SERVICE_START_PAUSE
|
||||
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, service, data, blocking=False, context=context
|
||||
@ -1440,7 +1673,12 @@ async def async_api_hold(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.TimeHoldController", "Resume"))
|
||||
async def async_api_resume(hass, config, directive, context):
|
||||
async def async_api_resume(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a TimeHoldController Resume request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
@ -1452,8 +1690,7 @@ async def async_api_resume(hass, config, directive, context):
|
||||
service = vacuum.SERVICE_START_PAUSE
|
||||
|
||||
else:
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
raise AlexaInvalidDirectiveError(DIRECTIVE_NOT_SUPPORTED)
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, service, data, blocking=False, context=context
|
||||
@ -1463,11 +1700,18 @@ async def async_api_resume(hass, config, directive, context):
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.CameraStreamController", "InitializeCameraStreams"))
|
||||
async def async_api_initialize_camera_stream(hass, config, directive, context):
|
||||
async def async_api_initialize_camera_stream(
|
||||
hass: ha.HomeAssistant,
|
||||
config: AbstractConfig,
|
||||
directive: AlexaDirective,
|
||||
context: ha.Context,
|
||||
) -> AlexaResponse:
|
||||
"""Process a InitializeCameraStreams request."""
|
||||
entity = directive.entity
|
||||
stream_source = await camera.async_request_stream(hass, entity.entity_id, fmt="hls")
|
||||
camera_image = hass.states.get(entity.entity_id).attributes[ATTR_ENTITY_PICTURE]
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state
|
||||
camera_image = state.attributes[ATTR_ENTITY_PICTURE]
|
||||
|
||||
try:
|
||||
external_url = network.get_url(
|
||||
|
@ -2,17 +2,17 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"missing_configuration": "El componente no est\u00e1 configurado. Mira su documentaci\u00f3n.",
|
||||
"no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [consulta la secci\u00f3n de ayuda]({docs_url})",
|
||||
"missing_configuration": "El componente no est\u00e1 configurado. Por favor, sigue la documentaci\u00f3n.",
|
||||
"no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [revisa la secci\u00f3n de ayuda]({docs_url})",
|
||||
"single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n."
|
||||
},
|
||||
"step": {
|
||||
"hassio_confirm": {
|
||||
"description": "\u00bfDesea configurar Home Assistant para conectarse a Almond proporcionado por el complemento Supervisor: {addon} ?",
|
||||
"title": "Almond a trav\u00e9s del complemento Supervisor"
|
||||
"description": "\u00bfQuieres configurar Home Assistant para conectarse a Almond proporcionado por el complemento: {addon}?",
|
||||
"title": "Almond a trav\u00e9s del complemento Home Assistant"
|
||||
},
|
||||
"pick_implementation": {
|
||||
"title": "Seleccione el m\u00e9todo de autenticaci\u00f3n"
|
||||
"title": "Selecciona el m\u00e9todo de autenticaci\u00f3n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cannot_connect": "Det g\u00e5r inte att ansluta till Almond-servern.",
|
||||
"missing_configuration": "Kontrollera dokumentationen f\u00f6r hur du st\u00e4ller in Almond."
|
||||
"missing_configuration": "Kontrollera dokumentationen f\u00f6r hur du st\u00e4ller in Almond.",
|
||||
"no_url_available": "Ingen webbadress tillg\u00e4nglig. F\u00f6r information om detta fel, [kolla hj\u00e4lpavsnittet]({docs_url})",
|
||||
"single_instance_allowed": "Redan konfigurerad. Endast en konfiguration m\u00f6jlig."
|
||||
},
|
||||
"step": {
|
||||
"hassio_confirm": {
|
||||
|
@ -10,7 +10,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components import persistent_notification
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
|
||||
from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY, CONF_CURRENCY, CONF_NAME
|
||||
from homeassistant.const import CONF_API_KEY, CONF_CURRENCY, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@ -118,6 +118,8 @@ def setup_platform(
|
||||
class AlphaVantageSensor(SensorEntity):
|
||||
"""Representation of a Alpha Vantage sensor."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
|
||||
def __init__(self, timeseries, symbol):
|
||||
"""Initialize the sensor."""
|
||||
self._symbol = symbol[CONF_SYMBOL]
|
||||
@ -126,7 +128,7 @@ class AlphaVantageSensor(SensorEntity):
|
||||
self._attr_native_unit_of_measurement = symbol.get(CONF_CURRENCY, self._symbol)
|
||||
self._attr_icon = ICONS.get(symbol.get(CONF_CURRENCY, "USD"))
|
||||
|
||||
def update(self):
|
||||
def update(self) -> None:
|
||||
"""Get the latest data and updates the states."""
|
||||
_LOGGER.debug("Requesting new data for symbol %s", self._symbol)
|
||||
all_values, _ = self._timeseries.get_intraday(self._symbol)
|
||||
@ -137,13 +139,12 @@ class AlphaVantageSensor(SensorEntity):
|
||||
self._attr_native_value = None
|
||||
self._attr_extra_state_attributes = (
|
||||
{
|
||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||
ATTR_CLOSE: values["4. close"],
|
||||
ATTR_HIGH: values["2. high"],
|
||||
ATTR_LOW: values["3. low"],
|
||||
}
|
||||
if isinstance(values, dict)
|
||||
else None
|
||||
else {}
|
||||
)
|
||||
_LOGGER.debug("Received new values for symbol %s", self._symbol)
|
||||
|
||||
@ -151,6 +152,8 @@ class AlphaVantageSensor(SensorEntity):
|
||||
class AlphaVantageForeignExchange(SensorEntity):
|
||||
"""Sensor for foreign exchange rates."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
|
||||
def __init__(self, foreign_exchange, config):
|
||||
"""Initialize the sensor."""
|
||||
self._foreign_exchange = foreign_exchange
|
||||
@ -164,7 +167,7 @@ class AlphaVantageForeignExchange(SensorEntity):
|
||||
self._attr_icon = ICONS.get(self._from_currency, "USD")
|
||||
self._attr_native_unit_of_measurement = self._to_currency
|
||||
|
||||
def update(self):
|
||||
def update(self) -> None:
|
||||
"""Get the latest data and updates the states."""
|
||||
_LOGGER.debug(
|
||||
"Requesting new data for forex %s - %s",
|
||||
@ -180,12 +183,11 @@ class AlphaVantageForeignExchange(SensorEntity):
|
||||
self._attr_native_value = None
|
||||
self._attr_extra_state_attributes = (
|
||||
{
|
||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||
CONF_FROM: self._from_currency,
|
||||
CONF_TO: self._to_currency,
|
||||
}
|
||||
if values is not None
|
||||
else None
|
||||
else {}
|
||||
)
|
||||
|
||||
_LOGGER.debug(
|
||||
|
@ -36,6 +36,7 @@ SUPPORTED_VOICES: Final[list[str]] = [
|
||||
"Aditi", # Hindi
|
||||
"Amy",
|
||||
"Aria",
|
||||
"Arthur", # English, Neural
|
||||
"Astrid", # Swedish
|
||||
"Ayanda",
|
||||
"Bianca", # Italian
|
||||
@ -47,6 +48,7 @@ SUPPORTED_VOICES: Final[list[str]] = [
|
||||
"Chantal", # French Canadian
|
||||
"Conchita",
|
||||
"Cristiano",
|
||||
"Daniel", # German, Neural
|
||||
"Dora", # Icelandic
|
||||
"Emma", # English
|
||||
"Enrique",
|
||||
@ -69,6 +71,7 @@ SUPPORTED_VOICES: Final[list[str]] = [
|
||||
"Kevin",
|
||||
"Kimberly",
|
||||
"Lea", # French
|
||||
"Liam", # Canadian French, Neural
|
||||
"Liv", # Norwegian
|
||||
"Lotte", # Dutch
|
||||
"Lucia", # Spanish European
|
||||
@ -86,6 +89,7 @@ SUPPORTED_VOICES: Final[list[str]] = [
|
||||
"Nicole", # English Australian
|
||||
"Olivia", # Female, Australian, Neural
|
||||
"Penelope", # Spanish US
|
||||
"Pedro", # Spanish US, Neural
|
||||
"Raveena", # English, Indian
|
||||
"Ricardo",
|
||||
"Ruben",
|
||||
|
@ -3,15 +3,15 @@ from __future__ import annotations
|
||||
|
||||
from ambee import AirQuality, Ambee, AmbeeAuthenticationError, Pollen
|
||||
|
||||
from homeassistant.components.repairs import (
|
||||
IssueSeverity,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||
from homeassistant.helpers.issue_registry import (
|
||||
IssueSeverity,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
)
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user