forked from home-assistant/core
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae71cc5fc5 |
+1
-2
@@ -45,7 +45,6 @@ base_platforms: &base_platforms
|
||||
- homeassistant/components/switch/**
|
||||
- homeassistant/components/text/**
|
||||
- homeassistant/components/time/**
|
||||
- homeassistant/components/todo/**
|
||||
- homeassistant/components/tts/**
|
||||
- homeassistant/components/update/**
|
||||
- homeassistant/components/vacuum/**
|
||||
@@ -97,8 +96,8 @@ components: &components
|
||||
- homeassistant/components/persistent_notification/**
|
||||
- homeassistant/components/person/**
|
||||
- homeassistant/components/recorder/**
|
||||
- homeassistant/components/recovery_mode/**
|
||||
- homeassistant/components/repairs/**
|
||||
- homeassistant/components/safe_mode/**
|
||||
- homeassistant/components/script/**
|
||||
- homeassistant/components/shopping_list/**
|
||||
- homeassistant/components/ssdp/**
|
||||
|
||||
+30
-52
@@ -67,6 +67,9 @@ omit =
|
||||
homeassistant/components/android_ip_webcam/switch.py
|
||||
homeassistant/components/anel_pwrctrl/switch.py
|
||||
homeassistant/components/anthemav/media_player.py
|
||||
homeassistant/components/apcupsd/__init__.py
|
||||
homeassistant/components/apcupsd/binary_sensor.py
|
||||
homeassistant/components/apcupsd/sensor.py
|
||||
homeassistant/components/apple_tv/__init__.py
|
||||
homeassistant/components/apple_tv/browse_media.py
|
||||
homeassistant/components/apple_tv/media_player.py
|
||||
@@ -120,7 +123,6 @@ omit =
|
||||
homeassistant/components/blink/binary_sensor.py
|
||||
homeassistant/components/blink/camera.py
|
||||
homeassistant/components/blink/sensor.py
|
||||
homeassistant/components/blink/switch.py
|
||||
homeassistant/components/blinksticklight/light.py
|
||||
homeassistant/components/blockchain/sensor.py
|
||||
homeassistant/components/bloomsky/*
|
||||
@@ -142,7 +144,6 @@ omit =
|
||||
homeassistant/components/braviatv/coordinator.py
|
||||
homeassistant/components/braviatv/media_player.py
|
||||
homeassistant/components/braviatv/remote.py
|
||||
homeassistant/components/broadlink/climate.py
|
||||
homeassistant/components/broadlink/light.py
|
||||
homeassistant/components/broadlink/remote.py
|
||||
homeassistant/components/broadlink/switch.py
|
||||
@@ -173,7 +174,6 @@ omit =
|
||||
homeassistant/components/coinbase/sensor.py
|
||||
homeassistant/components/comed_hourly_pricing/sensor.py
|
||||
homeassistant/components/comelit/__init__.py
|
||||
homeassistant/components/comelit/alarm_control_panel.py
|
||||
homeassistant/components/comelit/const.py
|
||||
homeassistant/components/comelit/cover.py
|
||||
homeassistant/components/comelit/coordinator.py
|
||||
@@ -216,6 +216,9 @@ omit =
|
||||
homeassistant/components/discogs/sensor.py
|
||||
homeassistant/components/discord/__init__.py
|
||||
homeassistant/components/discord/notify.py
|
||||
homeassistant/components/discovergy/__init__.py
|
||||
homeassistant/components/discovergy/sensor.py
|
||||
homeassistant/components/discovergy/coordinator.py
|
||||
homeassistant/components/dlib_face_detect/image_processing.py
|
||||
homeassistant/components/dlib_face_identify/image_processing.py
|
||||
homeassistant/components/dlink/data.py
|
||||
@@ -283,6 +286,9 @@ omit =
|
||||
homeassistant/components/edl21/__init__.py
|
||||
homeassistant/components/edl21/sensor.py
|
||||
homeassistant/components/egardia/*
|
||||
homeassistant/components/eight_sleep/__init__.py
|
||||
homeassistant/components/eight_sleep/binary_sensor.py
|
||||
homeassistant/components/eight_sleep/sensor.py
|
||||
homeassistant/components/electric_kiwi/__init__.py
|
||||
homeassistant/components/electric_kiwi/api.py
|
||||
homeassistant/components/electric_kiwi/oauth2.py
|
||||
@@ -335,9 +341,11 @@ omit =
|
||||
homeassistant/components/epson/__init__.py
|
||||
homeassistant/components/epson/media_player.py
|
||||
homeassistant/components/epsonworkforce/sensor.py
|
||||
homeassistant/components/eq3btsmart/climate.py
|
||||
homeassistant/components/escea/__init__.py
|
||||
homeassistant/components/escea/climate.py
|
||||
homeassistant/components/escea/discovery.py
|
||||
homeassistant/components/esphome/bluetooth/*
|
||||
homeassistant/components/esphome/manager.py
|
||||
homeassistant/components/etherscan/sensor.py
|
||||
homeassistant/components/eufy/*
|
||||
@@ -364,6 +372,7 @@ omit =
|
||||
homeassistant/components/faa_delays/binary_sensor.py
|
||||
homeassistant/components/faa_delays/coordinator.py
|
||||
homeassistant/components/familyhub/camera.py
|
||||
homeassistant/components/fastdotcom/*
|
||||
homeassistant/components/ffmpeg/camera.py
|
||||
homeassistant/components/fibaro/__init__.py
|
||||
homeassistant/components/fibaro/binary_sensor.py
|
||||
@@ -402,9 +411,6 @@ omit =
|
||||
homeassistant/components/fjaraskupan/sensor.py
|
||||
homeassistant/components/fleetgo/device_tracker.py
|
||||
homeassistant/components/flexit/climate.py
|
||||
homeassistant/components/flexit_bacnet/__init__.py
|
||||
homeassistant/components/flexit_bacnet/const.py
|
||||
homeassistant/components/flexit_bacnet/climate.py
|
||||
homeassistant/components/flic/binary_sensor.py
|
||||
homeassistant/components/flick_electric/__init__.py
|
||||
homeassistant/components/flick_electric/sensor.py
|
||||
@@ -420,11 +426,12 @@ omit =
|
||||
homeassistant/components/fortios/device_tracker.py
|
||||
homeassistant/components/foscam/__init__.py
|
||||
homeassistant/components/foscam/camera.py
|
||||
homeassistant/components/foscam/coordinator.py
|
||||
homeassistant/components/foursquare/*
|
||||
homeassistant/components/free_mobile/notify.py
|
||||
homeassistant/components/freebox/camera.py
|
||||
homeassistant/components/freebox/device_tracker.py
|
||||
homeassistant/components/freebox/home_base.py
|
||||
homeassistant/components/freebox/router.py
|
||||
homeassistant/components/freebox/switch.py
|
||||
homeassistant/components/fritz/common.py
|
||||
homeassistant/components/fritz/device_tracker.py
|
||||
@@ -538,7 +545,6 @@ omit =
|
||||
homeassistant/components/hvv_departures/binary_sensor.py
|
||||
homeassistant/components/hvv_departures/sensor.py
|
||||
homeassistant/components/ialarm/alarm_control_panel.py
|
||||
homeassistant/components/iammeter/const.py
|
||||
homeassistant/components/iammeter/sensor.py
|
||||
homeassistant/components/iaqualink/binary_sensor.py
|
||||
homeassistant/components/iaqualink/climate.py
|
||||
@@ -757,9 +763,6 @@ omit =
|
||||
homeassistant/components/motion_blinds/cover.py
|
||||
homeassistant/components/motion_blinds/entity.py
|
||||
homeassistant/components/motion_blinds/sensor.py
|
||||
homeassistant/components/motionmount/__init__.py
|
||||
homeassistant/components/motionmount/entity.py
|
||||
homeassistant/components/motionmount/number.py
|
||||
homeassistant/components/mpd/media_player.py
|
||||
homeassistant/components/mqtt_room/sensor.py
|
||||
homeassistant/components/msteams/notify.py
|
||||
@@ -769,6 +772,9 @@ omit =
|
||||
homeassistant/components/mutesync/binary_sensor.py
|
||||
homeassistant/components/mvglive/sensor.py
|
||||
homeassistant/components/mycroft/*
|
||||
homeassistant/components/myq/__init__.py
|
||||
homeassistant/components/myq/cover.py
|
||||
homeassistant/components/myq/light.py
|
||||
homeassistant/components/mysensors/__init__.py
|
||||
homeassistant/components/mysensors/climate.py
|
||||
homeassistant/components/mysensors/cover.py
|
||||
@@ -805,8 +811,7 @@ omit =
|
||||
homeassistant/components/netgear/sensor.py
|
||||
homeassistant/components/netgear/switch.py
|
||||
homeassistant/components/netgear/update.py
|
||||
homeassistant/components/netgear_lte/__init__.py
|
||||
homeassistant/components/netgear_lte/notify.py
|
||||
homeassistant/components/netgear_lte/*
|
||||
homeassistant/components/netio/switch.py
|
||||
homeassistant/components/neurio_energy/sensor.py
|
||||
homeassistant/components/nexia/climate.py
|
||||
@@ -820,6 +825,7 @@ omit =
|
||||
homeassistant/components/nfandroidtv/__init__.py
|
||||
homeassistant/components/nfandroidtv/notify.py
|
||||
homeassistant/components/nibe_heatpump/__init__.py
|
||||
homeassistant/components/nibe_heatpump/climate.py
|
||||
homeassistant/components/nibe_heatpump/binary_sensor.py
|
||||
homeassistant/components/nibe_heatpump/select.py
|
||||
homeassistant/components/nibe_heatpump/sensor.py
|
||||
@@ -834,7 +840,6 @@ omit =
|
||||
homeassistant/components/noaa_tides/sensor.py
|
||||
homeassistant/components/nobo_hub/__init__.py
|
||||
homeassistant/components/nobo_hub/climate.py
|
||||
homeassistant/components/nobo_hub/select.py
|
||||
homeassistant/components/nobo_hub/sensor.py
|
||||
homeassistant/components/norway_air/air_quality.py
|
||||
homeassistant/components/notify_events/notify.py
|
||||
@@ -907,9 +912,6 @@ omit =
|
||||
homeassistant/components/opple/light.py
|
||||
homeassistant/components/oru/*
|
||||
homeassistant/components/orvibo/switch.py
|
||||
homeassistant/components/osoenergy/__init__.py
|
||||
homeassistant/components/osoenergy/const.py
|
||||
homeassistant/components/osoenergy/water_heater.py
|
||||
homeassistant/components/osramlightify/light.py
|
||||
homeassistant/components/otp/sensor.py
|
||||
homeassistant/components/overkiz/__init__.py
|
||||
@@ -938,9 +940,6 @@ omit =
|
||||
homeassistant/components/panasonic_viera/media_player.py
|
||||
homeassistant/components/pandora/media_player.py
|
||||
homeassistant/components/pencom/switch.py
|
||||
homeassistant/components/permobil/__init__.py
|
||||
homeassistant/components/permobil/coordinator.py
|
||||
homeassistant/components/permobil/sensor.py
|
||||
homeassistant/components/philips_js/__init__.py
|
||||
homeassistant/components/philips_js/light.py
|
||||
homeassistant/components/philips_js/media_player.py
|
||||
@@ -954,6 +953,8 @@ omit =
|
||||
homeassistant/components/pilight/light.py
|
||||
homeassistant/components/pilight/switch.py
|
||||
homeassistant/components/ping/__init__.py
|
||||
homeassistant/components/ping/binary_sensor.py
|
||||
homeassistant/components/ping/device_tracker.py
|
||||
homeassistant/components/ping/helpers.py
|
||||
homeassistant/components/pioneer/media_player.py
|
||||
homeassistant/components/plaato/__init__.py
|
||||
@@ -991,7 +992,6 @@ omit =
|
||||
homeassistant/components/pushsafer/notify.py
|
||||
homeassistant/components/pyload/sensor.py
|
||||
homeassistant/components/qbittorrent/__init__.py
|
||||
homeassistant/components/qbittorrent/coordinator.py
|
||||
homeassistant/components/qbittorrent/sensor.py
|
||||
homeassistant/components/qnap/__init__.py
|
||||
homeassistant/components/qnap/coordinator.py
|
||||
@@ -1036,12 +1036,6 @@ omit =
|
||||
homeassistant/components/recorder/repack.py
|
||||
homeassistant/components/recswitch/switch.py
|
||||
homeassistant/components/reddit/sensor.py
|
||||
homeassistant/components/refoss/__init__.py
|
||||
homeassistant/components/refoss/bridge.py
|
||||
homeassistant/components/refoss/coordinator.py
|
||||
homeassistant/components/refoss/entity.py
|
||||
homeassistant/components/refoss/switch.py
|
||||
homeassistant/components/refoss/util.py
|
||||
homeassistant/components/rejseplanen/sensor.py
|
||||
homeassistant/components/remember_the_milk/__init__.py
|
||||
homeassistant/components/remote_rpi_gpio/*
|
||||
@@ -1077,7 +1071,6 @@ omit =
|
||||
homeassistant/components/roomba/sensor.py
|
||||
homeassistant/components/roomba/vacuum.py
|
||||
homeassistant/components/roon/__init__.py
|
||||
homeassistant/components/roon/event.py
|
||||
homeassistant/components/roon/media_browser.py
|
||||
homeassistant/components/roon/media_player.py
|
||||
homeassistant/components/roon/server.py
|
||||
@@ -1141,7 +1134,10 @@ omit =
|
||||
homeassistant/components/sky_hub/*
|
||||
homeassistant/components/skybeacon/sensor.py
|
||||
homeassistant/components/skybell/__init__.py
|
||||
homeassistant/components/skybell/binary_sensor.py
|
||||
homeassistant/components/skybell/camera.py
|
||||
homeassistant/components/skybell/coordinator.py
|
||||
homeassistant/components/skybell/entity.py
|
||||
homeassistant/components/skybell/light.py
|
||||
homeassistant/components/skybell/sensor.py
|
||||
homeassistant/components/skybell/switch.py
|
||||
@@ -1225,7 +1221,6 @@ omit =
|
||||
homeassistant/components/starline/__init__.py
|
||||
homeassistant/components/starline/account.py
|
||||
homeassistant/components/starline/binary_sensor.py
|
||||
homeassistant/components/starline/button.py
|
||||
homeassistant/components/starline/device_tracker.py
|
||||
homeassistant/components/starline/entity.py
|
||||
homeassistant/components/starline/lock.py
|
||||
@@ -1243,12 +1238,8 @@ omit =
|
||||
homeassistant/components/stream/fmp4utils.py
|
||||
homeassistant/components/stream/hls.py
|
||||
homeassistant/components/stream/worker.py
|
||||
homeassistant/components/streamlabswater/__init__.py
|
||||
homeassistant/components/streamlabswater/binary_sensor.py
|
||||
homeassistant/components/streamlabswater/coordinator.py
|
||||
homeassistant/components/streamlabswater/sensor.py
|
||||
homeassistant/components/suez_water/__init__.py
|
||||
homeassistant/components/suez_water/sensor.py
|
||||
homeassistant/components/streamlabswater/*
|
||||
homeassistant/components/suez_water/*
|
||||
homeassistant/components/supervisord/sensor.py
|
||||
homeassistant/components/supla/*
|
||||
homeassistant/components/surepetcare/__init__.py
|
||||
@@ -1256,8 +1247,6 @@ omit =
|
||||
homeassistant/components/surepetcare/entity.py
|
||||
homeassistant/components/surepetcare/sensor.py
|
||||
homeassistant/components/swiss_hydrological_data/sensor.py
|
||||
homeassistant/components/swiss_public_transport/__init__.py
|
||||
homeassistant/components/swiss_public_transport/coordinator.py
|
||||
homeassistant/components/swiss_public_transport/sensor.py
|
||||
homeassistant/components/swisscom/device_tracker.py
|
||||
homeassistant/components/switchbee/__init__.py
|
||||
@@ -1278,7 +1267,6 @@ omit =
|
||||
homeassistant/components/switchbot/sensor.py
|
||||
homeassistant/components/switchbot/switch.py
|
||||
homeassistant/components/switchbot/lock.py
|
||||
homeassistant/components/switchbot_cloud/climate.py
|
||||
homeassistant/components/switchbot_cloud/coordinator.py
|
||||
homeassistant/components/switchbot_cloud/entity.py
|
||||
homeassistant/components/switchbot_cloud/switch.py
|
||||
@@ -1304,14 +1292,10 @@ omit =
|
||||
homeassistant/components/system_bridge/__init__.py
|
||||
homeassistant/components/system_bridge/binary_sensor.py
|
||||
homeassistant/components/system_bridge/coordinator.py
|
||||
homeassistant/components/system_bridge/entity.py
|
||||
homeassistant/components/system_bridge/media_player.py
|
||||
homeassistant/components/system_bridge/notify.py
|
||||
homeassistant/components/system_bridge/sensor.py
|
||||
homeassistant/components/system_bridge/update.py
|
||||
homeassistant/components/systemmonitor/__init__.py
|
||||
homeassistant/components/systemmonitor/sensor.py
|
||||
homeassistant/components/systemmonitor/util.py
|
||||
homeassistant/components/tado/__init__.py
|
||||
homeassistant/components/tado/binary_sensor.py
|
||||
homeassistant/components/tado/climate.py
|
||||
@@ -1400,6 +1384,10 @@ omit =
|
||||
homeassistant/components/tradfri/light.py
|
||||
homeassistant/components/tradfri/sensor.py
|
||||
homeassistant/components/tradfri/switch.py
|
||||
homeassistant/components/trafikverket_train/__init__.py
|
||||
homeassistant/components/trafikverket_train/coordinator.py
|
||||
homeassistant/components/trafikverket_train/sensor.py
|
||||
homeassistant/components/trafikverket_train/util.py
|
||||
homeassistant/components/trafikverket_weatherstation/__init__.py
|
||||
homeassistant/components/trafikverket_weatherstation/coordinator.py
|
||||
homeassistant/components/trafikverket_weatherstation/sensor.py
|
||||
@@ -1434,8 +1422,6 @@ omit =
|
||||
homeassistant/components/ukraine_alarm/__init__.py
|
||||
homeassistant/components/ukraine_alarm/binary_sensor.py
|
||||
homeassistant/components/unifiled/*
|
||||
homeassistant/components/unifi_direct/__init__.py
|
||||
homeassistant/components/unifi_direct/device_tracker.py
|
||||
homeassistant/components/upb/__init__.py
|
||||
homeassistant/components/upb/light.py
|
||||
homeassistant/components/upc_connect/*
|
||||
@@ -1446,13 +1432,6 @@ omit =
|
||||
homeassistant/components/upnp/device.py
|
||||
homeassistant/components/upnp/sensor.py
|
||||
homeassistant/components/vasttrafik/sensor.py
|
||||
homeassistant/components/v2c/__init__.py
|
||||
homeassistant/components/v2c/binary_sensor.py
|
||||
homeassistant/components/v2c/coordinator.py
|
||||
homeassistant/components/v2c/entity.py
|
||||
homeassistant/components/v2c/number.py
|
||||
homeassistant/components/v2c/sensor.py
|
||||
homeassistant/components/v2c/switch.py
|
||||
homeassistant/components/velbus/__init__.py
|
||||
homeassistant/components/velbus/binary_sensor.py
|
||||
homeassistant/components/velbus/button.py
|
||||
@@ -1489,7 +1468,6 @@ omit =
|
||||
homeassistant/components/vicare/button.py
|
||||
homeassistant/components/vicare/climate.py
|
||||
homeassistant/components/vicare/entity.py
|
||||
homeassistant/components/vicare/number.py
|
||||
homeassistant/components/vicare/sensor.py
|
||||
homeassistant/components/vicare/utils.py
|
||||
homeassistant/components/vicare/water_heater.py
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"charliermarsh.ruff",
|
||||
"ms-python.pylint",
|
||||
"ms-python.vscode-pylance",
|
||||
"visualstudioexptteam.vscodeintellicode",
|
||||
"redhat.vscode-yaml",
|
||||
@@ -21,6 +19,14 @@
|
||||
// Please keep this file in sync with settings in home-assistant/.vscode/settings.default.json
|
||||
"settings": {
|
||||
"python.pythonPath": "/usr/local/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.formatting.blackPath": "/usr/local/bin/black",
|
||||
"python.linting.pycodestylePath": "/usr/local/bin/pycodestyle",
|
||||
"python.linting.pydocstylePath": "/usr/local/bin/pydocstyle",
|
||||
"python.linting.mypyPath": "/usr/local/bin/mypy",
|
||||
"python.linting.pylintPath": "/usr/local/bin/pylint",
|
||||
"python.formatting.provider": "black",
|
||||
"python.testing.pytestArgs": ["--no-cov"],
|
||||
"editor.formatOnPaste": false,
|
||||
"editor.formatOnSave": true,
|
||||
@@ -39,10 +45,7 @@
|
||||
"!include_dir_list scalar",
|
||||
"!include_dir_merge_list scalar",
|
||||
"!include_dir_merge_named scalar"
|
||||
],
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
- [ ] There is no commented out code in this PR.
|
||||
- [ ] I have followed the [development checklist][dev-checklist]
|
||||
- [ ] I have followed the [perfect PR recommendations][perfect-pr]
|
||||
- [ ] The code has been formatted using Ruff (`ruff format homeassistant tests`)
|
||||
- [ ] The code has been formatted using Black (`black --fast homeassistant tests`)
|
||||
- [ ] Tests have been added to verify that the new code works.
|
||||
|
||||
If user exposed functionality or configuration variables are added/changed:
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
if: needs.init.outputs.channel == 'dev'
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2023.12.0
|
||||
uses: home-assistant/builder@2023.09.0
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
@@ -247,7 +247,6 @@ jobs:
|
||||
- raspberrypi3-64
|
||||
- raspberrypi4
|
||||
- raspberrypi4-64
|
||||
- raspberrypi5-64
|
||||
- tinker
|
||||
- yellow
|
||||
- green
|
||||
@@ -274,7 +273,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2023.12.0
|
||||
uses: home-assistant/builder@2023.09.0
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
@@ -331,7 +330,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v3.3.0
|
||||
uses: sigstore/cosign-installer@v3.1.2
|
||||
with:
|
||||
cosign-release: "v2.0.2"
|
||||
|
||||
|
||||
+66
-26
@@ -35,8 +35,9 @@ on:
|
||||
env:
|
||||
CACHE_VERSION: 5
|
||||
PIP_CACHE_VERSION: 4
|
||||
MYPY_CACHE_VERSION: 6
|
||||
HA_SHORT_VERSION: "2024.1"
|
||||
MYPY_CACHE_VERSION: 5
|
||||
BLACK_CACHE_VERSION: 1
|
||||
HA_SHORT_VERSION: "2023.11"
|
||||
DEFAULT_PYTHON: "3.11"
|
||||
ALL_PYTHON_VERSIONS: "['3.11', '3.12']"
|
||||
# 10.3 is the oldest supported version
|
||||
@@ -57,6 +58,7 @@ env:
|
||||
POSTGRESQL_VERSIONS: "['postgres:12.14','postgres:15.2']"
|
||||
PRE_COMMIT_CACHE: ~/.cache/pre-commit
|
||||
PIP_CACHE: /tmp/pip-cache
|
||||
BLACK_CACHE: /tmp/black-cache
|
||||
SQLALCHEMY_WARN_20: 1
|
||||
PYTHONASYNCIODEBUG: 1
|
||||
HASS_CI: 1
|
||||
@@ -225,7 +227,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -259,8 +261,8 @@ jobs:
|
||||
. venv/bin/activate
|
||||
pre-commit install-hooks
|
||||
|
||||
lint-ruff-format:
|
||||
name: Check ruff-format
|
||||
lint-black:
|
||||
name: Check black
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- info
|
||||
@@ -269,11 +271,18 @@ jobs:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
- name: Generate partial black restore key
|
||||
id: generate-black-key
|
||||
run: |
|
||||
black_version=$(cat requirements_test_pre_commit.txt | grep black | cut -d '=' -f 3)
|
||||
echo "version=$black_version" >> $GITHUB_OUTPUT
|
||||
echo "key=black-${{ env.BLACK_CACHE_VERSION }}-$black_version-${{
|
||||
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v3.3.2
|
||||
@@ -292,12 +301,33 @@ jobs:
|
||||
key: >-
|
||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||
needs.info.outputs.pre-commit_cache_key }}
|
||||
- name: Run ruff-format
|
||||
- name: Restore black cache
|
||||
uses: actions/cache@v3.3.2
|
||||
with:
|
||||
path: ${{ env.BLACK_CACHE }}
|
||||
key: >-
|
||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||
steps.generate-black-key.outputs.key }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-black-${{
|
||||
env.BLACK_CACHE_VERSION }}-${{ steps.generate-black-key.outputs.version }}-${{
|
||||
env.HA_SHORT_VERSION }}-
|
||||
- name: Run black (fully)
|
||||
if: needs.info.outputs.test_full_suite == 'true'
|
||||
env:
|
||||
BLACK_CACHE_DIR: ${{ env.BLACK_CACHE }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
pre-commit run --hook-stage manual ruff-format --all-files --show-diff-on-failure
|
||||
pre-commit run --hook-stage manual black --all-files --show-diff-on-failure
|
||||
- name: Run black (partially)
|
||||
if: needs.info.outputs.test_full_suite == 'false'
|
||||
shell: bash
|
||||
env:
|
||||
RUFF_OUTPUT_FORMAT: github
|
||||
BLACK_CACHE_DIR: ${{ env.BLACK_CACHE }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
shopt -s globstar
|
||||
pre-commit run --hook-stage manual black --files {homeassistant,tests}/components/${{ needs.info.outputs.integrations_glob }}/{*,**/*} --show-diff-on-failure
|
||||
|
||||
lint-ruff:
|
||||
name: Check ruff
|
||||
@@ -309,7 +339,7 @@ jobs:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
@@ -332,12 +362,22 @@ jobs:
|
||||
key: >-
|
||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||
needs.info.outputs.pre-commit_cache_key }}
|
||||
- name: Run ruff
|
||||
- name: Register ruff problem matcher
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/ruff.json"
|
||||
- name: Run ruff (fully)
|
||||
if: needs.info.outputs.test_full_suite == 'true'
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
pre-commit run --hook-stage manual ruff --all-files --show-diff-on-failure
|
||||
env:
|
||||
RUFF_OUTPUT_FORMAT: github
|
||||
- name: Run ruff (partially)
|
||||
if: needs.info.outputs.test_full_suite == 'false'
|
||||
shell: bash
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
shopt -s globstar
|
||||
pre-commit run --hook-stage manual ruff --files {homeassistant,tests}/components/${{ needs.info.outputs.integrations_glob }}/{*,**/*} --show-diff-on-failure
|
||||
|
||||
lint-other:
|
||||
name: Check other linters
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -348,7 +388,7 @@ jobs:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
@@ -443,7 +483,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -511,7 +551,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -543,7 +583,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -576,7 +616,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -620,7 +660,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -702,7 +742,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -747,7 +787,7 @@ jobs:
|
||||
cov_params+=(--cov-report=xml)
|
||||
fi
|
||||
|
||||
python3 -b -X dev -m pytest \
|
||||
python3 -X dev -m pytest \
|
||||
-qq \
|
||||
--timeout=9 \
|
||||
--durations=10 \
|
||||
@@ -784,7 +824,7 @@ jobs:
|
||||
cov_params+=(--cov-report=term-missing)
|
||||
fi
|
||||
|
||||
python3 -b -X dev -m pytest \
|
||||
python3 -X dev -m pytest \
|
||||
-qq \
|
||||
--timeout=9 \
|
||||
-n auto \
|
||||
@@ -854,7 +894,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -905,7 +945,7 @@ jobs:
|
||||
cov_params+=(--cov-report=term-missing)
|
||||
fi
|
||||
|
||||
python3 -b -X dev -m pytest \
|
||||
python3 -X dev -m pytest \
|
||||
-qq \
|
||||
--timeout=20 \
|
||||
-n 1 \
|
||||
@@ -978,7 +1018,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -1029,7 +1069,7 @@ jobs:
|
||||
cov_params+=(--cov-report=term-missing)
|
||||
fi
|
||||
|
||||
python3 -b -X dev -m pytest \
|
||||
python3 -X dev -m pytest \
|
||||
-qq \
|
||||
--timeout=9 \
|
||||
-n 1 \
|
||||
|
||||
@@ -29,11 +29,11 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3.22.12
|
||||
uses: github/codeql-action/init@v2.22.3
|
||||
with:
|
||||
languages: python
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3.22.12
|
||||
uses: github/codeql-action/analyze@v2.22.3
|
||||
with:
|
||||
category: "/language:python"
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
if: github.repository_owner == 'home-assistant'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5.0.1
|
||||
- uses: dessant/lock-threads@v4.0.1
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: "30"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "ruff-error",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s([EF]\\d{3}\\s.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"owner": "ruff-warning",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s([CDNW]\\d{3}\\s.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,16 +11,16 @@ jobs:
|
||||
if: github.repository_owner == 'home-assistant'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# The 60 day stale policy for PRs
|
||||
# The 90 day stale policy for PRs
|
||||
# Used for:
|
||||
# - PRs
|
||||
# - No PRs marked as no-stale
|
||||
# - No issues (-1)
|
||||
- name: 60 days stale PRs policy
|
||||
uses: actions/stale@v9.0.0
|
||||
- name: 90 days stale PRs policy
|
||||
uses: actions/stale@v8.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 60
|
||||
days-before-stale: 90
|
||||
days-before-close: 7
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
@@ -33,11 +33,7 @@ jobs:
|
||||
pull request has been automatically marked as stale because of that
|
||||
and will be closed if no further activity occurs within 7 days.
|
||||
|
||||
If you are the author of this PR, please leave a comment if you want
|
||||
to keep it open. Also, please rebase your PR onto the latest dev
|
||||
branch to ensure that it's up to date with the latest changes.
|
||||
|
||||
Thank you for your contribution!
|
||||
Thank you for your contributions.
|
||||
|
||||
# Generate a token for the GitHub App, we use this method to avoid
|
||||
# hitting API limits for our GitHub actions + have a higher rate limit.
|
||||
@@ -57,7 +53,7 @@ jobs:
|
||||
# - No issues marked as no-stale or help-wanted
|
||||
# - No PRs (-1)
|
||||
- name: 90 days stale issues
|
||||
uses: actions/stale@v9.0.0
|
||||
uses: actions/stale@v8.0.0
|
||||
with:
|
||||
repo-token: ${{ steps.token.outputs.token }}
|
||||
days-before-stale: 90
|
||||
@@ -87,7 +83,7 @@ jobs:
|
||||
# - No Issues marked as no-stale or help-wanted
|
||||
# - No PRs (-1)
|
||||
- name: Needs more information stale issues policy
|
||||
uses: actions/stale@v9.0.0
|
||||
uses: actions/stale@v8.0.0
|
||||
with:
|
||||
repo-token: ${{ steps.token.outputs.token }}
|
||||
only-labels: "needs-more-information"
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v5.0.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.8
|
||||
rev: v0.1.1
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
- --fix
|
||||
- id: ruff-format
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.10.0
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
- --quiet
|
||||
files: ^((homeassistant|pylint|script|tests)/.+)?[^/]+\.py$
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.2
|
||||
@@ -34,7 +39,7 @@ repos:
|
||||
hooks:
|
||||
- id: yamllint
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v3.0.3
|
||||
rev: v2.7.1
|
||||
hooks:
|
||||
- id: prettier
|
||||
- repo: https://github.com/cdce8p/python-typing-update
|
||||
|
||||
@@ -5,4 +5,3 @@ homeassistant/components/*/translations/*.json
|
||||
homeassistant/generated/*
|
||||
tests/components/lidarr/fixtures/initialize.js
|
||||
tests/components/lidarr/fixtures/initialize-wrong.js
|
||||
tests/fixtures/core/config/yaml_errors/
|
||||
|
||||
@@ -43,15 +43,11 @@ homeassistant.components.abode.*
|
||||
homeassistant.components.accuweather.*
|
||||
homeassistant.components.acer_projector.*
|
||||
homeassistant.components.actiontec.*
|
||||
homeassistant.components.adax.*
|
||||
homeassistant.components.adguard.*
|
||||
homeassistant.components.aftership.*
|
||||
homeassistant.components.air_quality.*
|
||||
homeassistant.components.airly.*
|
||||
homeassistant.components.airnow.*
|
||||
homeassistant.components.airthings_ble.*
|
||||
homeassistant.components.airvisual.*
|
||||
homeassistant.components.airvisual_pro.*
|
||||
homeassistant.components.airzone.*
|
||||
homeassistant.components.airzone_cloud.*
|
||||
homeassistant.components.aladdin_connect.*
|
||||
@@ -63,14 +59,10 @@ homeassistant.components.ambient_station.*
|
||||
homeassistant.components.amcrest.*
|
||||
homeassistant.components.ampio.*
|
||||
homeassistant.components.analytics.*
|
||||
homeassistant.components.android_ip_webcam.*
|
||||
homeassistant.components.androidtv_remote.*
|
||||
homeassistant.components.anova.*
|
||||
homeassistant.components.anthemav.*
|
||||
homeassistant.components.apcupsd.*
|
||||
homeassistant.components.apprise.*
|
||||
homeassistant.components.aqualogic.*
|
||||
homeassistant.components.aranet.*
|
||||
homeassistant.components.aseko_pool_live.*
|
||||
homeassistant.components.assist_pipeline.*
|
||||
homeassistant.components.asuswrt.*
|
||||
@@ -83,7 +75,6 @@ homeassistant.components.bayesian.*
|
||||
homeassistant.components.binary_sensor.*
|
||||
homeassistant.components.bitcoin.*
|
||||
homeassistant.components.blockchain.*
|
||||
homeassistant.components.blue_current.*
|
||||
homeassistant.components.bluetooth.*
|
||||
homeassistant.components.bluetooth_tracker.*
|
||||
homeassistant.components.bmw_connected_drive.*
|
||||
@@ -126,12 +117,9 @@ homeassistant.components.elgato.*
|
||||
homeassistant.components.elkm1.*
|
||||
homeassistant.components.emulated_hue.*
|
||||
homeassistant.components.energy.*
|
||||
homeassistant.components.enigma2.*
|
||||
homeassistant.components.esphome.*
|
||||
homeassistant.components.event.*
|
||||
homeassistant.components.evil_genius_labs.*
|
||||
homeassistant.components.evohome.*
|
||||
homeassistant.components.faa_delays.*
|
||||
homeassistant.components.fan.*
|
||||
homeassistant.components.fastdotcom.*
|
||||
homeassistant.components.feedreader.*
|
||||
@@ -139,7 +127,6 @@ homeassistant.components.file_upload.*
|
||||
homeassistant.components.filesize.*
|
||||
homeassistant.components.filter.*
|
||||
homeassistant.components.fitbit.*
|
||||
homeassistant.components.flexit_bacnet.*
|
||||
homeassistant.components.flux_led.*
|
||||
homeassistant.components.forecast_solar.*
|
||||
homeassistant.components.fritz.*
|
||||
@@ -163,7 +150,6 @@ homeassistant.components.hardkernel.*
|
||||
homeassistant.components.hardware.*
|
||||
homeassistant.components.here_travel_time.*
|
||||
homeassistant.components.history.*
|
||||
homeassistant.components.holiday.*
|
||||
homeassistant.components.homeassistant.exposed_entities
|
||||
homeassistant.components.homeassistant.triggers.event
|
||||
homeassistant.components.homeassistant_alerts.*
|
||||
@@ -194,7 +180,6 @@ homeassistant.components.image_upload.*
|
||||
homeassistant.components.imap.*
|
||||
homeassistant.components.input_button.*
|
||||
homeassistant.components.input_select.*
|
||||
homeassistant.components.input_text.*
|
||||
homeassistant.components.integration.*
|
||||
homeassistant.components.ipp.*
|
||||
homeassistant.components.iqvia.*
|
||||
@@ -216,11 +201,9 @@ homeassistant.components.ld2410_ble.*
|
||||
homeassistant.components.lidarr.*
|
||||
homeassistant.components.lifx.*
|
||||
homeassistant.components.light.*
|
||||
homeassistant.components.linear_garage_door.*
|
||||
homeassistant.components.litejet.*
|
||||
homeassistant.components.litterrobot.*
|
||||
homeassistant.components.local_ip.*
|
||||
homeassistant.components.local_todo.*
|
||||
homeassistant.components.lock.*
|
||||
homeassistant.components.logbook.*
|
||||
homeassistant.components.logger.*
|
||||
@@ -242,7 +225,6 @@ homeassistant.components.modbus.*
|
||||
homeassistant.components.modem_callerid.*
|
||||
homeassistant.components.moon.*
|
||||
homeassistant.components.mopeka.*
|
||||
homeassistant.components.motionmount.*
|
||||
homeassistant.components.mqtt.*
|
||||
homeassistant.components.mysensors.*
|
||||
homeassistant.components.nam.*
|
||||
@@ -279,7 +261,6 @@ homeassistant.components.proximity.*
|
||||
homeassistant.components.prusalink.*
|
||||
homeassistant.components.pure_energie.*
|
||||
homeassistant.components.purpleair.*
|
||||
homeassistant.components.pushbullet.*
|
||||
homeassistant.components.pvoutput.*
|
||||
homeassistant.components.qnap_qsw.*
|
||||
homeassistant.components.radarr.*
|
||||
@@ -329,8 +310,6 @@ homeassistant.components.statistics.*
|
||||
homeassistant.components.steamist.*
|
||||
homeassistant.components.stookalert.*
|
||||
homeassistant.components.stream.*
|
||||
homeassistant.components.streamlabswater.*
|
||||
homeassistant.components.suez_water.*
|
||||
homeassistant.components.sun.*
|
||||
homeassistant.components.surepetcare.*
|
||||
homeassistant.components.switch.*
|
||||
@@ -341,7 +320,6 @@ homeassistant.components.synology_dsm.*
|
||||
homeassistant.components.systemmonitor.*
|
||||
homeassistant.components.tag.*
|
||||
homeassistant.components.tailscale.*
|
||||
homeassistant.components.tailwind.*
|
||||
homeassistant.components.tami4.*
|
||||
homeassistant.components.tautulli.*
|
||||
homeassistant.components.tcp.*
|
||||
@@ -372,7 +350,6 @@ homeassistant.components.uptimerobot.*
|
||||
homeassistant.components.usb.*
|
||||
homeassistant.components.vacuum.*
|
||||
homeassistant.components.vallox.*
|
||||
homeassistant.components.valve.*
|
||||
homeassistant.components.velbus.*
|
||||
homeassistant.components.vlc_telnet.*
|
||||
homeassistant.components.wake_on_lan.*
|
||||
|
||||
Vendored
+1
-5
@@ -1,7 +1,3 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"charliermarsh.ruff",
|
||||
"esbenp.prettier-vscode",
|
||||
"ms-python.python"
|
||||
]
|
||||
"recommendations": ["esbenp.prettier-vscode", "ms-python.python"]
|
||||
}
|
||||
|
||||
Vendored
-8
@@ -22,14 +22,6 @@
|
||||
"args": ["--debug", "-c", "config", "--skip-pip"],
|
||||
"preLaunchTask": "Compile English translations"
|
||||
},
|
||||
{
|
||||
"name": "Home Assistant: Changed tests",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "pytest",
|
||||
"justMyCode": false,
|
||||
"args": ["--timeout=10", "--picked"],
|
||||
},
|
||||
{
|
||||
// Debug by attaching to local Home Assistant server using Remote Python Debugger.
|
||||
// See https://www.home-assistant.io/integrations/debugpy/
|
||||
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
// Please keep this file in sync with settings in home-assistant/.devcontainer/devcontainer.json
|
||||
"python.formatting.provider": "black",
|
||||
// Added --no-cov to work around TypeError: message must be set
|
||||
// https://github.com/microsoft/vscode-python/issues/14067
|
||||
"python.testing.pytestArgs": ["--no-cov"],
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
ignore: |
|
||||
azure-*.yml
|
||||
tests/fixtures/core/config/yaml_errors/
|
||||
rules:
|
||||
braces:
|
||||
level: error
|
||||
|
||||
+48
-97
@@ -86,8 +86,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/anova/ @Lash-L
|
||||
/homeassistant/components/anthemav/ @hyralex
|
||||
/tests/components/anthemav/ @hyralex
|
||||
/homeassistant/components/aosmith/ @bdr99
|
||||
/tests/components/aosmith/ @bdr99
|
||||
/homeassistant/components/apache_kafka/ @bachya
|
||||
/tests/components/apache_kafka/ @bachya
|
||||
/homeassistant/components/apcupsd/ @yuxincs
|
||||
@@ -153,10 +151,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/bizkaibus/ @UgaitzEtxebarria
|
||||
/homeassistant/components/blebox/ @bbx-a @riokuu
|
||||
/tests/components/blebox/ @bbx-a @riokuu
|
||||
/homeassistant/components/blink/ @fronzbot @mkmer
|
||||
/tests/components/blink/ @fronzbot @mkmer
|
||||
/homeassistant/components/blue_current/ @Floris272 @gleeuwen
|
||||
/tests/components/blue_current/ @Floris272 @gleeuwen
|
||||
/homeassistant/components/blink/ @fronzbot
|
||||
/tests/components/blink/ @fronzbot
|
||||
/homeassistant/components/bluemaestro/ @bdraco
|
||||
/tests/components/bluemaestro/ @bdraco
|
||||
/homeassistant/components/blueprint/ @home-assistant/core
|
||||
@@ -174,8 +170,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/bosch_shc/ @tschamm
|
||||
/homeassistant/components/braviatv/ @bieniu @Drafteed
|
||||
/tests/components/braviatv/ @bieniu @Drafteed
|
||||
/homeassistant/components/broadlink/ @danielhiversen @felipediel @L-I-Am @eifinger
|
||||
/tests/components/broadlink/ @danielhiversen @felipediel @L-I-Am @eifinger
|
||||
/homeassistant/components/broadlink/ @danielhiversen @felipediel @L-I-Am
|
||||
/tests/components/broadlink/ @danielhiversen @felipediel @L-I-Am
|
||||
/homeassistant/components/brother/ @bieniu
|
||||
/tests/components/brother/ @bieniu
|
||||
/homeassistant/components/brottsplatskartan/ @gjohansson-ST
|
||||
@@ -197,8 +193,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/camera/ @home-assistant/core
|
||||
/homeassistant/components/cast/ @emontnemery
|
||||
/tests/components/cast/ @emontnemery
|
||||
/homeassistant/components/ccm15/ @ocalvo
|
||||
/tests/components/ccm15/ @ocalvo
|
||||
/homeassistant/components/cert_expiry/ @jjlawren
|
||||
/tests/components/cert_expiry/ @jjlawren
|
||||
/homeassistant/components/circuit/ @braam
|
||||
@@ -211,8 +205,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/cloud/ @home-assistant/cloud
|
||||
/homeassistant/components/cloudflare/ @ludeeus @ctalkington
|
||||
/tests/components/cloudflare/ @ludeeus @ctalkington
|
||||
/homeassistant/components/co2signal/ @jpbede @VIKTORVAV99
|
||||
/tests/components/co2signal/ @jpbede @VIKTORVAV99
|
||||
/homeassistant/components/co2signal/ @jpbede
|
||||
/tests/components/co2signal/ @jpbede
|
||||
/homeassistant/components/coinbase/ @tombrien
|
||||
/tests/components/coinbase/ @tombrien
|
||||
/homeassistant/components/color_extractor/ @GenericStudent
|
||||
@@ -265,8 +259,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/denonavr/ @ol-iver @starkillerOG
|
||||
/homeassistant/components/derivative/ @afaucogney
|
||||
/tests/components/derivative/ @afaucogney
|
||||
/homeassistant/components/devialet/ @fwestenberg
|
||||
/tests/components/devialet/ @fwestenberg
|
||||
/homeassistant/components/device_automation/ @home-assistant/core
|
||||
/tests/components/device_automation/ @home-assistant/core
|
||||
/homeassistant/components/device_tracker/ @home-assistant/core
|
||||
@@ -301,8 +293,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/dormakaba_dkey/ @emontnemery
|
||||
/homeassistant/components/dremel_3d_printer/ @tkdrob
|
||||
/tests/components/dremel_3d_printer/ @tkdrob
|
||||
/homeassistant/components/drop_connect/ @ChandlerSystems @pfrazer
|
||||
/tests/components/drop_connect/ @ChandlerSystems @pfrazer
|
||||
/homeassistant/components/dsmr/ @Robbie1221 @frenck
|
||||
/tests/components/dsmr/ @Robbie1221 @frenck
|
||||
/homeassistant/components/dsmr_reader/ @depl0y @glodenox
|
||||
@@ -317,18 +307,20 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/eafm/ @Jc2k
|
||||
/homeassistant/components/easyenergy/ @klaasnicolaas
|
||||
/tests/components/easyenergy/ @klaasnicolaas
|
||||
/homeassistant/components/ecobee/ @marcolivierarsenault
|
||||
/tests/components/ecobee/ @marcolivierarsenault
|
||||
/homeassistant/components/ecobee/ @marthoc @marcolivierarsenault
|
||||
/tests/components/ecobee/ @marthoc @marcolivierarsenault
|
||||
/homeassistant/components/ecoforest/ @pjanuario
|
||||
/tests/components/ecoforest/ @pjanuario
|
||||
/homeassistant/components/econet/ @w1ll1am23
|
||||
/tests/components/econet/ @w1ll1am23
|
||||
/homeassistant/components/econet/ @vangorra @w1ll1am23
|
||||
/tests/components/econet/ @vangorra @w1ll1am23
|
||||
/homeassistant/components/ecovacs/ @OverloadUT @mib1185
|
||||
/homeassistant/components/ecowitt/ @pvizeli
|
||||
/tests/components/ecowitt/ @pvizeli
|
||||
/homeassistant/components/efergy/ @tkdrob
|
||||
/tests/components/efergy/ @tkdrob
|
||||
/homeassistant/components/egardia/ @jeroenterheerdt
|
||||
/homeassistant/components/eight_sleep/ @mezz64 @raman325
|
||||
/tests/components/eight_sleep/ @mezz64 @raman325
|
||||
/homeassistant/components/electrasmart/ @jafar-atili
|
||||
/tests/components/electrasmart/ @jafar-atili
|
||||
/homeassistant/components/electric_kiwi/ @mikey0000
|
||||
@@ -352,18 +344,20 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/energy/ @home-assistant/core
|
||||
/homeassistant/components/energyzero/ @klaasnicolaas
|
||||
/tests/components/energyzero/ @klaasnicolaas
|
||||
/homeassistant/components/enigma2/ @autinerd
|
||||
/homeassistant/components/enigma2/ @fbradyirl
|
||||
/homeassistant/components/enocean/ @bdurrer
|
||||
/tests/components/enocean/ @bdurrer
|
||||
/homeassistant/components/enphase_envoy/ @bdraco @cgarwood @dgomes @joostlek @catsmanac
|
||||
/tests/components/enphase_envoy/ @bdraco @cgarwood @dgomes @joostlek @catsmanac
|
||||
/homeassistant/components/enphase_envoy/ @bdraco @cgarwood @dgomes @joostlek
|
||||
/tests/components/enphase_envoy/ @bdraco @cgarwood @dgomes @joostlek
|
||||
/homeassistant/components/entur_public_transport/ @hfurubotten
|
||||
/homeassistant/components/environment_canada/ @gwww @michaeldavie
|
||||
/tests/components/environment_canada/ @gwww @michaeldavie
|
||||
/homeassistant/components/envisalink/ @ufodone
|
||||
/homeassistant/components/ephember/ @ttroy50
|
||||
/homeassistant/components/epson/ @pszafer
|
||||
/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 @kbx81 @bdraco
|
||||
@@ -381,8 +375,7 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/faa_delays/ @ntilley905
|
||||
/homeassistant/components/fan/ @home-assistant/core
|
||||
/tests/components/fan/ @home-assistant/core
|
||||
/homeassistant/components/fastdotcom/ @rohankapoorcom @erwindouna
|
||||
/tests/components/fastdotcom/ @rohankapoorcom @erwindouna
|
||||
/homeassistant/components/fastdotcom/ @rohankapoorcom
|
||||
/homeassistant/components/fibaro/ @rappenze
|
||||
/tests/components/fibaro/ @rappenze
|
||||
/homeassistant/components/file/ @fabaff
|
||||
@@ -403,8 +396,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/fivem/ @Sander0542
|
||||
/homeassistant/components/fjaraskupan/ @elupus
|
||||
/tests/components/fjaraskupan/ @elupus
|
||||
/homeassistant/components/flexit_bacnet/ @lellky @piotrbulinski
|
||||
/tests/components/flexit_bacnet/ @lellky @piotrbulinski
|
||||
/homeassistant/components/flick_electric/ @ZephireNZ
|
||||
/tests/components/flick_electric/ @ZephireNZ
|
||||
/homeassistant/components/flipr/ @cnico
|
||||
@@ -420,8 +411,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/forked_daapd/ @uvjustin
|
||||
/tests/components/forked_daapd/ @uvjustin
|
||||
/homeassistant/components/fortios/ @kimfrellsen
|
||||
/homeassistant/components/foscam/ @skgsergio @krmarien
|
||||
/tests/components/foscam/ @skgsergio @krmarien
|
||||
/homeassistant/components/foscam/ @skgsergio
|
||||
/tests/components/foscam/ @skgsergio
|
||||
/homeassistant/components/freebox/ @hacf-fr @Quentame
|
||||
/tests/components/freebox/ @hacf-fr @Quentame
|
||||
/homeassistant/components/freedompro/ @stefano055415
|
||||
@@ -432,8 +423,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/fritzbox/ @mib1185 @flabbamann
|
||||
/homeassistant/components/fritzbox_callmonitor/ @cdce8p
|
||||
/tests/components/fritzbox_callmonitor/ @cdce8p
|
||||
/homeassistant/components/fronius/ @farmio
|
||||
/tests/components/fronius/ @farmio
|
||||
/homeassistant/components/fronius/ @nielstron @farmio
|
||||
/tests/components/fronius/ @nielstron @farmio
|
||||
/homeassistant/components/frontend/ @home-assistant/frontend
|
||||
/tests/components/frontend/ @home-assistant/frontend
|
||||
/homeassistant/components/frontier_silicon/ @wlcrs
|
||||
@@ -488,8 +479,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/google_mail/ @tkdrob
|
||||
/homeassistant/components/google_sheets/ @tkdrob
|
||||
/tests/components/google_sheets/ @tkdrob
|
||||
/homeassistant/components/google_tasks/ @allenporter
|
||||
/tests/components/google_tasks/ @allenporter
|
||||
/homeassistant/components/google_travel_time/ @eifinger
|
||||
/tests/components/google_travel_time/ @eifinger
|
||||
/homeassistant/components/govee_ble/ @bdraco @PierreAronnax
|
||||
@@ -501,6 +490,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/greeneye_monitor/ @jkeljo
|
||||
/homeassistant/components/group/ @home-assistant/core
|
||||
/tests/components/group/ @home-assistant/core
|
||||
/homeassistant/components/growatt_server/ @muppet3000
|
||||
/tests/components/growatt_server/ @muppet3000
|
||||
/homeassistant/components/guardian/ @bachya
|
||||
/tests/components/guardian/ @bachya
|
||||
/homeassistant/components/habitica/ @ASMfreaK @leikoilja
|
||||
@@ -530,8 +521,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/hive/ @Rendili @KJonline
|
||||
/homeassistant/components/hlk_sw16/ @jameshilliard
|
||||
/tests/components/hlk_sw16/ @jameshilliard
|
||||
/homeassistant/components/holiday/ @jrieger
|
||||
/tests/components/holiday/ @jrieger
|
||||
/homeassistant/components/home_connect/ @DavidMStraub
|
||||
/tests/components/home_connect/ @DavidMStraub
|
||||
/homeassistant/components/home_plus_control/ @chemaaa
|
||||
@@ -597,8 +586,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/image_upload/ @home-assistant/core
|
||||
/homeassistant/components/imap/ @jbouwh
|
||||
/tests/components/imap/ @jbouwh
|
||||
/homeassistant/components/improv_ble/ @emontnemery
|
||||
/tests/components/improv_ble/ @emontnemery
|
||||
/homeassistant/components/incomfort/ @zxdavb
|
||||
/homeassistant/components/influxdb/ @mdegat01
|
||||
/tests/components/influxdb/ @mdegat01
|
||||
@@ -710,8 +697,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/life360/ @pnbruckner
|
||||
/homeassistant/components/light/ @home-assistant/core
|
||||
/tests/components/light/ @home-assistant/core
|
||||
/homeassistant/components/linear_garage_door/ @IceBotYT
|
||||
/tests/components/linear_garage_door/ @IceBotYT
|
||||
/homeassistant/components/linux_battery/ @fabaff
|
||||
/homeassistant/components/litejet/ @joncar
|
||||
/tests/components/litejet/ @joncar
|
||||
@@ -723,8 +708,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/local_calendar/ @allenporter
|
||||
/homeassistant/components/local_ip/ @issacg
|
||||
/tests/components/local_ip/ @issacg
|
||||
/homeassistant/components/local_todo/ @allenporter
|
||||
/tests/components/local_todo/ @allenporter
|
||||
/homeassistant/components/lock/ @home-assistant/core
|
||||
/tests/components/lock/ @home-assistant/core
|
||||
/homeassistant/components/logbook/ @home-assistant/core
|
||||
@@ -815,8 +798,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/motion_blinds/ @starkillerOG
|
||||
/homeassistant/components/motioneye/ @dermotduffy
|
||||
/tests/components/motioneye/ @dermotduffy
|
||||
/homeassistant/components/motionmount/ @RJPoelstra
|
||||
/tests/components/motionmount/ @RJPoelstra
|
||||
/homeassistant/components/mqtt/ @emontnemery @jbouwh
|
||||
/tests/components/mqtt/ @emontnemery @jbouwh
|
||||
/homeassistant/components/msteams/ @peroyvind
|
||||
@@ -826,6 +807,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/mutesync/ @currentoor
|
||||
/homeassistant/components/my/ @home-assistant/core
|
||||
/tests/components/my/ @home-assistant/core
|
||||
/homeassistant/components/myq/ @ehendrix23 @Lash-L
|
||||
/tests/components/myq/ @ehendrix23 @Lash-L
|
||||
/homeassistant/components/mysensors/ @MartinHjelmare @functionpointer
|
||||
/tests/components/mysensors/ @MartinHjelmare @functionpointer
|
||||
/homeassistant/components/mystrom/ @fabaff
|
||||
@@ -847,7 +830,6 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/netgear/ @hacf-fr @Quentame @starkillerOG
|
||||
/tests/components/netgear/ @hacf-fr @Quentame @starkillerOG
|
||||
/homeassistant/components/netgear_lte/ @tkdrob
|
||||
/tests/components/netgear_lte/ @tkdrob
|
||||
/homeassistant/components/network/ @home-assistant/core
|
||||
/tests/components/network/ @home-assistant/core
|
||||
/homeassistant/components/nexia/ @bdraco
|
||||
@@ -941,12 +923,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/oralb/ @bdraco @Lash-L
|
||||
/tests/components/oralb/ @bdraco @Lash-L
|
||||
/homeassistant/components/oru/ @bvlaicu
|
||||
/homeassistant/components/osoenergy/ @osohotwateriot
|
||||
/tests/components/osoenergy/ @osohotwateriot
|
||||
/homeassistant/components/otbr/ @home-assistant/core
|
||||
/tests/components/otbr/ @home-assistant/core
|
||||
/homeassistant/components/ourgroceries/ @OnFreund
|
||||
/tests/components/ourgroceries/ @OnFreund
|
||||
/homeassistant/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev
|
||||
/tests/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev
|
||||
/homeassistant/components/ovo_energy/ @timmo001
|
||||
@@ -961,8 +939,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/peco/ @IceBotYT
|
||||
/homeassistant/components/pegel_online/ @mib1185
|
||||
/tests/components/pegel_online/ @mib1185
|
||||
/homeassistant/components/permobil/ @IsakNyberg
|
||||
/tests/components/permobil/ @IsakNyberg
|
||||
/homeassistant/components/persistent_notification/ @home-assistant/core
|
||||
/tests/components/persistent_notification/ @home-assistant/core
|
||||
/homeassistant/components/philips_js/ @elupus
|
||||
@@ -999,11 +975,9 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/prometheus/ @knyar
|
||||
/homeassistant/components/prosegur/ @dgomes
|
||||
/tests/components/prosegur/ @dgomes
|
||||
/homeassistant/components/proximity/ @mib1185
|
||||
/tests/components/proximity/ @mib1185
|
||||
/homeassistant/components/proxmoxve/ @jhollowe @Corbeno
|
||||
/homeassistant/components/prusalink/ @balloob @Skaronator
|
||||
/tests/components/prusalink/ @balloob @Skaronator
|
||||
/homeassistant/components/prusalink/ @balloob
|
||||
/tests/components/prusalink/ @balloob
|
||||
/homeassistant/components/ps4/ @ktnrg45
|
||||
/tests/components/ps4/ @ktnrg45
|
||||
/homeassistant/components/pure_energie/ @klaasnicolaas
|
||||
@@ -1020,8 +994,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/pvoutput/ @frenck
|
||||
/homeassistant/components/pvpc_hourly_pricing/ @azogue
|
||||
/tests/components/pvpc_hourly_pricing/ @azogue
|
||||
/homeassistant/components/qbittorrent/ @geoffreylagaisse @finder39
|
||||
/tests/components/qbittorrent/ @geoffreylagaisse @finder39
|
||||
/homeassistant/components/qbittorrent/ @geoffreylagaisse
|
||||
/tests/components/qbittorrent/ @geoffreylagaisse
|
||||
/homeassistant/components/qingping/ @bdraco @skgsergio
|
||||
/tests/components/qingping/ @bdraco @skgsergio
|
||||
/homeassistant/components/qld_bushfire/ @exxamalte
|
||||
@@ -1061,10 +1035,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/recollect_waste/ @bachya
|
||||
/homeassistant/components/recorder/ @home-assistant/core
|
||||
/tests/components/recorder/ @home-assistant/core
|
||||
/homeassistant/components/recovery_mode/ @home-assistant/core
|
||||
/tests/components/recovery_mode/ @home-assistant/core
|
||||
/homeassistant/components/refoss/ @ashionky
|
||||
/tests/components/refoss/ @ashionky
|
||||
/homeassistant/components/rejseplanen/ @DarkFox
|
||||
/homeassistant/components/remote/ @home-assistant/core
|
||||
/tests/components/remote/ @home-assistant/core
|
||||
@@ -1076,9 +1046,7 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/reolink/ @starkillerOG
|
||||
/homeassistant/components/repairs/ @home-assistant/core
|
||||
/tests/components/repairs/ @home-assistant/core
|
||||
/homeassistant/components/repetier/ @ShadowBr0ther
|
||||
/homeassistant/components/rest_command/ @jpbede
|
||||
/tests/components/rest_command/ @jpbede
|
||||
/homeassistant/components/repetier/ @MTrab @ShadowBr0ther
|
||||
/homeassistant/components/rflink/ @javicalle
|
||||
/tests/components/rflink/ @javicalle
|
||||
/homeassistant/components/rfxtrx/ @danielhiversen @elupus @RobBie1221
|
||||
@@ -1087,8 +1055,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/rhasspy/ @balloob @synesthesiam
|
||||
/homeassistant/components/ridwell/ @bachya
|
||||
/tests/components/ridwell/ @bachya
|
||||
/homeassistant/components/ring/ @sdb9696
|
||||
/tests/components/ring/ @sdb9696
|
||||
/homeassistant/components/risco/ @OnFreund
|
||||
/tests/components/risco/ @OnFreund
|
||||
/homeassistant/components/rituals_perfume_genie/ @milanmeu @frenck
|
||||
@@ -1119,6 +1085,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/rympro/ @OnFreund @elad-bar @maorcc
|
||||
/homeassistant/components/sabnzbd/ @shaiu
|
||||
/tests/components/sabnzbd/ @shaiu
|
||||
/homeassistant/components/safe_mode/ @home-assistant/core
|
||||
/tests/components/safe_mode/ @home-assistant/core
|
||||
/homeassistant/components/saj/ @fredericvl
|
||||
/homeassistant/components/samsungtv/ @chemelli74 @epenet
|
||||
/tests/components/samsungtv/ @chemelli74 @epenet
|
||||
@@ -1259,22 +1227,18 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/stookwijzer/ @fwestenberg
|
||||
/homeassistant/components/stream/ @hunterjm @uvjustin @allenporter
|
||||
/tests/components/stream/ @hunterjm @uvjustin @allenporter
|
||||
/homeassistant/components/stt/ @home-assistant/core
|
||||
/tests/components/stt/ @home-assistant/core
|
||||
/homeassistant/components/stt/ @home-assistant/core @pvizeli
|
||||
/tests/components/stt/ @home-assistant/core @pvizeli
|
||||
/homeassistant/components/subaru/ @G-Two
|
||||
/tests/components/subaru/ @G-Two
|
||||
/homeassistant/components/suez_water/ @ooii
|
||||
/tests/components/suez_water/ @ooii
|
||||
/homeassistant/components/sun/ @Swamp-Ig
|
||||
/tests/components/sun/ @Swamp-Ig
|
||||
/homeassistant/components/sunweg/ @rokam
|
||||
/tests/components/sunweg/ @rokam
|
||||
/homeassistant/components/supla/ @mwegrzynek
|
||||
/homeassistant/components/surepetcare/ @benleb @danielhiversen
|
||||
/tests/components/surepetcare/ @benleb @danielhiversen
|
||||
/homeassistant/components/swiss_hydrological_data/ @fabaff
|
||||
/homeassistant/components/swiss_public_transport/ @fabaff @miaucl
|
||||
/tests/components/swiss_public_transport/ @fabaff @miaucl
|
||||
/homeassistant/components/swiss_public_transport/ @fabaff
|
||||
/homeassistant/components/switch/ @home-assistant/core
|
||||
/tests/components/switch/ @home-assistant/core
|
||||
/homeassistant/components/switch_as_x/ @home-assistant/core
|
||||
@@ -1297,16 +1261,12 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/synology_srm/ @aerialls
|
||||
/homeassistant/components/system_bridge/ @timmo001
|
||||
/tests/components/system_bridge/ @timmo001
|
||||
/homeassistant/components/systemmonitor/ @gjohansson-ST
|
||||
/tests/components/systemmonitor/ @gjohansson-ST
|
||||
/homeassistant/components/tado/ @michaelarnauts @chiefdragon @erwindouna
|
||||
/tests/components/tado/ @michaelarnauts @chiefdragon @erwindouna
|
||||
/homeassistant/components/tado/ @michaelarnauts @chiefdragon
|
||||
/tests/components/tado/ @michaelarnauts @chiefdragon
|
||||
/homeassistant/components/tag/ @balloob @dmulcahey
|
||||
/tests/components/tag/ @balloob @dmulcahey
|
||||
/homeassistant/components/tailscale/ @frenck
|
||||
/tests/components/tailscale/ @frenck
|
||||
/homeassistant/components/tailwind/ @frenck
|
||||
/tests/components/tailwind/ @frenck
|
||||
/homeassistant/components/tami4/ @Guy293
|
||||
/tests/components/tami4/ @Guy293
|
||||
/homeassistant/components/tankerkoenig/ @guillempages @mib1185
|
||||
@@ -1322,8 +1282,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/template/ @PhracturedBlue @tetienne @home-assistant/core
|
||||
/homeassistant/components/tesla_wall_connector/ @einarhauks
|
||||
/tests/components/tesla_wall_connector/ @einarhauks
|
||||
/homeassistant/components/tessie/ @Bre77
|
||||
/tests/components/tessie/ @Bre77
|
||||
/homeassistant/components/text/ @home-assistant/core
|
||||
/tests/components/text/ @home-assistant/core
|
||||
/homeassistant/components/tfiac/ @fredrike @mellado
|
||||
@@ -1345,8 +1303,6 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/time_date/ @fabaff
|
||||
/tests/components/time_date/ @fabaff
|
||||
/homeassistant/components/tmb/ @alemuro
|
||||
/homeassistant/components/todo/ @home-assistant/core
|
||||
/tests/components/todo/ @home-assistant/core
|
||||
/homeassistant/components/todoist/ @boralyl
|
||||
/tests/components/todoist/ @boralyl
|
||||
/homeassistant/components/tolo/ @MatthiasLohr
|
||||
@@ -1355,8 +1311,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/tomorrowio/ @raman325 @lymanepp
|
||||
/homeassistant/components/totalconnect/ @austinmroczek
|
||||
/tests/components/totalconnect/ @austinmroczek
|
||||
/homeassistant/components/tplink/ @rytilahti @thegardenmonkey @bdraco
|
||||
/tests/components/tplink/ @rytilahti @thegardenmonkey @bdraco
|
||||
/homeassistant/components/tplink/ @rytilahti @thegardenmonkey
|
||||
/tests/components/tplink/ @rytilahti @thegardenmonkey
|
||||
/homeassistant/components/tplink_omada/ @MarkGodwin
|
||||
/tests/components/tplink_omada/ @MarkGodwin
|
||||
/homeassistant/components/traccar/ @ludeeus
|
||||
@@ -1377,8 +1333,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/transmission/ @engrbm87 @JPHutchins
|
||||
/homeassistant/components/trend/ @jpbede
|
||||
/tests/components/trend/ @jpbede
|
||||
/homeassistant/components/tts/ @home-assistant/core
|
||||
/tests/components/tts/ @home-assistant/core
|
||||
/homeassistant/components/tts/ @home-assistant/core @pvizeli
|
||||
/tests/components/tts/ @home-assistant/core @pvizeli
|
||||
/homeassistant/components/tuya/ @Tuya @zlinoliver @frenck
|
||||
/tests/components/tuya/ @Tuya @zlinoliver @frenck
|
||||
/homeassistant/components/twentemilieu/ @frenck
|
||||
@@ -1391,7 +1347,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/ukraine_alarm/ @PaulAnnekov
|
||||
/homeassistant/components/unifi/ @Kane610
|
||||
/tests/components/unifi/ @Kane610
|
||||
/homeassistant/components/unifi_direct/ @tofuSCHNITZEL
|
||||
/homeassistant/components/unifiled/ @florisvdk
|
||||
/homeassistant/components/unifiprotect/ @AngellusMortis @bdraco
|
||||
/tests/components/unifiprotect/ @AngellusMortis @bdraco
|
||||
@@ -1414,26 +1369,22 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/usgs_earthquakes_feed/ @exxamalte
|
||||
/homeassistant/components/utility_meter/ @dgomes
|
||||
/tests/components/utility_meter/ @dgomes
|
||||
/homeassistant/components/v2c/ @dgomes
|
||||
/tests/components/v2c/ @dgomes
|
||||
/homeassistant/components/vacuum/ @home-assistant/core
|
||||
/tests/components/vacuum/ @home-assistant/core
|
||||
/homeassistant/components/vallox/ @andre-richter @slovdahl @viiru-
|
||||
/tests/components/vallox/ @andre-richter @slovdahl @viiru-
|
||||
/homeassistant/components/valve/ @home-assistant/core
|
||||
/tests/components/valve/ @home-assistant/core
|
||||
/homeassistant/components/velbus/ @Cereal2nd @brefra
|
||||
/tests/components/velbus/ @Cereal2nd @brefra
|
||||
/homeassistant/components/velux/ @Julius2342
|
||||
/homeassistant/components/venstar/ @garbled1 @jhollowe
|
||||
/tests/components/venstar/ @garbled1 @jhollowe
|
||||
/homeassistant/components/verisure/ @frenck
|
||||
/tests/components/verisure/ @frenck
|
||||
/homeassistant/components/versasense/ @imstevenxyz
|
||||
/homeassistant/components/version/ @ludeeus
|
||||
/tests/components/version/ @ludeeus
|
||||
/homeassistant/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja
|
||||
/tests/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja
|
||||
/homeassistant/components/vicare/ @CFenner
|
||||
/tests/components/vicare/ @CFenner
|
||||
/homeassistant/components/vesync/ @markperdue @webdjoe @thegardenmonkey
|
||||
/tests/components/vesync/ @markperdue @webdjoe @thegardenmonkey
|
||||
/homeassistant/components/vilfo/ @ManneW
|
||||
/tests/components/vilfo/ @ManneW
|
||||
/homeassistant/components/vivotek/ @HarlemSquirrel
|
||||
@@ -1544,8 +1495,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/zerproc/ @emlove
|
||||
/homeassistant/components/zeversolar/ @kvanzuijlen
|
||||
/tests/components/zeversolar/ @kvanzuijlen
|
||||
/homeassistant/components/zha/ @dmulcahey @adminiuga @puddly @TheJulianJES
|
||||
/tests/components/zha/ @dmulcahey @adminiuga @puddly @TheJulianJES
|
||||
/homeassistant/components/zha/ @dmulcahey @adminiuga @puddly
|
||||
/tests/components/zha/ @dmulcahey @adminiuga @puddly
|
||||
/homeassistant/components/zodiac/ @JulienTant
|
||||
/tests/components/zodiac/ @JulienTant
|
||||
/homeassistant/components/zone/ @home-assistant/core
|
||||
|
||||
+1
-4
@@ -1,12 +1,9 @@
|
||||
# Automatically generated by hassfest.
|
||||
#
|
||||
# To update, run python3 -m script.hassfest -p docker
|
||||
ARG BUILD_FROM
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# Synchronize with homeassistant/core.py:async_stop
|
||||
ENV \
|
||||
S6_SERVICES_GRACETIME=240000
|
||||
S6_SERVICES_GRACETIME=220000
|
||||
|
||||
ARG QEMU_CPU
|
||||
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
# Uninstall pre-installed formatting and linting tools
|
||||
# They would conflict with our pinned versions
|
||||
RUN \
|
||||
pipx uninstall pydocstyle \
|
||||
pipx uninstall black \
|
||||
&& pipx uninstall pydocstyle \
|
||||
&& pipx uninstall pycodestyle \
|
||||
&& pipx uninstall mypy \
|
||||
&& pipx uninstall pylint
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
image: ghcr.io/home-assistant/{arch}-homeassistant
|
||||
build_from:
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2023.10.1
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2023.10.1
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2023.10.1
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2023.10.1
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2023.10.1
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2023.10.0
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2023.10.0
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2023.10.0
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2023.10.0
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2023.10.0
|
||||
codenotary:
|
||||
signer: notary@home-assistant.io
|
||||
base_image: notary@home-assistant.io
|
||||
|
||||
@@ -93,9 +93,7 @@ def get_arguments() -> argparse.Namespace:
|
||||
help="Directory that contains the Home Assistant configuration",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--recovery-mode",
|
||||
action="store_true",
|
||||
help="Start Home Assistant in recovery mode",
|
||||
"--safe-mode", action="store_true", help="Start Home Assistant in safe mode"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--debug", action="store_true", help="Start Home Assistant in debug mode"
|
||||
@@ -185,9 +183,7 @@ def main() -> int:
|
||||
ensure_config_path(config_dir)
|
||||
|
||||
# pylint: disable-next=import-outside-toplevel
|
||||
from . import config, runner
|
||||
|
||||
safe_mode = config.safe_mode_enabled(config_dir)
|
||||
from . import runner
|
||||
|
||||
runtime_conf = runner.RuntimeConfig(
|
||||
config_dir=config_dir,
|
||||
@@ -197,10 +193,9 @@ def main() -> int:
|
||||
log_no_color=args.log_no_color,
|
||||
skip_pip=args.skip_pip,
|
||||
skip_pip_packages=args.skip_pip_packages,
|
||||
recovery_mode=args.recovery_mode,
|
||||
safe_mode=args.safe_mode,
|
||||
debug=args.debug,
|
||||
open_ui=args.open_ui,
|
||||
safe_mode=safe_mode,
|
||||
)
|
||||
|
||||
fault_file_name = os.path.join(config_dir, FAULT_LOG_FILENAME)
|
||||
|
||||
@@ -280,8 +280,7 @@ class AuthManager:
|
||||
credentials=credentials,
|
||||
name=info.name,
|
||||
is_active=info.is_active,
|
||||
group_ids=[GROUP_ID_ADMIN if info.group is None else info.group],
|
||||
local_only=info.local_only,
|
||||
group_ids=[GROUP_ID_ADMIN],
|
||||
)
|
||||
|
||||
self.hass.bus.async_fire(EVENT_USER_ADDED, {"user_id": user.id})
|
||||
|
||||
@@ -134,5 +134,3 @@ class UserMeta(NamedTuple):
|
||||
|
||||
name: str | None
|
||||
is_active: bool
|
||||
group: str | None = None
|
||||
local_only: bool | None = None
|
||||
|
||||
@@ -19,7 +19,6 @@ from homeassistant.const import (
|
||||
from homeassistant.helpers.area_registry import EVENT_AREA_REGISTRY_UPDATED
|
||||
from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED
|
||||
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
||||
from homeassistant.helpers.issue_registry import EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED
|
||||
|
||||
# These are events that do not contain any sensitive data
|
||||
# Except for state_changed, which is handled accordingly.
|
||||
@@ -29,7 +28,6 @@ SUBSCRIBE_ALLOWLIST: Final[set[str]] = {
|
||||
EVENT_CORE_CONFIG_UPDATE,
|
||||
EVENT_DEVICE_REGISTRY_UPDATED,
|
||||
EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
||||
EVENT_LOVELACE_UPDATED,
|
||||
EVENT_PANELS_UPDATED,
|
||||
EVENT_RECORDER_5MIN_STATISTICS_GENERATED,
|
||||
|
||||
@@ -5,7 +5,9 @@ from collections.abc import Mapping
|
||||
|
||||
ValueType = (
|
||||
# Example: entities.all = { read: true, control: true }
|
||||
Mapping[str, bool] | bool | None
|
||||
Mapping[str, bool]
|
||||
| bool
|
||||
| None
|
||||
)
|
||||
|
||||
# Example: entities.domains = { light: … }
|
||||
|
||||
@@ -44,11 +44,7 @@ class CommandLineAuthProvider(AuthProvider):
|
||||
DEFAULT_TITLE = "Command Line Authentication"
|
||||
|
||||
# which keys to accept from a program's stdout
|
||||
ALLOWED_META_KEYS = (
|
||||
"name",
|
||||
"group",
|
||||
"local_only",
|
||||
)
|
||||
ALLOWED_META_KEYS = ("name",)
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
"""Extend parent's __init__.
|
||||
@@ -122,15 +118,10 @@ class CommandLineAuthProvider(AuthProvider):
|
||||
) -> UserMeta:
|
||||
"""Return extra user metadata for credentials.
|
||||
|
||||
Currently, supports name, group and local_only.
|
||||
Currently, only name is supported.
|
||||
"""
|
||||
meta = self._user_meta.get(credentials.data["username"], {})
|
||||
return UserMeta(
|
||||
name=meta.get("name"),
|
||||
is_active=True,
|
||||
group=meta.get("group"),
|
||||
local_only=meta.get("local_only") == "true",
|
||||
)
|
||||
return UserMeta(name=meta.get("name"), is_active=True)
|
||||
|
||||
|
||||
class CommandLineLoginFlow(LoginFlow):
|
||||
|
||||
@@ -10,11 +10,10 @@ from typing import Any, cast
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import async_get_hass, callback
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
|
||||
from ..models import Credentials, UserMeta
|
||||
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||
@@ -22,28 +21,10 @@ from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||
AUTH_PROVIDER_TYPE = "legacy_api_password"
|
||||
CONF_API_PASSWORD = "api_password"
|
||||
|
||||
_CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend(
|
||||
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend(
|
||||
{vol.Required(CONF_API_PASSWORD): cv.string}, extra=vol.PREVENT_EXTRA
|
||||
)
|
||||
|
||||
|
||||
def _create_repair_and_validate(config: dict[str, Any]) -> dict[str, Any]:
|
||||
async_create_issue(
|
||||
async_get_hass(),
|
||||
"auth",
|
||||
"deprecated_legacy_api_password",
|
||||
breaks_in_ha_version="2024.6.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_legacy_api_password",
|
||||
)
|
||||
|
||||
return _CONFIG_SCHEMA(config) # type: ignore[no-any-return]
|
||||
|
||||
|
||||
CONFIG_SCHEMA = _create_repair_and_validate
|
||||
|
||||
|
||||
LEGACY_USER_NAME = "Legacy API password user"
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.network import is_cloud_connection
|
||||
|
||||
from .. import InvalidAuthError
|
||||
from ..models import Credentials, RefreshToken, UserMeta
|
||||
@@ -193,8 +192,11 @@ class TrustedNetworksAuthProvider(AuthProvider):
|
||||
if any(ip_addr in trusted_proxy for trusted_proxy in self.trusted_proxies):
|
||||
raise InvalidAuthError("Can't allow access from a proxy server")
|
||||
|
||||
if is_cloud_connection(self.hass):
|
||||
raise InvalidAuthError("Can't allow access from Home Assistant Cloud")
|
||||
if "cloud" in self.hass.config.components:
|
||||
from hass_nabucasa import remote # pylint: disable=import-outside-toplevel
|
||||
|
||||
if remote.is_cloud_request.get():
|
||||
raise InvalidAuthError("Can't allow access from Home Assistant Cloud")
|
||||
|
||||
@callback
|
||||
def async_validate_refresh_token(
|
||||
|
||||
+15
-23
@@ -27,7 +27,6 @@ from .const import (
|
||||
from .exceptions import HomeAssistantError
|
||||
from .helpers import (
|
||||
area_registry,
|
||||
config_validation as cv,
|
||||
device_registry,
|
||||
entity,
|
||||
entity_registry,
|
||||
@@ -42,7 +41,6 @@ from .setup import (
|
||||
DATA_SETUP,
|
||||
DATA_SETUP_STARTED,
|
||||
DATA_SETUP_TIME,
|
||||
async_notify_setup_error,
|
||||
async_set_domains_to_be_loaded,
|
||||
async_setup_component,
|
||||
)
|
||||
@@ -122,7 +120,6 @@ async def async_setup_hass(
|
||||
runtime_config.log_no_color,
|
||||
)
|
||||
|
||||
hass.config.safe_mode = runtime_config.safe_mode
|
||||
hass.config.skip_pip = runtime_config.skip_pip
|
||||
hass.config.skip_pip_packages = runtime_config.skip_pip_packages
|
||||
if runtime_config.skip_pip or runtime_config.skip_pip_packages:
|
||||
@@ -140,14 +137,14 @@ async def async_setup_hass(
|
||||
config_dict = None
|
||||
basic_setup_success = False
|
||||
|
||||
if not (recovery_mode := runtime_config.recovery_mode):
|
||||
if not (safe_mode := runtime_config.safe_mode):
|
||||
await hass.async_add_executor_job(conf_util.process_ha_config_upgrade, hass)
|
||||
|
||||
try:
|
||||
config_dict = await conf_util.async_hass_config_yaml(hass)
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error(
|
||||
"Failed to parse configuration.yaml: %s. Activating recovery mode",
|
||||
"Failed to parse configuration.yaml: %s. Activating safe mode",
|
||||
err,
|
||||
)
|
||||
else:
|
||||
@@ -159,24 +156,24 @@ async def async_setup_hass(
|
||||
)
|
||||
|
||||
if config_dict is None:
|
||||
recovery_mode = True
|
||||
safe_mode = True
|
||||
|
||||
elif not basic_setup_success:
|
||||
_LOGGER.warning("Unable to set up core integrations. Activating recovery mode")
|
||||
recovery_mode = True
|
||||
_LOGGER.warning("Unable to set up core integrations. Activating safe mode")
|
||||
safe_mode = True
|
||||
|
||||
elif (
|
||||
"frontend" in hass.data.get(DATA_SETUP, {})
|
||||
and "frontend" not in hass.config.components
|
||||
):
|
||||
_LOGGER.warning("Detected that frontend did not load. Activating recovery mode")
|
||||
_LOGGER.warning("Detected that frontend did not load. Activating safe mode")
|
||||
# Ask integrations to shut down. It's messy but we can't
|
||||
# do a clean stop without knowing what is broken
|
||||
with contextlib.suppress(asyncio.TimeoutError):
|
||||
async with hass.timeout.async_timeout(10):
|
||||
await hass.async_stop()
|
||||
|
||||
recovery_mode = True
|
||||
safe_mode = True
|
||||
old_config = hass.config
|
||||
old_logging = hass.data.get(DATA_LOGGING)
|
||||
|
||||
@@ -190,18 +187,16 @@ async def async_setup_hass(
|
||||
# Setup loader cache after the config dir has been set
|
||||
loader.async_setup(hass)
|
||||
|
||||
if recovery_mode:
|
||||
_LOGGER.info("Starting in recovery mode")
|
||||
hass.config.recovery_mode = True
|
||||
if safe_mode:
|
||||
_LOGGER.info("Starting in safe mode")
|
||||
hass.config.safe_mode = True
|
||||
|
||||
http_conf = (await http.async_get_last_config(hass)) or {}
|
||||
|
||||
await async_from_config_dict(
|
||||
{"recovery_mode": {}, "http": http_conf},
|
||||
{"safe_mode": {}, "http": http_conf},
|
||||
hass,
|
||||
)
|
||||
elif hass.config.safe_mode:
|
||||
_LOGGER.info("Starting in safe mode")
|
||||
|
||||
if runtime_config.open_ui:
|
||||
hass.add_job(open_hass_ui, hass)
|
||||
@@ -294,8 +289,7 @@ async def async_from_config_dict(
|
||||
try:
|
||||
await conf_util.async_process_ha_core_config(hass, core_config)
|
||||
except vol.Invalid as config_err:
|
||||
conf_util.async_log_schema_error(config_err, core.DOMAIN, core_config, hass)
|
||||
async_notify_setup_error(hass, core.DOMAIN)
|
||||
conf_util.async_log_exception(config_err, "homeassistant", core_config, hass)
|
||||
return None
|
||||
except HomeAssistantError:
|
||||
_LOGGER.error(
|
||||
@@ -401,7 +395,7 @@ def async_enable_logging(
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
|
||||
sys.excepthook = lambda *args: logging.getLogger(None).exception(
|
||||
"Uncaught exception", exc_info=args
|
||||
"Uncaught exception", exc_info=args # type: ignore[arg-type]
|
||||
)
|
||||
threading.excepthook = lambda args: logging.getLogger(None).exception(
|
||||
"Uncaught thread exception",
|
||||
@@ -474,12 +468,10 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
|
||||
def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
|
||||
"""Get domains of components to set up."""
|
||||
# Filter out the repeating and common config section [homeassistant]
|
||||
domains = {
|
||||
domain for key in config if (domain := cv.domain_key(key)) != core.DOMAIN
|
||||
}
|
||||
domains = {key.partition(" ")[0] for key in config if key != core.DOMAIN}
|
||||
|
||||
# Add config entry domains
|
||||
if not hass.config.recovery_mode:
|
||||
if not hass.config.safe_mode:
|
||||
domains.update(hass.config_entries.async_domains())
|
||||
|
||||
# Make sure the Hass.io component is loaded
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"domain": "eq3",
|
||||
"name": "eQ-3",
|
||||
"integrations": ["maxcube"]
|
||||
"integrations": ["eq3btsmart", "maxcube"]
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"domain": "flexit",
|
||||
"name": "Flexit",
|
||||
"integrations": ["flexit", "flexit_bacnet"]
|
||||
}
|
||||
@@ -11,7 +11,6 @@
|
||||
"google_maps",
|
||||
"google_pubsub",
|
||||
"google_sheets",
|
||||
"google_tasks",
|
||||
"google_translate",
|
||||
"google_travel_time",
|
||||
"google_wifi",
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
},
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["jaraco.abode", "lomond"],
|
||||
"requirements": ["jaraco.abode==3.3.0", "jaraco.functools==3.9.0"]
|
||||
"requirements": ["jaraco.abode==3.3.0"]
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ ABODE_TEMPERATURE_UNIT_HA_UNIT = {
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AbodeSensorDescriptionMixin:
|
||||
"""Mixin for Abode sensor."""
|
||||
|
||||
@@ -35,7 +35,7 @@ class AbodeSensorDescriptionMixin:
|
||||
native_unit_of_measurement_fn: Callable[[AbodeSense], str]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AbodeSensorDescription(SensorEntityDescription, AbodeSensorDescriptionMixin):
|
||||
"""Class describing Abode sensor entities."""
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["accuweather"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["accuweather==2.1.1"]
|
||||
"requirements": ["accuweather==1.0.0"]
|
||||
}
|
||||
|
||||
@@ -45,14 +45,14 @@ from .const import (
|
||||
PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AccuWeatherSensorDescriptionMixin:
|
||||
"""Mixin for AccuWeather sensor."""
|
||||
|
||||
value_fn: Callable[[dict[str, Any]], str | int | float | None]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AccuWeatherSensorDescription(
|
||||
SensorEntityDescription, AccuWeatherSensorDescriptionMixin
|
||||
):
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/acmeda",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aiopulse"],
|
||||
"requirements": ["aiopulse==0.4.4"]
|
||||
"requirements": ["aiopulse==0.4.3"]
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
||||
# convert title and unique_id to string
|
||||
if config_entry.version == 1:
|
||||
if isinstance(config_entry.unique_id, int):
|
||||
hass.config_entries.async_update_entry( # type: ignore[unreachable]
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
unique_id=str(config_entry.unique_id),
|
||||
title=str(config_entry.title),
|
||||
|
||||
@@ -137,7 +137,7 @@ class LocalAdaxDevice(ClimateEntity):
|
||||
_attr_target_temperature_step = PRECISION_WHOLE
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
def __init__(self, adax_data_handler: AdaxLocal, unique_id: str) -> None:
|
||||
def __init__(self, adax_data_handler, unique_id):
|
||||
"""Initialize the heater."""
|
||||
self._adax_data_handler = adax_data_handler
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
@@ -36,9 +36,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 2
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle the initial step."""
|
||||
data_schema = vol.Schema(
|
||||
{
|
||||
@@ -61,9 +59,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
return await self.async_step_local()
|
||||
return await self.async_step_cloud()
|
||||
|
||||
async def async_step_local(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
async def async_step_local(self, user_input=None):
|
||||
"""Handle the local step."""
|
||||
data_schema = vol.Schema(
|
||||
{vol.Required(WIFI_SSID): str, vol.Required(WIFI_PSWD): str}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/adax",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["adax", "adax_local"],
|
||||
"requirements": ["adax==0.4.0", "Adax-local==0.1.5"]
|
||||
"requirements": ["adax==0.2.0", "Adax-local==0.1.5"]
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["adguardhome"],
|
||||
"requirements": ["adguardhome==0.6.3"]
|
||||
"requirements": ["adguardhome==0.6.1"]
|
||||
}
|
||||
|
||||
@@ -22,13 +22,20 @@ SCAN_INTERVAL = timedelta(seconds=300)
|
||||
PARALLEL_UPDATES = 4
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class AdGuardHomeEntityDescription(SensorEntityDescription):
|
||||
"""Describes AdGuard Home sensor entity."""
|
||||
@dataclass
|
||||
class AdGuardHomeEntityDescriptionMixin:
|
||||
"""Mixin for required keys."""
|
||||
|
||||
value_fn: Callable[[AdGuardHome], Coroutine[Any, Any, int | float]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class AdGuardHomeEntityDescription(
|
||||
SensorEntityDescription, AdGuardHomeEntityDescriptionMixin
|
||||
):
|
||||
"""Describes AdGuard Home sensor entity."""
|
||||
|
||||
|
||||
SENSORS: tuple[AdGuardHomeEntityDescription, ...] = (
|
||||
AdGuardHomeEntityDescription(
|
||||
key="dns_queries",
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"ssl": "[%key:common::config_flow::data::ssl%]",
|
||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
|
||||
},
|
||||
"data_description": {
|
||||
"host": "The hostname or IP address of the device running your AdGuard Home."
|
||||
}
|
||||
},
|
||||
"hassio_confirm": {
|
||||
|
||||
@@ -21,15 +21,22 @@ SCAN_INTERVAL = timedelta(seconds=10)
|
||||
PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class AdGuardHomeSwitchEntityDescription(SwitchEntityDescription):
|
||||
"""Describes AdGuard Home switch entity."""
|
||||
@dataclass
|
||||
class AdGuardHomeSwitchEntityDescriptionMixin:
|
||||
"""Mixin for required keys."""
|
||||
|
||||
is_on_fn: Callable[[AdGuardHome], Callable[[], Coroutine[Any, Any, bool]]]
|
||||
turn_on_fn: Callable[[AdGuardHome], Callable[[], Coroutine[Any, Any, None]]]
|
||||
turn_off_fn: Callable[[AdGuardHome], Callable[[], Coroutine[Any, Any, None]]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class AdGuardHomeSwitchEntityDescription(
|
||||
SwitchEntityDescription, AdGuardHomeSwitchEntityDescriptionMixin
|
||||
):
|
||||
"""Describes AdGuard Home switch entity."""
|
||||
|
||||
|
||||
SWITCHES: tuple[AdGuardHomeSwitchEntityDescription, ...] = (
|
||||
AdGuardHomeSwitchEntityDescription(
|
||||
key="protection",
|
||||
|
||||
@@ -8,7 +8,6 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import ADVANTAGE_AIR_RETRY, DOMAIN
|
||||
@@ -27,7 +26,6 @@ PLATFORMS = [
|
||||
]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
REQUEST_REFRESH_DELAY = 0.5
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
@@ -53,9 +51,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
name="Advantage Air",
|
||||
update_method=async_get,
|
||||
update_interval=timedelta(seconds=ADVANTAGE_AIR_SYNC_INTERVAL),
|
||||
request_refresh_debouncer=Debouncer(
|
||||
hass, _LOGGER, cooldown=REQUEST_REFRESH_DELAY, immediate=False
|
||||
),
|
||||
)
|
||||
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
@@ -21,7 +21,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
ADVANTAGE_AIR_AUTOFAN_ENABLED,
|
||||
ADVANTAGE_AIR_STATE_CLOSE,
|
||||
ADVANTAGE_AIR_STATE_OFF,
|
||||
ADVANTAGE_AIR_STATE_ON,
|
||||
@@ -40,6 +39,16 @@ ADVANTAGE_AIR_HVAC_MODES = {
|
||||
}
|
||||
HASS_HVAC_MODES = {v: k for k, v in ADVANTAGE_AIR_HVAC_MODES.items()}
|
||||
|
||||
ADVANTAGE_AIR_FAN_MODES = {
|
||||
"autoAA": FAN_AUTO,
|
||||
"low": FAN_LOW,
|
||||
"medium": FAN_MEDIUM,
|
||||
"high": FAN_HIGH,
|
||||
}
|
||||
HASS_FAN_MODES = {v: k for k, v in ADVANTAGE_AIR_FAN_MODES.items()}
|
||||
FAN_SPEEDS = {FAN_LOW: 30, FAN_MEDIUM: 60, FAN_HIGH: 100}
|
||||
|
||||
ADVANTAGE_AIR_AUTOFAN = "aaAutoFanModeEnabled"
|
||||
ADVANTAGE_AIR_MYZONE = "MyZone"
|
||||
ADVANTAGE_AIR_MYAUTO = "MyAuto"
|
||||
ADVANTAGE_AIR_MYAUTO_ENABLED = "myAutoModeEnabled"
|
||||
@@ -47,7 +56,6 @@ ADVANTAGE_AIR_MYTEMP = "MyTemp"
|
||||
ADVANTAGE_AIR_MYTEMP_ENABLED = "climateControlModeEnabled"
|
||||
ADVANTAGE_AIR_HEAT_TARGET = "myAutoHeatTargetTemp"
|
||||
ADVANTAGE_AIR_COOL_TARGET = "myAutoCoolTargetTemp"
|
||||
ADVANTAGE_AIR_MYFAN = "autoAA"
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -77,25 +85,27 @@ async def async_setup_entry(
|
||||
class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
"""AdvantageAir AC unit."""
|
||||
|
||||
_attr_fan_modes = [FAN_LOW, FAN_MEDIUM, FAN_HIGH, FAN_AUTO]
|
||||
_attr_fan_modes = [FAN_LOW, FAN_MEDIUM, FAN_HIGH]
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
_attr_target_temperature_step = PRECISION_WHOLE
|
||||
_attr_max_temp = 32
|
||||
_attr_min_temp = 16
|
||||
_attr_name = None
|
||||
|
||||
_attr_hvac_modes = [
|
||||
HVACMode.OFF,
|
||||
HVACMode.COOL,
|
||||
HVACMode.HEAT,
|
||||
HVACMode.FAN_ONLY,
|
||||
HVACMode.DRY,
|
||||
]
|
||||
|
||||
_attr_supported_features = ClimateEntityFeature.FAN_MODE
|
||||
|
||||
def __init__(self, instance: AdvantageAirData, ac_key: str) -> None:
|
||||
"""Initialize an AdvantageAir AC unit."""
|
||||
super().__init__(instance, ac_key)
|
||||
|
||||
self._attr_supported_features = ClimateEntityFeature.FAN_MODE
|
||||
self._attr_hvac_modes = [
|
||||
HVACMode.OFF,
|
||||
HVACMode.COOL,
|
||||
HVACMode.HEAT,
|
||||
HVACMode.FAN_ONLY,
|
||||
HVACMode.DRY,
|
||||
]
|
||||
# Set supported features and HVAC modes based on current operating mode
|
||||
if self._ac.get(ADVANTAGE_AIR_MYAUTO_ENABLED):
|
||||
# MyAuto
|
||||
@@ -108,12 +118,9 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
# MyZone
|
||||
self._attr_supported_features |= ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
|
||||
@property
|
||||
def current_temperature(self) -> float | None:
|
||||
"""Return the selected zones current temperature."""
|
||||
if self._myzone:
|
||||
return self._myzone["measuredTemp"]
|
||||
return None
|
||||
# Add "ezfan" mode if supported
|
||||
if self._ac.get(ADVANTAGE_AIR_AUTOFAN):
|
||||
self._attr_fan_modes += [FAN_AUTO]
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> float | None:
|
||||
@@ -137,7 +144,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
@property
|
||||
def fan_mode(self) -> str | None:
|
||||
"""Return the current fan modes."""
|
||||
return FAN_AUTO if self._ac["fan"] == ADVANTAGE_AIR_MYFAN else self._ac["fan"]
|
||||
return ADVANTAGE_AIR_FAN_MODES.get(self._ac["fan"])
|
||||
|
||||
@property
|
||||
def target_temperature_high(self) -> float | None:
|
||||
@@ -175,11 +182,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set the Fan Mode."""
|
||||
if fan_mode == FAN_AUTO and self._ac.get(ADVANTAGE_AIR_AUTOFAN_ENABLED):
|
||||
mode = ADVANTAGE_AIR_MYFAN
|
||||
else:
|
||||
mode = fan_mode
|
||||
await self.async_update_ac({"fan": mode})
|
||||
await self.async_update_ac({"fan": HASS_FAN_MODES.get(fan_mode)})
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the Temperature."""
|
||||
|
||||
@@ -5,4 +5,3 @@ ADVANTAGE_AIR_STATE_OPEN = "open"
|
||||
ADVANTAGE_AIR_STATE_CLOSE = "close"
|
||||
ADVANTAGE_AIR_STATE_ON = "on"
|
||||
ADVANTAGE_AIR_STATE_OFF = "off"
|
||||
ADVANTAGE_AIR_AUTOFAN_ENABLED = "aaAutoFanModeEnabled"
|
||||
|
||||
@@ -30,7 +30,7 @@ class AdvantageAirEntity(CoordinatorEntity):
|
||||
async def update_handle(*values):
|
||||
try:
|
||||
if await func(*keys, *values):
|
||||
await self.coordinator.async_request_refresh()
|
||||
await self.coordinator.async_refresh()
|
||||
except ApiError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
ADVANTAGE_AIR_AUTOFAN_ENABLED,
|
||||
ADVANTAGE_AIR_STATE_OFF,
|
||||
ADVANTAGE_AIR_STATE_ON,
|
||||
DOMAIN as ADVANTAGE_AIR_DOMAIN,
|
||||
@@ -30,8 +29,6 @@ async def async_setup_entry(
|
||||
for ac_key, ac_device in aircons.items():
|
||||
if ac_device["info"]["freshAirStatus"] != "none":
|
||||
entities.append(AdvantageAirFreshAir(instance, ac_key))
|
||||
if ADVANTAGE_AIR_AUTOFAN_ENABLED in ac_device["info"]:
|
||||
entities.append(AdvantageAirMyFan(instance, ac_key))
|
||||
if things := instance.coordinator.data.get("myThings"):
|
||||
for thing in things["things"].values():
|
||||
if thing["channelDipState"] == 8: # 8 = Other relay
|
||||
@@ -65,32 +62,6 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity):
|
||||
await self.async_update_ac({"freshAirStatus": ADVANTAGE_AIR_STATE_OFF})
|
||||
|
||||
|
||||
class AdvantageAirMyFan(AdvantageAirAcEntity, SwitchEntity):
|
||||
"""Representation of Advantage Air MyFan control."""
|
||||
|
||||
_attr_icon = "mdi:fan-auto"
|
||||
_attr_name = "MyFan"
|
||||
_attr_device_class = SwitchDeviceClass.SWITCH
|
||||
|
||||
def __init__(self, instance: AdvantageAirData, ac_key: str) -> None:
|
||||
"""Initialize an Advantage Air MyFan control."""
|
||||
super().__init__(instance, ac_key)
|
||||
self._attr_unique_id += "-myfan"
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return the MyFan status."""
|
||||
return self._ac[ADVANTAGE_AIR_AUTOFAN_ENABLED]
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn MyFan on."""
|
||||
await self.async_update_ac({ADVANTAGE_AIR_AUTOFAN_ENABLED: True})
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn MyFan off."""
|
||||
await self.async_update_ac({ADVANTAGE_AIR_AUTOFAN_ENABLED: False})
|
||||
|
||||
|
||||
class AdvantageAirRelay(AdvantageAirThingEntity, SwitchEntity):
|
||||
"""Representation of Advantage Air Thing."""
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"""The AEMET OpenData component."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aemet_opendata.exceptions import AemetError, TownNotFound
|
||||
from aemet_opendata.exceptions import TownNotFound
|
||||
from aemet_opendata.interface import AEMET, ConnectionOptions
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
@@ -38,8 +39,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
except TownNotFound as err:
|
||||
_LOGGER.error(err)
|
||||
return False
|
||||
except AemetError as err:
|
||||
raise ConfigEntryNotReady(err) from err
|
||||
except asyncio.TimeoutError as err:
|
||||
raise ConfigEntryNotReady("AEMET OpenData API timed out") from err
|
||||
|
||||
weather_coordinator = WeatherUpdateCoordinator(hass, aemet)
|
||||
await weather_coordinator.async_config_entry_first_refresh()
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
"""Config flow for AEMET OpenData."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aemet_opendata.exceptions import AuthError
|
||||
from aemet_opendata.interface import AEMET, ConnectionOptions
|
||||
import voluptuous as vol
|
||||
@@ -10,7 +8,6 @@ import voluptuous as vol
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
SchemaFlowFormStep,
|
||||
@@ -32,9 +29,7 @@ OPTIONS_FLOW = {
|
||||
class AemetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for AEMET OpenData."""
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a flow initialized by the user."""
|
||||
errors = {}
|
||||
|
||||
|
||||
@@ -12,18 +12,6 @@ from aemet_opendata.const import (
|
||||
AOD_COND_RAINY,
|
||||
AOD_COND_SNOWY,
|
||||
AOD_COND_SUNNY,
|
||||
AOD_CONDITION,
|
||||
AOD_FORECAST_DAILY,
|
||||
AOD_FORECAST_HOURLY,
|
||||
AOD_PRECIPITATION,
|
||||
AOD_PRECIPITATION_PROBABILITY,
|
||||
AOD_TEMP,
|
||||
AOD_TEMP_MAX,
|
||||
AOD_TEMP_MIN,
|
||||
AOD_TIMESTAMP,
|
||||
AOD_WIND_DIRECTION,
|
||||
AOD_WIND_SPEED,
|
||||
AOD_WIND_SPEED_MAX,
|
||||
)
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
@@ -37,15 +25,6 @@ from homeassistant.components.weather import (
|
||||
ATTR_CONDITION_RAINY,
|
||||
ATTR_CONDITION_SNOWY,
|
||||
ATTR_CONDITION_SUNNY,
|
||||
ATTR_FORECAST_CONDITION,
|
||||
ATTR_FORECAST_NATIVE_PRECIPITATION,
|
||||
ATTR_FORECAST_NATIVE_TEMP,
|
||||
ATTR_FORECAST_NATIVE_TEMP_LOW,
|
||||
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
|
||||
ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_FORECAST_TIME,
|
||||
ATTR_FORECAST_WIND_BEARING,
|
||||
)
|
||||
from homeassistant.const import Platform
|
||||
|
||||
@@ -143,30 +122,3 @@ FORECAST_MODE_ATTR_API = {
|
||||
FORECAST_MODE_DAILY: ATTR_API_FORECAST_DAILY,
|
||||
FORECAST_MODE_HOURLY: ATTR_API_FORECAST_HOURLY,
|
||||
}
|
||||
|
||||
FORECAST_MAP = {
|
||||
AOD_FORECAST_DAILY: {
|
||||
AOD_CONDITION: ATTR_FORECAST_CONDITION,
|
||||
AOD_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
AOD_TEMP_MAX: ATTR_FORECAST_NATIVE_TEMP,
|
||||
AOD_TEMP_MIN: ATTR_FORECAST_NATIVE_TEMP_LOW,
|
||||
AOD_TIMESTAMP: ATTR_FORECAST_TIME,
|
||||
AOD_WIND_DIRECTION: ATTR_FORECAST_WIND_BEARING,
|
||||
AOD_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
},
|
||||
AOD_FORECAST_HOURLY: {
|
||||
AOD_CONDITION: ATTR_FORECAST_CONDITION,
|
||||
AOD_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
AOD_PRECIPITATION: ATTR_FORECAST_NATIVE_PRECIPITATION,
|
||||
AOD_TEMP: ATTR_FORECAST_NATIVE_TEMP,
|
||||
AOD_TIMESTAMP: ATTR_FORECAST_TIME,
|
||||
AOD_WIND_DIRECTION: ATTR_FORECAST_WIND_BEARING,
|
||||
AOD_WIND_SPEED_MAX: ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
|
||||
AOD_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
},
|
||||
}
|
||||
|
||||
WEATHER_FORECAST_MODES = {
|
||||
AOD_FORECAST_DAILY: "daily",
|
||||
AOD_FORECAST_HOURLY: "hourly",
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
"""Entity classes for the AEMET OpenData integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aemet_opendata.helpers import dict_nested_value
|
||||
|
||||
from homeassistant.components.weather import Forecast
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .weather_update_coordinator import WeatherUpdateCoordinator
|
||||
|
||||
|
||||
class AemetEntity(CoordinatorEntity[WeatherUpdateCoordinator]):
|
||||
"""Define an AEMET entity."""
|
||||
|
||||
def get_aemet_forecast(self, forecast_mode: str) -> list[Forecast]:
|
||||
"""Return AEMET entity forecast by mode."""
|
||||
return self.coordinator.data["forecast"][forecast_mode]
|
||||
|
||||
def get_aemet_value(self, keys: list[str]) -> Any:
|
||||
"""Return AEMET entity value by keys."""
|
||||
return dict_nested_value(self.coordinator.data["lib"], keys)
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/aemet",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["aemet_opendata"],
|
||||
"requirements": ["AEMET-OpenData==0.4.7"]
|
||||
"requirements": ["AEMET-OpenData==0.4.5"]
|
||||
}
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
"""Support for the AEMET OpenData service."""
|
||||
|
||||
from aemet_opendata.const import (
|
||||
AOD_CONDITION,
|
||||
AOD_FORECAST_DAILY,
|
||||
AOD_FORECAST_HOURLY,
|
||||
AOD_HUMIDITY,
|
||||
AOD_PRESSURE,
|
||||
AOD_TEMP,
|
||||
AOD_WEATHER,
|
||||
AOD_WIND_DIRECTION,
|
||||
AOD_WIND_SPEED,
|
||||
AOD_WIND_SPEED_MAX,
|
||||
)
|
||||
from typing import cast
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_FORECAST_CONDITION,
|
||||
ATTR_FORECAST_NATIVE_PRECIPITATION,
|
||||
ATTR_FORECAST_NATIVE_TEMP,
|
||||
ATTR_FORECAST_NATIVE_TEMP_LOW,
|
||||
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
|
||||
ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_FORECAST_TIME,
|
||||
ATTR_FORECAST_WIND_BEARING,
|
||||
DOMAIN as WEATHER_DOMAIN,
|
||||
Forecast,
|
||||
SingleCoordinatorWeatherEntity,
|
||||
@@ -31,16 +28,55 @@ from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
ATTR_API_CONDITION,
|
||||
ATTR_API_FORECAST_CONDITION,
|
||||
ATTR_API_FORECAST_PRECIPITATION,
|
||||
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_API_FORECAST_TEMP,
|
||||
ATTR_API_FORECAST_TEMP_LOW,
|
||||
ATTR_API_FORECAST_TIME,
|
||||
ATTR_API_FORECAST_WIND_BEARING,
|
||||
ATTR_API_FORECAST_WIND_MAX_SPEED,
|
||||
ATTR_API_FORECAST_WIND_SPEED,
|
||||
ATTR_API_HUMIDITY,
|
||||
ATTR_API_PRESSURE,
|
||||
ATTR_API_TEMPERATURE,
|
||||
ATTR_API_WIND_BEARING,
|
||||
ATTR_API_WIND_MAX_SPEED,
|
||||
ATTR_API_WIND_SPEED,
|
||||
ATTRIBUTION,
|
||||
CONDITIONS_MAP,
|
||||
DOMAIN,
|
||||
ENTRY_NAME,
|
||||
ENTRY_WEATHER_COORDINATOR,
|
||||
WEATHER_FORECAST_MODES,
|
||||
FORECAST_MODE_ATTR_API,
|
||||
FORECAST_MODE_DAILY,
|
||||
FORECAST_MODE_HOURLY,
|
||||
FORECAST_MODES,
|
||||
)
|
||||
from .entity import AemetEntity
|
||||
from .weather_update_coordinator import WeatherUpdateCoordinator
|
||||
|
||||
FORECAST_MAP = {
|
||||
FORECAST_MODE_DAILY: {
|
||||
ATTR_API_FORECAST_CONDITION: ATTR_FORECAST_CONDITION,
|
||||
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_API_FORECAST_TEMP_LOW: ATTR_FORECAST_NATIVE_TEMP_LOW,
|
||||
ATTR_API_FORECAST_TEMP: ATTR_FORECAST_NATIVE_TEMP,
|
||||
ATTR_API_FORECAST_TIME: ATTR_FORECAST_TIME,
|
||||
ATTR_API_FORECAST_WIND_BEARING: ATTR_FORECAST_WIND_BEARING,
|
||||
ATTR_API_FORECAST_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
},
|
||||
FORECAST_MODE_HOURLY: {
|
||||
ATTR_API_FORECAST_CONDITION: ATTR_FORECAST_CONDITION,
|
||||
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_API_FORECAST_PRECIPITATION: ATTR_FORECAST_NATIVE_PRECIPITATION,
|
||||
ATTR_API_FORECAST_TEMP: ATTR_FORECAST_NATIVE_TEMP,
|
||||
ATTR_API_FORECAST_TIME: ATTR_FORECAST_TIME,
|
||||
ATTR_API_FORECAST_WIND_BEARING: ATTR_FORECAST_WIND_BEARING,
|
||||
ATTR_API_FORECAST_WIND_MAX_SPEED: ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
|
||||
ATTR_API_FORECAST_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@@ -59,11 +95,11 @@ async def async_setup_entry(
|
||||
if entity_registry.async_get_entity_id(
|
||||
WEATHER_DOMAIN,
|
||||
DOMAIN,
|
||||
f"{config_entry.unique_id} {WEATHER_FORECAST_MODES[AOD_FORECAST_HOURLY]}",
|
||||
f"{config_entry.unique_id} {FORECAST_MODE_HOURLY}",
|
||||
):
|
||||
for mode, mode_id in WEATHER_FORECAST_MODES.items():
|
||||
name = f"{domain_data[ENTRY_NAME]} {mode_id}"
|
||||
unique_id = f"{config_entry.unique_id} {mode_id}"
|
||||
for mode in FORECAST_MODES:
|
||||
name = f"{domain_data[ENTRY_NAME]} {mode}"
|
||||
unique_id = f"{config_entry.unique_id} {mode}"
|
||||
entities.append(AemetWeather(name, unique_id, weather_coordinator, mode))
|
||||
else:
|
||||
entities.append(
|
||||
@@ -71,18 +107,15 @@ async def async_setup_entry(
|
||||
domain_data[ENTRY_NAME],
|
||||
config_entry.unique_id,
|
||||
weather_coordinator,
|
||||
AOD_FORECAST_DAILY,
|
||||
FORECAST_MODE_DAILY,
|
||||
)
|
||||
)
|
||||
|
||||
async_add_entities(entities, False)
|
||||
|
||||
|
||||
class AemetWeather(
|
||||
AemetEntity,
|
||||
SingleCoordinatorWeatherEntity[WeatherUpdateCoordinator],
|
||||
):
|
||||
"""Implementation of an AEMET OpenData weather."""
|
||||
class AemetWeather(SingleCoordinatorWeatherEntity[WeatherUpdateCoordinator]):
|
||||
"""Implementation of an AEMET OpenData sensor."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
_attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
|
||||
@@ -104,7 +137,7 @@ class AemetWeather(
|
||||
super().__init__(coordinator)
|
||||
self._forecast_mode = forecast_mode
|
||||
self._attr_entity_registry_enabled_default = (
|
||||
self._forecast_mode == AOD_FORECAST_DAILY
|
||||
self._forecast_mode == FORECAST_MODE_DAILY
|
||||
)
|
||||
self._attr_name = name
|
||||
self._attr_unique_id = unique_id
|
||||
@@ -112,50 +145,61 @@ class AemetWeather(
|
||||
@property
|
||||
def condition(self):
|
||||
"""Return the current condition."""
|
||||
cond = self.get_aemet_value([AOD_WEATHER, AOD_CONDITION])
|
||||
return CONDITIONS_MAP.get(cond)
|
||||
return self.coordinator.data[ATTR_API_CONDITION]
|
||||
|
||||
def _forecast(self, forecast_mode: str) -> list[Forecast]:
|
||||
"""Return the forecast array."""
|
||||
forecasts = self.coordinator.data[FORECAST_MODE_ATTR_API[forecast_mode]]
|
||||
forecast_map = FORECAST_MAP[forecast_mode]
|
||||
return cast(
|
||||
list[Forecast],
|
||||
[
|
||||
{ha_key: forecast[api_key] for api_key, ha_key in forecast_map.items()}
|
||||
for forecast in forecasts
|
||||
],
|
||||
)
|
||||
|
||||
@property
|
||||
def forecast(self) -> list[Forecast]:
|
||||
"""Return the forecast array."""
|
||||
return self.get_aemet_forecast(self._forecast_mode)
|
||||
return self._forecast(self._forecast_mode)
|
||||
|
||||
@callback
|
||||
def _async_forecast_daily(self) -> list[Forecast]:
|
||||
"""Return the daily forecast in native units."""
|
||||
return self.get_aemet_forecast(AOD_FORECAST_DAILY)
|
||||
return self._forecast(FORECAST_MODE_DAILY)
|
||||
|
||||
@callback
|
||||
def _async_forecast_hourly(self) -> list[Forecast]:
|
||||
"""Return the hourly forecast in native units."""
|
||||
return self.get_aemet_forecast(AOD_FORECAST_HOURLY)
|
||||
return self._forecast(FORECAST_MODE_HOURLY)
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
"""Return the humidity."""
|
||||
return self.get_aemet_value([AOD_WEATHER, AOD_HUMIDITY])
|
||||
return self.coordinator.data[ATTR_API_HUMIDITY]
|
||||
|
||||
@property
|
||||
def native_pressure(self):
|
||||
"""Return the pressure."""
|
||||
return self.get_aemet_value([AOD_WEATHER, AOD_PRESSURE])
|
||||
return self.coordinator.data[ATTR_API_PRESSURE]
|
||||
|
||||
@property
|
||||
def native_temperature(self):
|
||||
"""Return the temperature."""
|
||||
return self.get_aemet_value([AOD_WEATHER, AOD_TEMP])
|
||||
return self.coordinator.data[ATTR_API_TEMPERATURE]
|
||||
|
||||
@property
|
||||
def wind_bearing(self):
|
||||
"""Return the wind bearing."""
|
||||
return self.get_aemet_value([AOD_WEATHER, AOD_WIND_DIRECTION])
|
||||
return self.coordinator.data[ATTR_API_WIND_BEARING]
|
||||
|
||||
@property
|
||||
def native_wind_gust_speed(self):
|
||||
"""Return the wind gust speed in native units."""
|
||||
return self.get_aemet_value([AOD_WEATHER, AOD_WIND_SPEED_MAX])
|
||||
return self.coordinator.data[ATTR_API_WIND_MAX_SPEED]
|
||||
|
||||
@property
|
||||
def native_wind_speed(self):
|
||||
"""Return the wind speed."""
|
||||
return self.get_aemet_value([AOD_WEATHER, AOD_WIND_SPEED])
|
||||
return self.coordinator.data[ATTR_API_WIND_SPEED]
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
from asyncio import timeout
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any, Final, cast
|
||||
from typing import Any, Final
|
||||
|
||||
from aemet_opendata.const import (
|
||||
AEMET_ATTR_DATE,
|
||||
@@ -31,24 +31,17 @@ from aemet_opendata.const import (
|
||||
AEMET_ATTR_TEMPERATURE,
|
||||
AEMET_ATTR_WIND,
|
||||
AEMET_ATTR_WIND_GUST,
|
||||
AOD_CONDITION,
|
||||
AOD_FORECAST,
|
||||
AOD_FORECAST_DAILY,
|
||||
AOD_FORECAST_HOURLY,
|
||||
AOD_TOWN,
|
||||
ATTR_DATA,
|
||||
)
|
||||
from aemet_opendata.exceptions import AemetError
|
||||
from aemet_opendata.forecast import ForecastValue
|
||||
from aemet_opendata.helpers import (
|
||||
dict_nested_value,
|
||||
get_forecast_day_value,
|
||||
get_forecast_hour_value,
|
||||
get_forecast_interval_value,
|
||||
)
|
||||
from aemet_opendata.interface import AEMET
|
||||
|
||||
from homeassistant.components.weather import Forecast
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
from homeassistant.util import dt as dt_util
|
||||
@@ -86,7 +79,6 @@ from .const import (
|
||||
ATTR_API_WIND_SPEED,
|
||||
CONDITIONS_MAP,
|
||||
DOMAIN,
|
||||
FORECAST_MAP,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -247,12 +239,6 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||
weather_response, now
|
||||
)
|
||||
|
||||
data = self.aemet.data()
|
||||
forecasts: list[dict[str, Forecast]] = {
|
||||
AOD_FORECAST_DAILY: self.aemet_forecast(data, AOD_FORECAST_DAILY),
|
||||
AOD_FORECAST_HOURLY: self.aemet_forecast(data, AOD_FORECAST_HOURLY),
|
||||
}
|
||||
|
||||
return {
|
||||
ATTR_API_CONDITION: condition,
|
||||
ATTR_API_FORECAST_DAILY: forecast_daily,
|
||||
@@ -275,29 +261,8 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||
ATTR_API_WIND_BEARING: wind_bearing,
|
||||
ATTR_API_WIND_MAX_SPEED: wind_max_speed,
|
||||
ATTR_API_WIND_SPEED: wind_speed,
|
||||
"forecast": forecasts,
|
||||
"lib": data,
|
||||
}
|
||||
|
||||
def aemet_forecast(
|
||||
self,
|
||||
data: dict[str, Any],
|
||||
forecast_mode: str,
|
||||
) -> list[Forecast]:
|
||||
"""Return the forecast array."""
|
||||
forecasts = dict_nested_value(data, [AOD_TOWN, forecast_mode, AOD_FORECAST])
|
||||
forecast_map = FORECAST_MAP[forecast_mode]
|
||||
forecast_list: list[dict[str, Any]] = []
|
||||
for forecast in forecasts:
|
||||
cur_forecast: dict[str, Any] = {}
|
||||
for api_key, ha_key in forecast_map.items():
|
||||
value = forecast[api_key]
|
||||
if api_key == AOD_CONDITION:
|
||||
value = CONDITIONS_MAP.get(value)
|
||||
cur_forecast[ha_key] = value
|
||||
forecast_list += [cur_forecast]
|
||||
return cast(list[Forecast], forecast_list)
|
||||
|
||||
def _get_daily_forecast_from_weather_response(self, weather_response, now):
|
||||
if weather_response.daily:
|
||||
parse = False
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Virtual integration: AEP Ohio."""
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"domain": "aep_ohio",
|
||||
"name": "AEP Ohio",
|
||||
"integration_type": "virtual",
|
||||
"supported_by": "opower"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
"""Virtual integration: AEP Texas."""
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"domain": "aep_texas",
|
||||
"name": "AEP Texas",
|
||||
"integration_type": "virtual",
|
||||
"supported_by": "opower"
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import voluptuous as vol
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
from homeassistant.const import CONF_API_KEY, CONF_NAME
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.data_entry_flow import AbortFlow, FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
|
||||
@@ -51,6 +51,25 @@ class AfterShipConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
async def async_step_import(self, config: dict[str, Any]) -> FlowResult:
|
||||
"""Import configuration from yaml."""
|
||||
try:
|
||||
self._async_abort_entries_match({CONF_API_KEY: config[CONF_API_KEY]})
|
||||
except AbortFlow as err:
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
"deprecated_yaml_import_issue_already_configured",
|
||||
breaks_in_ha_version="2024.4.0",
|
||||
is_fixable=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml_import_issue_already_configured",
|
||||
translation_placeholders={
|
||||
"domain": DOMAIN,
|
||||
"integration_title": "AfterShip",
|
||||
},
|
||||
)
|
||||
raise err
|
||||
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
HOMEASSISTANT_DOMAIN,
|
||||
@@ -65,8 +84,6 @@ class AfterShipConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"integration_title": "AfterShip",
|
||||
},
|
||||
)
|
||||
|
||||
self._async_abort_entries_match({CONF_API_KEY: config[CONF_API_KEY]})
|
||||
return self.async_create_entry(
|
||||
title=config.get(CONF_NAME, "AfterShip"),
|
||||
data={CONF_API_KEY: config[CONF_API_KEY]},
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_yaml_import_issue_already_configured": {
|
||||
"title": "The {integration_title} YAML configuration import failed",
|
||||
"description": "Configuring {integration_title} using YAML is being removed but the YAML configuration was already imported.\n\nRemove the YAML configuration and restart Home Assistant."
|
||||
},
|
||||
"deprecated_yaml_import_issue_cannot_connect": {
|
||||
"title": "The {integration_title} YAML configuration import failed",
|
||||
"description": "Configuring {integration_title} using YAML is being removed but there was an connection error importing your YAML configuration.\n\nEnsure connection to {integration_title} works and restart Home Assistant to try again or remove the {integration_title} YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Config flow to configure Agent devices."""
|
||||
from contextlib import suppress
|
||||
from typing import Any
|
||||
|
||||
from agent import AgentConnectionError, AgentError
|
||||
from agent.a import Agent
|
||||
@@ -8,7 +7,6 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import DOMAIN, SERVER_URL
|
||||
@@ -20,9 +18,11 @@ DEFAULT_PORT = 8090
|
||||
class AgentFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle an Agent config flow."""
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
def __init__(self):
|
||||
"""Initialize the Agent config flow."""
|
||||
self.device_config = {}
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle an Agent config flow."""
|
||||
errors = {}
|
||||
|
||||
@@ -49,15 +49,13 @@ class AgentFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
}
|
||||
)
|
||||
|
||||
device_config = {
|
||||
self.device_config = {
|
||||
CONF_HOST: host,
|
||||
CONF_PORT: port,
|
||||
SERVER_URL: server_origin,
|
||||
}
|
||||
|
||||
return self.async_create_entry(
|
||||
title=agent_client.name, data=device_config
|
||||
)
|
||||
return await self._create_entry(agent_client.name)
|
||||
|
||||
errors["base"] = "cannot_connect"
|
||||
|
||||
@@ -68,6 +66,11 @@ class AgentFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
description_placeholders=self.device_config,
|
||||
data_schema=vol.Schema(data),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def _create_entry(self, server_name):
|
||||
"""Create entry for device."""
|
||||
return self.async_create_entry(title=server_name, data=self.device_config)
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
"port": "[%key:common::config_flow::data::port%]"
|
||||
},
|
||||
"data_description": {
|
||||
"host": "The IP address of the Agent DVR server."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -56,7 +56,7 @@ from .const import (
|
||||
PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirlySensorEntityDescription(SensorEntityDescription):
|
||||
"""Class describing Airly sensor entities."""
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ from homeassistant.const import (
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -51,20 +50,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
# Clean up unused device entries with no entities
|
||||
device_registry = dr.async_get(hass)
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
device_entries = dr.async_entries_for_config_entry(
|
||||
device_registry, config_entry_id=entry.entry_id
|
||||
)
|
||||
for dev in device_entries:
|
||||
dev_entities = er.async_entries_for_device(
|
||||
entity_registry, dev.id, include_disabled_entities=True
|
||||
)
|
||||
if not dev_entities:
|
||||
device_registry.async_remove_device(dev.id)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -6,17 +6,8 @@ from pyairnow import WebServiceAPI
|
||||
from pyairnow.errors import AirNowError, EmptyResponseError, InvalidKeyError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import core
|
||||
from homeassistant.config_entries import (
|
||||
ConfigEntry,
|
||||
ConfigFlow,
|
||||
OptionsFlow,
|
||||
OptionsFlowWithConfigEntry,
|
||||
)
|
||||
from homeassistant import config_entries, core, data_entry_flow, exceptions
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
@@ -25,7 +16,7 @@ from .const import DOMAIN
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> bool:
|
||||
async def validate_input(hass: core.HomeAssistant, data):
|
||||
"""Validate the user input allows us to connect.
|
||||
|
||||
Data has the keys from DATA_SCHEMA with values provided by the user.
|
||||
@@ -55,14 +46,12 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class AirNowConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for AirNow."""
|
||||
|
||||
VERSION = 2
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
@@ -119,18 +108,18 @@ class AirNowConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
@staticmethod
|
||||
@core.callback
|
||||
def async_get_options_flow(
|
||||
config_entry: ConfigEntry,
|
||||
) -> OptionsFlow:
|
||||
config_entry: config_entries.ConfigEntry,
|
||||
) -> config_entries.OptionsFlow:
|
||||
"""Return the options flow."""
|
||||
return AirNowOptionsFlowHandler(config_entry)
|
||||
return OptionsFlowHandler(config_entry)
|
||||
|
||||
|
||||
class AirNowOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
||||
class OptionsFlowHandler(config_entries.OptionsFlowWithConfigEntry):
|
||||
"""Handle an options flow for AirNow."""
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
) -> data_entry_flow.FlowResult:
|
||||
"""Manage the options."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(data=user_input)
|
||||
@@ -152,13 +141,13 @@ class AirNowOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
||||
)
|
||||
|
||||
|
||||
class CannotConnect(HomeAssistantError):
|
||||
class CannotConnect(exceptions.HomeAssistantError):
|
||||
"""Error to indicate we cannot connect."""
|
||||
|
||||
|
||||
class InvalidAuth(HomeAssistantError):
|
||||
class InvalidAuth(exceptions.HomeAssistantError):
|
||||
"""Error to indicate there is invalid auth."""
|
||||
|
||||
|
||||
class InvalidLocation(HomeAssistantError):
|
||||
class InvalidLocation(exceptions.HomeAssistantError):
|
||||
"""Error to indicate the location is invalid."""
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
"""DataUpdateCoordinator for the AirNow integration."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from aiohttp.client_exceptions import ClientConnectorError
|
||||
from pyairnow import WebServiceAPI
|
||||
from pyairnow.conv import aqi_to_concentration
|
||||
from pyairnow.errors import AirNowError
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import (
|
||||
@@ -35,19 +31,12 @@ from .const import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
class AirNowDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""The AirNow update coordinator."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
session: ClientSession,
|
||||
api_key: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
distance: int,
|
||||
update_interval: timedelta,
|
||||
) -> None:
|
||||
self, hass, session, api_key, latitude, longitude, distance, update_interval
|
||||
):
|
||||
"""Initialize."""
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
@@ -57,7 +46,7 @@ class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
|
||||
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
async def _async_update_data(self):
|
||||
"""Update data via library."""
|
||||
data = {}
|
||||
try:
|
||||
|
||||
@@ -51,7 +51,7 @@ ATTR_LEVEL = "level"
|
||||
ATTR_STATION = "reporting_station"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirNowEntityDescriptionMixin:
|
||||
"""Mixin for required keys."""
|
||||
|
||||
@@ -59,7 +59,7 @@ class AirNowEntityDescriptionMixin:
|
||||
extra_state_attributes_fn: Callable[[Any], dict[str, str]] | None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirNowEntityDescription(SensorEntityDescription, AirNowEntityDescriptionMixin):
|
||||
"""Describes Airnow sensor entity."""
|
||||
|
||||
@@ -148,14 +148,13 @@ class AirNowSensor(CoordinatorEntity[AirNowDataUpdateCoordinator], SensorEntity)
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
_device_id = f"{coordinator.latitude}-{coordinator.longitude}"
|
||||
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{_device_id}-{description.key.lower()}"
|
||||
self._attr_unique_id = (
|
||||
f"{coordinator.latitude}-{coordinator.longitude}-{description.key.lower()}"
|
||||
)
|
||||
self._attr_device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
identifiers={(DOMAIN, _device_id)},
|
||||
identifiers={(DOMAIN, self._attr_unique_id)},
|
||||
manufacturer=DEFAULT_NAME,
|
||||
name=DEFAULT_NAME,
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from aioairq import AirQ, InvalidAuth
|
||||
from aioairq import AirQ, InvalidAuth, InvalidInput
|
||||
from aiohttp.client_exceptions import ClientConnectionError
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -42,32 +42,44 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
session = async_get_clientsession(self.hass)
|
||||
airq = AirQ(user_input[CONF_IP_ADDRESS], user_input[CONF_PASSWORD], session)
|
||||
try:
|
||||
await airq.validate()
|
||||
except ClientConnectionError:
|
||||
airq = AirQ(user_input[CONF_IP_ADDRESS], user_input[CONF_PASSWORD], session)
|
||||
except InvalidInput:
|
||||
_LOGGER.debug(
|
||||
(
|
||||
"Failed to connect to device %s. Check the IP address / device"
|
||||
" ID as well as whether the device is connected to power and"
|
||||
" the WiFi"
|
||||
),
|
||||
"%s does not appear to be a valid IP address or mDNS name",
|
||||
user_input[CONF_IP_ADDRESS],
|
||||
)
|
||||
errors["base"] = "cannot_connect"
|
||||
except InvalidAuth:
|
||||
_LOGGER.debug(
|
||||
"Incorrect password for device %s", user_input[CONF_IP_ADDRESS]
|
||||
)
|
||||
errors["base"] = "invalid_auth"
|
||||
errors["base"] = "invalid_input"
|
||||
else:
|
||||
_LOGGER.debug("Successfully connected to %s", user_input[CONF_IP_ADDRESS])
|
||||
try:
|
||||
await airq.validate()
|
||||
except ClientConnectionError:
|
||||
_LOGGER.debug(
|
||||
(
|
||||
"Failed to connect to device %s. Check the IP address / device"
|
||||
" ID as well as whether the device is connected to power and"
|
||||
" the WiFi"
|
||||
),
|
||||
user_input[CONF_IP_ADDRESS],
|
||||
)
|
||||
errors["base"] = "cannot_connect"
|
||||
except InvalidAuth:
|
||||
_LOGGER.debug(
|
||||
"Incorrect password for device %s", user_input[CONF_IP_ADDRESS]
|
||||
)
|
||||
errors["base"] = "invalid_auth"
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Successfully connected to %s", user_input[CONF_IP_ADDRESS]
|
||||
)
|
||||
|
||||
device_info = await airq.fetch_device_info()
|
||||
await self.async_set_unique_id(device_info["id"])
|
||||
self._abort_if_unique_id_configured()
|
||||
device_info = await airq.fetch_device_info()
|
||||
await self.async_set_unique_id(device_info["id"])
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return self.async_create_entry(title=device_info["name"], data=user_input)
|
||||
return self.async_create_entry(
|
||||
title=device_info["name"], data=user_input
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import Final
|
||||
|
||||
DOMAIN: Final = "airq"
|
||||
MANUFACTURER: Final = "CorantGmbH"
|
||||
TARGET_ROUTE: Final = "average"
|
||||
CONCENTRATION_GRAMS_PER_CUBIC_METER: Final = "g/m³"
|
||||
ACTIVITY_BECQUEREL_PER_CUBIC_METER: Final = "Bq/m³"
|
||||
UPDATE_INTERVAL: float = 10.0
|
||||
|
||||
@@ -13,7 +13,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .const import DOMAIN, MANUFACTURER, UPDATE_INTERVAL
|
||||
from .const import DOMAIN, MANUFACTURER, TARGET_ROUTE, UPDATE_INTERVAL
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -56,4 +56,6 @@ class AirQCoordinator(DataUpdateCoordinator):
|
||||
hw_version=info["hw_version"],
|
||||
)
|
||||
)
|
||||
return await self.airq.get_latest_data()
|
||||
|
||||
data = await self.airq.get(TARGET_ROUTE)
|
||||
return self.airq.drop_uncertainties_from_data(data)
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairq"],
|
||||
"requirements": ["aioairq==0.3.2"]
|
||||
"requirements": ["aioairq==0.2.4"]
|
||||
}
|
||||
|
||||
@@ -37,14 +37,14 @@ from .const import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirQEntityDescriptionMixin:
|
||||
"""Class for keys required by AirQ entity."""
|
||||
|
||||
value: Callable[[dict], float | int | None]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirQEntityDescription(SensorEntityDescription, AirQEntityDescriptionMixin):
|
||||
"""Describes AirQ sensor entity."""
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import logging
|
||||
from airthings import Airthings, AirthingsError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_ID, Platform
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import CONF_SECRET, DOMAIN
|
||||
from .const import CONF_ID, CONF_SECRET, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -8,11 +8,10 @@ import airthings
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_ID
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import CONF_SECRET, DOMAIN
|
||||
from .const import CONF_ID, CONF_SECRET, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
DOMAIN = "airthings"
|
||||
|
||||
CONF_ID = "id"
|
||||
CONF_SECRET = "secret"
|
||||
|
||||
@@ -4,8 +4,7 @@ from __future__ import annotations
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from airthings_ble import AirthingsBluetoothDeviceData, AirthingsDevice
|
||||
from bleak_retry_connector import close_stale_connections_by_address
|
||||
from airthings_ble import AirthingsBluetoothDeviceData
|
||||
|
||||
from homeassistant.components import bluetooth
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
@@ -31,8 +30,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
is_metric = hass.config.units is METRIC_SYSTEM
|
||||
assert address is not None
|
||||
|
||||
await close_stale_connections_by_address(address)
|
||||
|
||||
ble_device = bluetooth.async_ble_device_from_address(hass, address)
|
||||
|
||||
if not ble_device:
|
||||
@@ -40,13 +37,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
f"Could not find Airthings device with address {address}"
|
||||
)
|
||||
|
||||
async def _async_update_method() -> AirthingsDevice:
|
||||
async def _async_update_method():
|
||||
"""Get data from Airthings BLE."""
|
||||
ble_device = bluetooth.async_ble_device_from_address(hass, address)
|
||||
airthings = AirthingsBluetoothDeviceData(_LOGGER, elevation, is_metric)
|
||||
|
||||
try:
|
||||
data = await airthings.update_device(ble_device) # type: ignore[arg-type]
|
||||
data = await airthings.update_device(ble_device)
|
||||
except Exception as err:
|
||||
raise UpdateFailed(f"Unable to fetch data: {err}") from err
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Support for airthings ble sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import logging
|
||||
|
||||
from airthings_ble import AirthingsDevice
|
||||
@@ -168,13 +167,10 @@ async def async_setup_entry(
|
||||
# we need to change some units
|
||||
sensors_mapping = SENSORS_MAPPING_TEMPLATE.copy()
|
||||
if not is_metric:
|
||||
for key, val in sensors_mapping.items():
|
||||
for val in sensors_mapping.values():
|
||||
if val.native_unit_of_measurement is not VOLUME_BECQUEREL:
|
||||
continue
|
||||
sensors_mapping[key] = dataclasses.replace(
|
||||
val,
|
||||
native_unit_of_measurement=VOLUME_PICOCURIE,
|
||||
)
|
||||
val.native_unit_of_measurement = VOLUME_PICOCURIE
|
||||
|
||||
entities = []
|
||||
_LOGGER.debug("got sensors: %s", coordinator.data.sensors)
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
"title": "Set up your AirTouch 4 connection details.",
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]"
|
||||
},
|
||||
"data_description": {
|
||||
"host": "The hostname or IP address of your AirTouch controller."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ from homeassistant.components import automation
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_COUNTRY,
|
||||
CONF_IP_ADDRESS,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
@@ -45,6 +44,7 @@ from homeassistant.helpers.update_coordinator import (
|
||||
|
||||
from .const import (
|
||||
CONF_CITY,
|
||||
CONF_COUNTRY,
|
||||
CONF_GEOGRAPHIES,
|
||||
CONF_INTEGRATION_TYPE,
|
||||
DOMAIN,
|
||||
|
||||
@@ -19,7 +19,6 @@ from homeassistant import config_entries
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_COUNTRY,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_SHOW_ON_MAP,
|
||||
@@ -36,6 +35,7 @@ from homeassistant.helpers.schema_config_entry_flow import (
|
||||
from . import async_get_geography_id
|
||||
from .const import (
|
||||
CONF_CITY,
|
||||
CONF_COUNTRY,
|
||||
CONF_INTEGRATION_TYPE,
|
||||
DOMAIN,
|
||||
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
||||
|
||||
@@ -9,5 +9,6 @@ INTEGRATION_TYPE_GEOGRAPHY_NAME = "Geographical Location by Name"
|
||||
INTEGRATION_TYPE_NODE_PRO = "AirVisual Node/Pro"
|
||||
|
||||
CONF_CITY = "city"
|
||||
CONF_COUNTRY = "country"
|
||||
CONF_GEOGRAPHIES = "geographies"
|
||||
CONF_INTEGRATION_TYPE = "integration_type"
|
||||
|
||||
@@ -7,7 +7,6 @@ from homeassistant.components.diagnostics import async_redact_data
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_COUNTRY,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_STATE,
|
||||
@@ -16,7 +15,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .const import CONF_CITY, DOMAIN
|
||||
from .const import CONF_CITY, CONF_COUNTRY, DOMAIN
|
||||
|
||||
CONF_COORDINATES = "coordinates"
|
||||
CONF_TITLE = "title"
|
||||
|
||||
@@ -15,7 +15,6 @@ from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_COUNTRY,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_SHOW_ON_MAP,
|
||||
@@ -26,7 +25,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from . import AirVisualEntity
|
||||
from .const import CONF_CITY, DOMAIN
|
||||
from .const import CONF_CITY, CONF_COUNTRY, DOMAIN
|
||||
|
||||
ATTR_CITY = "city"
|
||||
ATTR_COUNTRY = "country"
|
||||
|
||||
@@ -26,7 +26,7 @@ from . import AirVisualProData, AirVisualProEntity
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirVisualProMeasurementKeyMixin:
|
||||
"""Define an entity description mixin to include a measurement key."""
|
||||
|
||||
@@ -35,7 +35,7 @@ class AirVisualProMeasurementKeyMixin:
|
||||
]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirVisualProMeasurementDescription(
|
||||
SensorEntityDescription, AirVisualProMeasurementKeyMixin
|
||||
):
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
"data": {
|
||||
"ip_address": "[%key:common::config_flow::data::host%]",
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
},
|
||||
"data_description": {
|
||||
"ip_address": "The hostname or IP address of your AirVisual Pro device."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ from aioairzone.const import (
|
||||
AZD_BATTERY_LOW,
|
||||
AZD_ERRORS,
|
||||
AZD_FLOOR_DEMAND,
|
||||
AZD_NAME,
|
||||
AZD_PROBLEMS,
|
||||
AZD_SYSTEMS,
|
||||
AZD_ZONES,
|
||||
@@ -29,7 +30,7 @@ from .coordinator import AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneSystemEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirzoneBinarySensorEntityDescription(BinarySensorEntityDescription):
|
||||
"""A class that describes airzone binary sensor entities."""
|
||||
|
||||
@@ -44,6 +45,7 @@ SYSTEM_BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ..
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
key=AZD_PROBLEMS,
|
||||
name="Problem",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -51,16 +53,17 @@ ZONE_BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]
|
||||
AirzoneBinarySensorEntityDescription(
|
||||
device_class=BinarySensorDeviceClass.RUNNING,
|
||||
key=AZD_AIR_DEMAND,
|
||||
translation_key="air_demand",
|
||||
name="Air Demand",
|
||||
),
|
||||
AirzoneBinarySensorEntityDescription(
|
||||
device_class=BinarySensorDeviceClass.BATTERY,
|
||||
key=AZD_BATTERY_LOW,
|
||||
name="Battery Low",
|
||||
),
|
||||
AirzoneBinarySensorEntityDescription(
|
||||
device_class=BinarySensorDeviceClass.RUNNING,
|
||||
key=AZD_FLOOR_DEMAND,
|
||||
translation_key="floor_demand",
|
||||
name="Floor Demand",
|
||||
),
|
||||
AirzoneBinarySensorEntityDescription(
|
||||
attributes={
|
||||
@@ -69,6 +72,7 @@ ZONE_BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
key=AZD_PROBLEMS,
|
||||
name="Problem",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -145,6 +149,7 @@ class AirzoneSystemBinarySensor(AirzoneSystemEntity, AirzoneBinarySensor):
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator, entry, system_data)
|
||||
self._attr_name = f"System {system_id} {description.name}"
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_{system_id}_{description.key}"
|
||||
self.entity_description = description
|
||||
self._async_update_attrs()
|
||||
@@ -164,6 +169,7 @@ class AirzoneZoneBinarySensor(AirzoneZoneEntity, AirzoneBinarySensor):
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator, entry, system_zone_id, zone_data)
|
||||
|
||||
self._attr_name = f"{zone_data[AZD_NAME]} {description.name}"
|
||||
self._attr_unique_id = (
|
||||
f"{self._attr_unique_id}_{system_zone_id}_{description.key}"
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ from aioairzone.const import (
|
||||
AZD_MASTER,
|
||||
AZD_MODE,
|
||||
AZD_MODES,
|
||||
AZD_NAME,
|
||||
AZD_ON,
|
||||
AZD_SPEED,
|
||||
AZD_SPEEDS,
|
||||
@@ -31,7 +32,6 @@ from aioairzone.const import (
|
||||
)
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_HVAC_MODE,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
FAN_AUTO,
|
||||
@@ -114,7 +114,6 @@ async def async_setup_entry(
|
||||
class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
"""Define an Airzone sensor."""
|
||||
|
||||
_attr_name = None
|
||||
_speeds: dict[int, str] = {}
|
||||
_speeds_reverse: dict[str, int] = {}
|
||||
|
||||
@@ -128,6 +127,7 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
"""Initialize Airzone climate entity."""
|
||||
super().__init__(coordinator, entry, system_zone_id, zone_data)
|
||||
|
||||
self._attr_name = f"{zone_data[AZD_NAME]}"
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_{system_zone_id}"
|
||||
self._attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
self._attr_target_temperature_step = API_TEMPERATURE_STEP
|
||||
@@ -209,9 +209,7 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
await self._async_update_hvac_params(params)
|
||||
|
||||
if slave_raise:
|
||||
raise HomeAssistantError(
|
||||
f"Mode can't be changed on slave zone {self.entity_id}"
|
||||
)
|
||||
raise HomeAssistantError(f"Mode can't be changed on slave zone {self.name}")
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
@@ -223,9 +221,6 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
params[API_HEAT_SET_POINT] = kwargs[ATTR_TARGET_TEMP_LOW]
|
||||
await self._async_update_hvac_params(params)
|
||||
|
||||
if ATTR_HVAC_MODE in kwargs:
|
||||
await self.async_set_hvac_mode(kwargs[ATTR_HVAC_MODE])
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Update attributes when the coordinator updates."""
|
||||
@@ -248,6 +243,7 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
self._attr_max_temp = self.get_airzone_value(AZD_TEMP_MAX)
|
||||
self._attr_min_temp = self.get_airzone_value(AZD_TEMP_MIN)
|
||||
self._attr_target_temperature = self.get_airzone_value(AZD_TEMP_SET)
|
||||
if self.supported_features & ClimateEntityFeature.FAN_MODE:
|
||||
self._attr_fan_mode = self._speeds.get(self.get_airzone_value(AZD_SPEED))
|
||||
if self.supported_features & ClimateEntityFeature.TARGET_TEMPERATURE_RANGE:
|
||||
@@ -257,5 +253,3 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
self._attr_target_temperature_low = self.get_airzone_value(
|
||||
AZD_HEAT_TEMP_SET
|
||||
)
|
||||
else:
|
||||
self._attr_target_temperature = self.get_airzone_value(AZD_TEMP_SET)
|
||||
|
||||
@@ -39,8 +39,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class AirzoneEntity(CoordinatorEntity[AirzoneUpdateCoordinator]):
|
||||
"""Define an Airzone entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def get_airzone_value(self, key: str) -> Any:
|
||||
"""Return Airzone entity value by key."""
|
||||
raise NotImplementedError()
|
||||
@@ -64,7 +62,7 @@ class AirzoneSystemEntity(AirzoneEntity):
|
||||
identifiers={(DOMAIN, f"{entry.entry_id}_{self.system_id}")},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=self.get_airzone_value(AZD_MODEL),
|
||||
name=f"System {self.system_id}",
|
||||
name=self.get_airzone_value(AZD_FULL_NAME),
|
||||
sw_version=self.get_airzone_value(AZD_FIRMWARE),
|
||||
via_device=(DOMAIN, f"{entry.entry_id}_ws"),
|
||||
)
|
||||
@@ -118,7 +116,9 @@ class AirzoneHotWaterEntity(AirzoneEntity):
|
||||
try:
|
||||
await self.coordinator.airzone.set_dhw_parameters(_params)
|
||||
except AirzoneError as error:
|
||||
raise HomeAssistantError(f"Failed to set DHW: {error}") from error
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set dhw {self.name}: {error}"
|
||||
) from error
|
||||
|
||||
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
|
||||
|
||||
@@ -172,7 +172,7 @@ class AirzoneZoneEntity(AirzoneEntity):
|
||||
identifiers={(DOMAIN, f"{entry.entry_id}_{system_zone_id}")},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=self.get_airzone_value(AZD_THERMOSTAT_MODEL),
|
||||
name=zone_data[AZD_NAME],
|
||||
name=f"Airzone [{system_zone_id}] {zone_data[AZD_NAME]}",
|
||||
sw_version=self.get_airzone_value(AZD_THERMOSTAT_FW),
|
||||
via_device=(DOMAIN, f"{entry.entry_id}_{self.system_id}"),
|
||||
)
|
||||
@@ -203,7 +203,7 @@ class AirzoneZoneEntity(AirzoneEntity):
|
||||
await self.coordinator.airzone.set_hvac_parameters(_params)
|
||||
except AirzoneError as error:
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set zone {self.entity_id}: {error}"
|
||||
f"Failed to set zone {self.name}: {error}"
|
||||
) from error
|
||||
|
||||
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairzone"],
|
||||
"requirements": ["aioairzone==0.7.2"]
|
||||
"requirements": ["aioairzone==0.6.9"]
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ from aioairzone.const import (
|
||||
API_SLEEP,
|
||||
AZD_COLD_ANGLE,
|
||||
AZD_HEAT_ANGLE,
|
||||
AZD_NAME,
|
||||
AZD_SLEEP,
|
||||
AZD_ZONES,
|
||||
)
|
||||
@@ -26,7 +27,7 @@ from .coordinator import AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirzoneSelectDescriptionMixin:
|
||||
"""Define an entity description mixin for select entities."""
|
||||
|
||||
@@ -34,7 +35,7 @@ class AirzoneSelectDescriptionMixin:
|
||||
options_dict: dict[str, int]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirzoneSelectDescription(SelectEntityDescription, AirzoneSelectDescriptionMixin):
|
||||
"""Class to describe an Airzone select entity."""
|
||||
|
||||
@@ -59,6 +60,7 @@ ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = (
|
||||
api_param=API_COLD_ANGLE,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
key=AZD_COLD_ANGLE,
|
||||
name="Cold Angle",
|
||||
options=list(GRILLE_ANGLE_DICT),
|
||||
options_dict=GRILLE_ANGLE_DICT,
|
||||
translation_key="grille_angles",
|
||||
@@ -67,14 +69,16 @@ ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = (
|
||||
api_param=API_HEAT_ANGLE,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
key=AZD_HEAT_ANGLE,
|
||||
name="Heat Angle",
|
||||
options=list(GRILLE_ANGLE_DICT),
|
||||
options_dict=GRILLE_ANGLE_DICT,
|
||||
translation_key="heat_angles",
|
||||
translation_key="grille_angles",
|
||||
),
|
||||
AirzoneSelectDescription(
|
||||
api_param=API_SLEEP,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
key=AZD_SLEEP,
|
||||
name="Sleep",
|
||||
options=list(SLEEP_DICT),
|
||||
options_dict=SLEEP_DICT,
|
||||
translation_key="sleep_times",
|
||||
@@ -142,6 +146,7 @@ class AirzoneZoneSelect(AirzoneZoneEntity, AirzoneBaseSelect):
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator, entry, system_zone_id, zone_data)
|
||||
|
||||
self._attr_name = f"{zone_data[AZD_NAME]} {description.name}"
|
||||
self._attr_unique_id = (
|
||||
f"{self._attr_unique_id}_{system_zone_id}_{description.key}"
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Any, Final
|
||||
from aioairzone.const import (
|
||||
AZD_HOT_WATER,
|
||||
AZD_HUMIDITY,
|
||||
AZD_NAME,
|
||||
AZD_TEMP,
|
||||
AZD_TEMP_UNIT,
|
||||
AZD_WEBSERVER,
|
||||
@@ -53,7 +54,7 @@ WEBSERVER_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
key=AZD_WIFI_RSSI,
|
||||
translation_key="rssi",
|
||||
name="RSSI",
|
||||
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -63,12 +64,14 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
key=AZD_TEMP,
|
||||
name="Temperature",
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key=AZD_HUMIDITY,
|
||||
name="Humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -141,6 +144,8 @@ class AirzoneSensor(AirzoneEntity, SensorEntity):
|
||||
class AirzoneHotWaterSensor(AirzoneHotWaterEntity, AirzoneSensor):
|
||||
"""Define an Airzone Hot Water sensor."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
@@ -171,6 +176,7 @@ class AirzoneWebServerSensor(AirzoneWebServerEntity, AirzoneSensor):
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator, entry)
|
||||
self._attr_name = f"WebServer {description.name}"
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_ws_{description.key}"
|
||||
self.entity_description = description
|
||||
self._async_update_attrs()
|
||||
@@ -190,6 +196,7 @@ class AirzoneZoneSensor(AirzoneZoneEntity, AirzoneSensor):
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator, entry, system_zone_id, zone_data)
|
||||
|
||||
self._attr_name = f"{zone_data[AZD_NAME]} {description.name}"
|
||||
self._attr_unique_id = (
|
||||
f"{self._attr_unique_id}_{system_zone_id}_{description.key}"
|
||||
)
|
||||
|
||||
@@ -25,17 +25,8 @@
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"binary_sensor": {
|
||||
"air_demand": {
|
||||
"name": "Air demand"
|
||||
},
|
||||
"floor_demand": {
|
||||
"name": "Floor demand"
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"grille_angles": {
|
||||
"name": "Cold angle",
|
||||
"state": {
|
||||
"90deg": "90°",
|
||||
"50deg": "50°",
|
||||
@@ -43,17 +34,7 @@
|
||||
"40deg": "40°"
|
||||
}
|
||||
},
|
||||
"heat_angles": {
|
||||
"name": "Heat angle",
|
||||
"state": {
|
||||
"90deg": "[%key:component::airzone::entity::select::grille_angles::state::90deg%]",
|
||||
"50deg": "[%key:component::airzone::entity::select::grille_angles::state::50deg%]",
|
||||
"45deg": "[%key:component::airzone::entity::select::grille_angles::state::45deg%]",
|
||||
"40deg": "[%key:component::airzone::entity::select::grille_angles::state::40deg%]"
|
||||
}
|
||||
},
|
||||
"sleep_times": {
|
||||
"name": "Sleep",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"30m": "30 minutes",
|
||||
@@ -61,11 +42,6 @@
|
||||
"90m": "90 minutes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"rssi": {
|
||||
"name": "RSSI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ from aioairzone.const import (
|
||||
API_ACS_POWER_MODE,
|
||||
API_ACS_SET_POINT,
|
||||
AZD_HOT_WATER,
|
||||
AZD_NAME,
|
||||
AZD_OPERATION,
|
||||
AZD_OPERATIONS,
|
||||
AZD_TEMP,
|
||||
@@ -66,7 +67,6 @@ async def async_setup_entry(
|
||||
class AirzoneWaterHeater(AirzoneHotWaterEntity, WaterHeaterEntity):
|
||||
"""Define an Airzone Water Heater."""
|
||||
|
||||
_attr_name = None
|
||||
_attr_supported_features = (
|
||||
WaterHeaterEntityFeature.TARGET_TEMPERATURE
|
||||
| WaterHeaterEntityFeature.ON_OFF
|
||||
@@ -81,6 +81,7 @@ class AirzoneWaterHeater(AirzoneHotWaterEntity, WaterHeaterEntity):
|
||||
"""Initialize Airzone water heater entity."""
|
||||
super().__init__(coordinator, entry)
|
||||
|
||||
self._attr_name = self.get_airzone_value(AZD_NAME)
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_dhw"
|
||||
self._attr_operation_list = [
|
||||
OPERATION_LIB_TO_HASS[operation]
|
||||
|
||||
@@ -46,9 +46,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||
coordinator: AirzoneUpdateCoordinator = hass.data[DOMAIN].pop(entry.entry_id)
|
||||
await coordinator.airzone.logout()
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
|
||||
return unload_ok
|
||||
|
||||
@@ -34,7 +34,7 @@ from .entity import (
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass
|
||||
class AirzoneBinarySensorEntityDescription(BinarySensorEntityDescription):
|
||||
"""A class that describes Airzone Cloud binary sensor entities."""
|
||||
|
||||
@@ -159,6 +159,8 @@ class AirzoneBinarySensor(AirzoneEntity, BinarySensorEntity):
|
||||
class AirzoneAidooBinarySensor(AirzoneAidooEntity, AirzoneBinarySensor):
|
||||
"""Define an Airzone Cloud Aidoo binary sensor."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
@@ -178,6 +180,8 @@ class AirzoneAidooBinarySensor(AirzoneAidooEntity, AirzoneBinarySensor):
|
||||
class AirzoneSystemBinarySensor(AirzoneSystemEntity, AirzoneBinarySensor):
|
||||
"""Define an Airzone Cloud System binary sensor."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
@@ -197,6 +201,8 @@ class AirzoneSystemBinarySensor(AirzoneSystemEntity, AirzoneBinarySensor):
|
||||
class AirzoneZoneBinarySensor(AirzoneZoneEntity, AirzoneBinarySensor):
|
||||
"""Define an Airzone Cloud Zone binary sensor."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user