mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
2022.11.0 (#81423)
This commit is contained in:
commit
1f0073f450
@ -46,7 +46,6 @@ base_platforms: &base_platforms
|
|||||||
|
|
||||||
# Extra components that trigger the full suite
|
# Extra components that trigger the full suite
|
||||||
components: &components
|
components: &components
|
||||||
- homeassistant/components/alert/**
|
|
||||||
- homeassistant/components/alexa/**
|
- homeassistant/components/alexa/**
|
||||||
- homeassistant/components/application_credentials/**
|
- homeassistant/components/application_credentials/**
|
||||||
- homeassistant/components/auth/**
|
- homeassistant/components/auth/**
|
||||||
|
22
.coveragerc
22
.coveragerc
@ -37,6 +37,8 @@ omit =
|
|||||||
homeassistant/components/airnow/sensor.py
|
homeassistant/components/airnow/sensor.py
|
||||||
homeassistant/components/airthings/__init__.py
|
homeassistant/components/airthings/__init__.py
|
||||||
homeassistant/components/airthings/sensor.py
|
homeassistant/components/airthings/sensor.py
|
||||||
|
homeassistant/components/airthings_ble/__init__.py
|
||||||
|
homeassistant/components/airthings_ble/sensor.py
|
||||||
homeassistant/components/airtouch4/__init__.py
|
homeassistant/components/airtouch4/__init__.py
|
||||||
homeassistant/components/airtouch4/climate.py
|
homeassistant/components/airtouch4/climate.py
|
||||||
homeassistant/components/airtouch4/const.py
|
homeassistant/components/airtouch4/const.py
|
||||||
@ -159,6 +161,8 @@ omit =
|
|||||||
homeassistant/components/brunt/const.py
|
homeassistant/components/brunt/const.py
|
||||||
homeassistant/components/brunt/cover.py
|
homeassistant/components/brunt/cover.py
|
||||||
homeassistant/components/bsblan/climate.py
|
homeassistant/components/bsblan/climate.py
|
||||||
|
homeassistant/components/bsblan/const.py
|
||||||
|
homeassistant/components/bsblan/entity.py
|
||||||
homeassistant/components/bt_home_hub_5/device_tracker.py
|
homeassistant/components/bt_home_hub_5/device_tracker.py
|
||||||
homeassistant/components/bt_smarthub/device_tracker.py
|
homeassistant/components/bt_smarthub/device_tracker.py
|
||||||
homeassistant/components/buienradar/sensor.py
|
homeassistant/components/buienradar/sensor.py
|
||||||
@ -405,9 +409,11 @@ omit =
|
|||||||
homeassistant/components/flick_electric/sensor.py
|
homeassistant/components/flick_electric/sensor.py
|
||||||
homeassistant/components/flock/notify.py
|
homeassistant/components/flock/notify.py
|
||||||
homeassistant/components/flume/__init__.py
|
homeassistant/components/flume/__init__.py
|
||||||
|
homeassistant/components/flume/binary_sensor.py
|
||||||
homeassistant/components/flume/coordinator.py
|
homeassistant/components/flume/coordinator.py
|
||||||
homeassistant/components/flume/entity.py
|
homeassistant/components/flume/entity.py
|
||||||
homeassistant/components/flume/sensor.py
|
homeassistant/components/flume/sensor.py
|
||||||
|
homeassistant/components/flume/util.py
|
||||||
homeassistant/components/folder/sensor.py
|
homeassistant/components/folder/sensor.py
|
||||||
homeassistant/components/folder_watcher/*
|
homeassistant/components/folder_watcher/*
|
||||||
homeassistant/components/foobot/sensor.py
|
homeassistant/components/foobot/sensor.py
|
||||||
@ -534,6 +540,7 @@ omit =
|
|||||||
homeassistant/components/hunterdouglas_powerview/entity.py
|
homeassistant/components/hunterdouglas_powerview/entity.py
|
||||||
homeassistant/components/hunterdouglas_powerview/model.py
|
homeassistant/components/hunterdouglas_powerview/model.py
|
||||||
homeassistant/components/hunterdouglas_powerview/scene.py
|
homeassistant/components/hunterdouglas_powerview/scene.py
|
||||||
|
homeassistant/components/hunterdouglas_powerview/select.py
|
||||||
homeassistant/components/hunterdouglas_powerview/sensor.py
|
homeassistant/components/hunterdouglas_powerview/sensor.py
|
||||||
homeassistant/components/hunterdouglas_powerview/shade_data.py
|
homeassistant/components/hunterdouglas_powerview/shade_data.py
|
||||||
homeassistant/components/hunterdouglas_powerview/util.py
|
homeassistant/components/hunterdouglas_powerview/util.py
|
||||||
@ -578,6 +585,7 @@ omit =
|
|||||||
homeassistant/components/intellifire/coordinator.py
|
homeassistant/components/intellifire/coordinator.py
|
||||||
homeassistant/components/intellifire/entity.py
|
homeassistant/components/intellifire/entity.py
|
||||||
homeassistant/components/intellifire/fan.py
|
homeassistant/components/intellifire/fan.py
|
||||||
|
homeassistant/components/intellifire/number.py
|
||||||
homeassistant/components/intellifire/sensor.py
|
homeassistant/components/intellifire/sensor.py
|
||||||
homeassistant/components/intellifire/switch.py
|
homeassistant/components/intellifire/switch.py
|
||||||
homeassistant/components/intesishome/*
|
homeassistant/components/intesishome/*
|
||||||
@ -608,7 +616,6 @@ omit =
|
|||||||
homeassistant/components/izone/__init__.py
|
homeassistant/components/izone/__init__.py
|
||||||
homeassistant/components/izone/climate.py
|
homeassistant/components/izone/climate.py
|
||||||
homeassistant/components/izone/discovery.py
|
homeassistant/components/izone/discovery.py
|
||||||
homeassistant/components/jellyfin/__init__.py
|
|
||||||
homeassistant/components/jellyfin/media_source.py
|
homeassistant/components/jellyfin/media_source.py
|
||||||
homeassistant/components/joaoapps_join/*
|
homeassistant/components/joaoapps_join/*
|
||||||
homeassistant/components/juicenet/__init__.py
|
homeassistant/components/juicenet/__init__.py
|
||||||
@ -657,8 +664,6 @@ omit =
|
|||||||
homeassistant/components/kostal_plenticore/switch.py
|
homeassistant/components/kostal_plenticore/switch.py
|
||||||
homeassistant/components/kwb/sensor.py
|
homeassistant/components/kwb/sensor.py
|
||||||
homeassistant/components/lacrosse/sensor.py
|
homeassistant/components/lacrosse/sensor.py
|
||||||
homeassistant/components/lametric/notify.py
|
|
||||||
homeassistant/components/lametric/number.py
|
|
||||||
homeassistant/components/lannouncer/notify.py
|
homeassistant/components/lannouncer/notify.py
|
||||||
homeassistant/components/lastfm/sensor.py
|
homeassistant/components/lastfm/sensor.py
|
||||||
homeassistant/components/launch_library/__init__.py
|
homeassistant/components/launch_library/__init__.py
|
||||||
@ -855,6 +860,7 @@ omit =
|
|||||||
homeassistant/components/noaa_tides/sensor.py
|
homeassistant/components/noaa_tides/sensor.py
|
||||||
homeassistant/components/nobo_hub/__init__.py
|
homeassistant/components/nobo_hub/__init__.py
|
||||||
homeassistant/components/nobo_hub/climate.py
|
homeassistant/components/nobo_hub/climate.py
|
||||||
|
homeassistant/components/nobo_hub/sensor.py
|
||||||
homeassistant/components/norway_air/air_quality.py
|
homeassistant/components/norway_air/air_quality.py
|
||||||
homeassistant/components/notify_events/notify.py
|
homeassistant/components/notify_events/notify.py
|
||||||
homeassistant/components/notion/__init__.py
|
homeassistant/components/notion/__init__.py
|
||||||
@ -1101,11 +1107,10 @@ omit =
|
|||||||
homeassistant/components/sesame/lock.py
|
homeassistant/components/sesame/lock.py
|
||||||
homeassistant/components/seven_segments/image_processing.py
|
homeassistant/components/seven_segments/image_processing.py
|
||||||
homeassistant/components/seventeentrack/sensor.py
|
homeassistant/components/seventeentrack/sensor.py
|
||||||
homeassistant/components/shelly/__init__.py
|
|
||||||
homeassistant/components/shelly/binary_sensor.py
|
homeassistant/components/shelly/binary_sensor.py
|
||||||
homeassistant/components/shelly/climate.py
|
homeassistant/components/shelly/climate.py
|
||||||
|
homeassistant/components/shelly/coordinator.py
|
||||||
homeassistant/components/shelly/entity.py
|
homeassistant/components/shelly/entity.py
|
||||||
homeassistant/components/shelly/light.py
|
|
||||||
homeassistant/components/shelly/number.py
|
homeassistant/components/shelly/number.py
|
||||||
homeassistant/components/shelly/sensor.py
|
homeassistant/components/shelly/sensor.py
|
||||||
homeassistant/components/shelly/utils.py
|
homeassistant/components/shelly/utils.py
|
||||||
@ -1161,6 +1166,7 @@ omit =
|
|||||||
homeassistant/components/smtp/notify.py
|
homeassistant/components/smtp/notify.py
|
||||||
homeassistant/components/snapcast/*
|
homeassistant/components/snapcast/*
|
||||||
homeassistant/components/snmp/*
|
homeassistant/components/snmp/*
|
||||||
|
homeassistant/components/snooz/__init__.py
|
||||||
homeassistant/components/solaredge/__init__.py
|
homeassistant/components/solaredge/__init__.py
|
||||||
homeassistant/components/solaredge/coordinator.py
|
homeassistant/components/solaredge/coordinator.py
|
||||||
homeassistant/components/solaredge/sensor.py
|
homeassistant/components/solaredge/sensor.py
|
||||||
@ -1230,7 +1236,9 @@ omit =
|
|||||||
homeassistant/components/swisscom/device_tracker.py
|
homeassistant/components/swisscom/device_tracker.py
|
||||||
homeassistant/components/switchbee/__init__.py
|
homeassistant/components/switchbee/__init__.py
|
||||||
homeassistant/components/switchbee/button.py
|
homeassistant/components/switchbee/button.py
|
||||||
|
homeassistant/components/switchbee/climate.py
|
||||||
homeassistant/components/switchbee/coordinator.py
|
homeassistant/components/switchbee/coordinator.py
|
||||||
|
homeassistant/components/switchbee/cover.py
|
||||||
homeassistant/components/switchbee/entity.py
|
homeassistant/components/switchbee/entity.py
|
||||||
homeassistant/components/switchbee/light.py
|
homeassistant/components/switchbee/light.py
|
||||||
homeassistant/components/switchbee/switch.py
|
homeassistant/components/switchbee/switch.py
|
||||||
@ -1421,6 +1429,7 @@ omit =
|
|||||||
homeassistant/components/velbus/const.py
|
homeassistant/components/velbus/const.py
|
||||||
homeassistant/components/velbus/cover.py
|
homeassistant/components/velbus/cover.py
|
||||||
homeassistant/components/velbus/diagnostics.py
|
homeassistant/components/velbus/diagnostics.py
|
||||||
|
homeassistant/components/velbus/entity.py
|
||||||
homeassistant/components/velbus/light.py
|
homeassistant/components/velbus/light.py
|
||||||
homeassistant/components/velbus/sensor.py
|
homeassistant/components/velbus/sensor.py
|
||||||
homeassistant/components/velbus/switch.py
|
homeassistant/components/velbus/switch.py
|
||||||
@ -1573,6 +1582,9 @@ omit =
|
|||||||
homeassistant/components/youless/const.py
|
homeassistant/components/youless/const.py
|
||||||
homeassistant/components/youless/sensor.py
|
homeassistant/components/youless/sensor.py
|
||||||
homeassistant/components/zabbix/*
|
homeassistant/components/zabbix/*
|
||||||
|
homeassistant/components/zamg/__init__.py
|
||||||
|
homeassistant/components/zamg/const.py
|
||||||
|
homeassistant/components/zamg/coordinator.py
|
||||||
homeassistant/components/zamg/sensor.py
|
homeassistant/components/zamg/sensor.py
|
||||||
homeassistant/components/zamg/weather.py
|
homeassistant/components/zamg/weather.py
|
||||||
homeassistant/components/zengge/light.py
|
homeassistant/components/zengge/light.py
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"postCreateCommand": "script/setup",
|
"postCreateCommand": "script/setup",
|
||||||
"postStartCommand": "script/bootstrap",
|
"postStartCommand": "script/bootstrap",
|
||||||
"containerEnv": { "DEVCONTAINER": "1" },
|
"containerEnv": { "DEVCONTAINER": "1" },
|
||||||
"appPort": 8123,
|
"appPort": ["8123:8123"],
|
||||||
"runArgs": ["-e", "GIT_EDITOR=code --wait"],
|
"runArgs": ["-e", "GIT_EDITOR=code --wait"],
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-python.vscode-pylance",
|
"ms-python.vscode-pylance",
|
||||||
@ -17,8 +17,14 @@
|
|||||||
// Please keep this file in sync with settings in home-assistant/.vscode/settings.default.json
|
// Please keep this file in sync with settings in home-assistant/.vscode/settings.default.json
|
||||||
"settings": {
|
"settings": {
|
||||||
"python.pythonPath": "/usr/local/bin/python",
|
"python.pythonPath": "/usr/local/bin/python",
|
||||||
"python.linting.pylintEnabled": true,
|
|
||||||
"python.linting.enabled": true,
|
"python.linting.enabled": true,
|
||||||
|
"python.linting.pylintEnabled": true,
|
||||||
|
"python.formatting.blackPath": "/usr/local/bin/black",
|
||||||
|
"python.linting.flake8Path": "/usr/local/bin/flake8",
|
||||||
|
"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.formatting.provider": "black",
|
||||||
"python.testing.pytestArgs": ["--no-cov"],
|
"python.testing.pytestArgs": ["--no-cov"],
|
||||||
"editor.formatOnPaste": false,
|
"editor.formatOnPaste": false,
|
||||||
|
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -46,9 +46,9 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: What type of installation are you running?
|
label: What type of installation are you running?
|
||||||
description: >
|
description: >
|
||||||
Can be found in: [Settings -> About](https://my.home-assistant.io/redirect/info/).
|
Can be found in: [Settings -> System-> Repairs -> Three Dots in Upper Right -> System information](https://my.home-assistant.io/redirect/system_health/).
|
||||||
|
|
||||||
[](https://my.home-assistant.io/redirect/info/)
|
[](https://my.home-assistant.io/redirect/system_health/)
|
||||||
options:
|
options:
|
||||||
- Home Assistant OS
|
- Home Assistant OS
|
||||||
- Home Assistant Container
|
- Home Assistant Container
|
||||||
|
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -75,18 +75,6 @@ If the code communicates with devices, web services, or third-party tools:
|
|||||||
- [ ] For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.
|
- [ ] For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.
|
||||||
- [ ] Untested files have been added to `.coveragerc`.
|
- [ ] Untested files have been added to `.coveragerc`.
|
||||||
|
|
||||||
The integration reached or maintains the following [Integration Quality Scale][quality-scale]:
|
|
||||||
<!--
|
|
||||||
The Integration Quality Scale scores an integration on the code quality
|
|
||||||
and user experience. Each level of the quality scale consists of a list
|
|
||||||
of requirements. We highly recommend getting your integration scored!
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] No score or internal
|
|
||||||
- [ ] 🥈 Silver
|
|
||||||
- [ ] 🥇 Gold
|
|
||||||
- [ ] 🏆 Platinum
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This project is very active and we have a high turnover of pull requests.
|
This project is very active and we have a high turnover of pull requests.
|
||||||
|
|
||||||
|
30
.github/workflows/builder.yml
vendored
30
.github/workflows/builder.yml
vendored
@ -24,12 +24,12 @@ jobs:
|
|||||||
publish: ${{ steps.version.outputs.publish }}
|
publish: ${{ steps.version.outputs.publish }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
@ -67,10 +67,10 @@ jobs:
|
|||||||
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
|
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ jobs:
|
|||||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Download nightly wheels of frontend
|
- name: Download nightly wheels of frontend
|
||||||
if: needs.init.outputs.channel == 'dev'
|
if: needs.init.outputs.channel == 'dev'
|
||||||
@ -115,7 +115,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
if: needs.init.outputs.channel == 'dev'
|
if: needs.init.outputs.channel == 'dev'
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
@ -146,13 +146,13 @@ jobs:
|
|||||||
echo "${{ github.sha }};${{ github.ref }};${{ github.event_name }};${{ github.actor }}" > rootfs/OFFICIAL_IMAGE
|
echo "${{ github.sha }};${{ github.ref }};${{ github.event_name }};${{ github.actor }}" > rootfs/OFFICIAL_IMAGE
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2.0.0
|
uses: docker/login-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v2.0.0
|
uses: docker/login-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
@ -198,7 +198,7 @@ jobs:
|
|||||||
- yellow
|
- yellow
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Set build additional args
|
- name: Set build additional args
|
||||||
run: |
|
run: |
|
||||||
@ -212,13 +212,13 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2.0.0
|
uses: docker/login-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v2.0.0
|
uses: docker/login-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
@ -241,7 +241,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Initialize git
|
- name: Initialize git
|
||||||
uses: home-assistant/actions/helpers/git-init@master
|
uses: home-assistant/actions/helpers/git-init@master
|
||||||
@ -280,18 +280,18 @@ jobs:
|
|||||||
- "homeassistant"
|
- "homeassistant"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: matrix.registry == 'homeassistant'
|
if: matrix.registry == 'homeassistant'
|
||||||
uses: docker/login-action@v2.0.0
|
uses: docker/login-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
if: matrix.registry == 'ghcr.io/home-assistant'
|
if: matrix.registry == 'ghcr.io/home-assistant'
|
||||||
uses: docker/login-action@v2.0.0
|
uses: docker/login-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
|
289
.github/workflows/ci.yaml
vendored
289
.github/workflows/ci.yaml
vendored
@ -20,13 +20,11 @@ on:
|
|||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CACHE_VERSION: 1
|
CACHE_VERSION: 3
|
||||||
PIP_CACHE_VERSION: 1
|
PIP_CACHE_VERSION: 3
|
||||||
HA_SHORT_VERSION: 2022.10
|
HA_SHORT_VERSION: 2022.11
|
||||||
# Pin latest Python patch versions to avoid issues
|
DEFAULT_PYTHON: 3.9
|
||||||
# with runners using different versions.
|
ALL_PYTHON_VERSIONS: "['3.9', '3.10']"
|
||||||
DEFAULT_PYTHON: 3.9.14
|
|
||||||
ALL_PYTHON_VERSIONS: "['3.9.14', '3.10.7']"
|
|
||||||
PRE_COMMIT_CACHE: ~/.cache/pre-commit
|
PRE_COMMIT_CACHE: ~/.cache/pre-commit
|
||||||
PIP_CACHE: /tmp/pip-cache
|
PIP_CACHE: /tmp/pip-cache
|
||||||
SQLALCHEMY_WARN_20: 1
|
SQLALCHEMY_WARN_20: 1
|
||||||
@ -58,21 +56,21 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Generate partial Python venv restore key
|
- name: Generate partial Python venv restore key
|
||||||
id: generate_python_cache_key
|
id: generate_python_cache_key
|
||||||
run: >-
|
run: >-
|
||||||
echo "::set-output name=key::venv-${{ env.CACHE_VERSION }}-${{
|
echo "key=venv-${{ env.CACHE_VERSION }}-${{
|
||||||
hashFiles('requirements_test.txt') }}-${{
|
hashFiles('requirements_test.txt') }}-${{
|
||||||
hashFiles('requirements_all.txt') }}-${{
|
hashFiles('requirements_all.txt') }}-${{
|
||||||
hashFiles('homeassistant/package_constraints.txt') }}"
|
hashFiles('homeassistant/package_constraints.txt') }}" >> $GITHUB_OUTPUT
|
||||||
- name: Generate partial pre-commit restore key
|
- name: Generate partial pre-commit restore key
|
||||||
id: generate_pre-commit_cache_key
|
id: generate_pre-commit_cache_key
|
||||||
run: >-
|
run: >-
|
||||||
echo "::set-output name=key::${{ env.CACHE_VERSION }}-${{ env.DEFAULT_PYTHON }}-${{
|
echo "key=pre-commit-${{ env.CACHE_VERSION }}-${{
|
||||||
hashFiles('.pre-commit-config.yaml') }}"
|
hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
|
||||||
- name: Filter for core changes
|
- name: Filter for core changes
|
||||||
uses: dorny/paths-filter@v2.10.2
|
uses: dorny/paths-filter@v2.11.1
|
||||||
id: core
|
id: core
|
||||||
with:
|
with:
|
||||||
filters: .core_files.yaml
|
filters: .core_files.yaml
|
||||||
@ -87,7 +85,7 @@ jobs:
|
|||||||
echo "Result:"
|
echo "Result:"
|
||||||
cat .integration_paths.yaml
|
cat .integration_paths.yaml
|
||||||
- name: Filter for integration changes
|
- name: Filter for integration changes
|
||||||
uses: dorny/paths-filter@v2.10.2
|
uses: dorny/paths-filter@v2.11.1
|
||||||
id: integrations
|
id: integrations
|
||||||
with:
|
with:
|
||||||
filters: .integration_paths.yaml
|
filters: .integration_paths.yaml
|
||||||
@ -148,19 +146,19 @@ jobs:
|
|||||||
|
|
||||||
# Output & sent to GitHub Actions
|
# Output & sent to GitHub Actions
|
||||||
echo "python_versions: ${ALL_PYTHON_VERSIONS}"
|
echo "python_versions: ${ALL_PYTHON_VERSIONS}"
|
||||||
echo "::set-output name=python_versions::${ALL_PYTHON_VERSIONS}"
|
echo "python_versions=${ALL_PYTHON_VERSIONS}" >> $GITHUB_OUTPUT
|
||||||
echo "test_full_suite: ${test_full_suite}"
|
echo "test_full_suite: ${test_full_suite}"
|
||||||
echo "::set-output name=test_full_suite::${test_full_suite}"
|
echo "test_full_suite=${test_full_suite}" >> $GITHUB_OUTPUT
|
||||||
echo "integrations_glob: ${integrations_glob}"
|
echo "integrations_glob: ${integrations_glob}"
|
||||||
echo "::set-output name=integrations_glob::${integrations_glob}"
|
echo "integrations_glob=${integrations_glob}" >> $GITHUB_OUTPUT
|
||||||
echo "test_group_count: ${test_group_count}"
|
echo "test_group_count: ${test_group_count}"
|
||||||
echo "::set-output name=test_group_count::${test_group_count}"
|
echo "test_group_count=${test_group_count}" >> $GITHUB_OUTPUT
|
||||||
echo "test_groups: ${test_groups}"
|
echo "test_groups: ${test_groups}"
|
||||||
echo "::set-output name=test_groups::${test_groups}"
|
echo "test_groups=${test_groups}" >> $GITHUB_OUTPUT
|
||||||
echo "tests: ${tests}"
|
echo "tests: ${tests}"
|
||||||
echo "::set-output name=tests::${tests}"
|
echo "tests=${tests}" >> $GITHUB_OUTPUT
|
||||||
echo "tests_glob: ${tests_glob}"
|
echo "tests_glob: ${tests_glob}"
|
||||||
echo "::set-output name=tests_glob::${tests_glob}"
|
echo "tests_glob=${tests_glob}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
pre-commit:
|
pre-commit:
|
||||||
name: Prepare pre-commit base
|
name: Prepare pre-commit base
|
||||||
@ -169,18 +167,21 @@ jobs:
|
|||||||
- info
|
- info
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Create Python virtual environment
|
- name: Create Python virtual environment
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -190,10 +191,12 @@ jobs:
|
|||||||
pip install "$(cat requirements_test.txt | grep pre-commit)"
|
pip install "$(cat requirements_test.txt | grep pre-commit)"
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Install pre-commit dependencies
|
- name: Install pre-commit dependencies
|
||||||
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -208,18 +211,21 @@ jobs:
|
|||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if Python cache restore failed
|
- name: Fail job if Python cache restore failed
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -227,10 +233,12 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if pre-commit cache restore failed
|
- name: Fail job if pre-commit cache restore failed
|
||||||
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -257,18 +265,21 @@ jobs:
|
|||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if Python cache restore failed
|
- name: Fail job if Python cache restore failed
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -276,10 +287,12 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if pre-commit cache restore failed
|
- name: Fail job if pre-commit cache restore failed
|
||||||
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -309,18 +322,21 @@ jobs:
|
|||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if Python cache restore failed
|
- name: Fail job if Python cache restore failed
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -328,10 +344,12 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if pre-commit cache restore failed
|
- name: Fail job if pre-commit cache restore failed
|
||||||
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -350,18 +368,21 @@ jobs:
|
|||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: ${{ runner.os }}-venv-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if Python cache restore failed
|
- name: Fail job if Python cache restore failed
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -369,10 +390,12 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: ${{ runner.os }}-pre-commit-${{ needs.info.outputs.pre-commit_cache_key }}
|
key: >-
|
||||||
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Fail job if pre-commit cache restore failed
|
- name: Fail job if pre-commit cache restore failed
|
||||||
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
if: steps.cache-precommit.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
@ -472,20 +495,21 @@ jobs:
|
|||||||
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
|
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
check-latest: true
|
||||||
- name: Generate partial pip restore key
|
- name: Generate partial pip restore key
|
||||||
id: generate-pip-key
|
id: generate-pip-key
|
||||||
run: >-
|
run: >-
|
||||||
echo "::set-output name=key::pip-${{ env.PIP_CACHE_VERSION }}-${{
|
echo "key=pip-${{ env.PIP_CACHE_VERSION }}-${{
|
||||||
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')"
|
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
@ -493,7 +517,7 @@ jobs:
|
|||||||
needs.info.outputs.python_cache_key }}
|
needs.info.outputs.python_cache_key }}
|
||||||
- name: Restore pip wheel cache
|
- name: Restore pip wheel cache
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PIP_CACHE }}
|
path: ${{ env.PIP_CACHE }}
|
||||||
key: >-
|
key: >-
|
||||||
@ -522,7 +546,7 @@ jobs:
|
|||||||
python -m venv venv
|
python -m venv venv
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python --version
|
python --version
|
||||||
pip install --cache-dir=$PIP_CACHE -U "pip>=21.0,<22.3" setuptools wheel
|
pip install --cache-dir=$PIP_CACHE -U "pip>=21.0,<22.4" setuptools wheel
|
||||||
pip install --cache-dir=$PIP_CACHE -r requirements_all.txt --use-deprecated=legacy-resolver
|
pip install --cache-dir=$PIP_CACHE -r requirements_all.txt --use-deprecated=legacy-resolver
|
||||||
pip install --cache-dir=$PIP_CACHE -r requirements_test.txt --use-deprecated=legacy-resolver
|
pip install --cache-dir=$PIP_CACHE -r requirements_test.txt --use-deprecated=legacy-resolver
|
||||||
pip install -e .
|
pip install -e .
|
||||||
@ -535,15 +559,16 @@ jobs:
|
|||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
@ -567,15 +592,16 @@ jobs:
|
|||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
@ -600,15 +626,16 @@ jobs:
|
|||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
@ -644,15 +671,16 @@ jobs:
|
|||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
@ -692,15 +720,16 @@ jobs:
|
|||||||
name: Run pip check ${{ matrix.python-version }}
|
name: Run pip check ${{ matrix.python-version }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
@ -746,15 +775,16 @@ jobs:
|
|||||||
bluez \
|
bluez \
|
||||||
ffmpeg
|
ffmpeg
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
check-latest: true
|
||||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v3.0.8
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
@ -823,7 +853,7 @@ jobs:
|
|||||||
-p no:sugar \
|
-p no:sugar \
|
||||||
tests/components/${{ matrix.group }}
|
tests/components/${{ matrix.group }}
|
||||||
- name: Upload coverage artifact
|
- name: Upload coverage artifact
|
||||||
uses: actions/upload-artifact@v3.1.0
|
uses: actions/upload-artifact@v3.1.1
|
||||||
with:
|
with:
|
||||||
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
@ -831,6 +861,109 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./script/check_dirty
|
./script/check_dirty
|
||||||
|
|
||||||
|
pytest-mariadb:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
services:
|
||||||
|
mariadb:
|
||||||
|
image: mariadb:10.9.3
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
env:
|
||||||
|
MYSQL_ROOT_PASSWORD: password
|
||||||
|
options: --health-cmd="mysqladmin ping -uroot -ppassword" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||||
|
if: |
|
||||||
|
(github.event_name != 'push' || github.event.repository.full_name == 'home-assistant/core')
|
||||||
|
&& github.event.inputs.lint-only != 'true'
|
||||||
|
&& needs.info.outputs.test_full_suite == 'true'
|
||||||
|
needs:
|
||||||
|
- info
|
||||||
|
- base
|
||||||
|
- gen-requirements-all
|
||||||
|
- hassfest
|
||||||
|
- lint-black
|
||||||
|
- lint-other
|
||||||
|
- lint-isort
|
||||||
|
- mypy
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: ${{ fromJson(needs.info.outputs.python_versions) }}
|
||||||
|
name: >-
|
||||||
|
Run tests Python ${{ matrix.python-version }} (mariadb)
|
||||||
|
steps:
|
||||||
|
- name: Install additional OS dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install \
|
||||||
|
bluez \
|
||||||
|
ffmpeg \
|
||||||
|
libmariadb-dev-compat
|
||||||
|
- name: Check out code from GitHub
|
||||||
|
uses: actions/checkout@v3.1.0
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
id: python
|
||||||
|
uses: actions/setup-python@v4.3.0
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
check-latest: true
|
||||||
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
|
id: cache-venv
|
||||||
|
uses: actions/cache@v3.0.11
|
||||||
|
with:
|
||||||
|
path: venv
|
||||||
|
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
|
needs.info.outputs.python_cache_key }}
|
||||||
|
- name: Fail job if Python cache restore failed
|
||||||
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
echo "Failed to restore Python virtual environment from cache"
|
||||||
|
exit 1
|
||||||
|
- name: Register Python problem matcher
|
||||||
|
run: |
|
||||||
|
echo "::add-matcher::.github/workflows/matchers/python.json"
|
||||||
|
- name: Install Pytest Annotation plugin
|
||||||
|
run: |
|
||||||
|
. venv/bin/activate
|
||||||
|
# Ideally this should be part of our dependencies
|
||||||
|
# However this plugin is fairly new and doesn't run correctly
|
||||||
|
# on a non-GitHub environment.
|
||||||
|
pip install pytest-github-actions-annotate-failures==0.1.3
|
||||||
|
- name: Register pytest slow test problem matcher
|
||||||
|
run: |
|
||||||
|
echo "::add-matcher::.github/workflows/matchers/pytest-slow.json"
|
||||||
|
- name: Install SQL Python libraries
|
||||||
|
run: |
|
||||||
|
. venv/bin/activate
|
||||||
|
pip install mysqlclient sqlalchemy_utils
|
||||||
|
- name: Run pytest (partially)
|
||||||
|
timeout-minutes: 10
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
. venv/bin/activate
|
||||||
|
python --version
|
||||||
|
|
||||||
|
python3 -X dev -m pytest \
|
||||||
|
-qq \
|
||||||
|
--timeout=9 \
|
||||||
|
-n 1 \
|
||||||
|
--cov="homeassistant.components.recorder" \
|
||||||
|
--cov-report=xml \
|
||||||
|
--cov-report=term-missing \
|
||||||
|
-o console_output_style=count \
|
||||||
|
--durations=0 \
|
||||||
|
--durations-min=10 \
|
||||||
|
-p no:sugar \
|
||||||
|
--dburl=mysql://root:password@127.0.0.1/homeassistant-test \
|
||||||
|
tests/components/recorder
|
||||||
|
- name: Upload coverage artifact
|
||||||
|
uses: actions/upload-artifact@v3.1.1
|
||||||
|
with:
|
||||||
|
name: coverage-${{ matrix.python-version }}-mariadb
|
||||||
|
path: coverage.xml
|
||||||
|
- name: Check dirty
|
||||||
|
run: |
|
||||||
|
./script/check_dirty
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
name: Upload test coverage to Codecov
|
name: Upload test coverage to Codecov
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@ -839,7 +972,7 @@ jobs:
|
|||||||
- pytest
|
- pytest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
- name: Download all coverage artifacts
|
- name: Download all coverage artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
- name: Upload coverage to Codecov (full coverage)
|
- name: Upload coverage to Codecov (full coverage)
|
||||||
|
6
.github/workflows/stale.yml
vendored
6
.github/workflows/stale.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
|||||||
# - No PRs marked as no-stale
|
# - No PRs marked as no-stale
|
||||||
# - No issues marked as no-stale or help-wanted
|
# - No issues marked as no-stale or help-wanted
|
||||||
- name: 90 days stale issues & PRs policy
|
- name: 90 days stale issues & PRs policy
|
||||||
uses: actions/stale@v6.0.0
|
uses: actions/stale@v6.0.1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 90
|
days-before-stale: 90
|
||||||
@ -54,7 +54,7 @@ jobs:
|
|||||||
# - No PRs marked as no-stale or new-integrations
|
# - No PRs marked as no-stale or new-integrations
|
||||||
# - No issues (-1)
|
# - No issues (-1)
|
||||||
- name: 30 days stale PRs policy
|
- name: 30 days stale PRs policy
|
||||||
uses: actions/stale@v6.0.0
|
uses: actions/stale@v6.0.1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 30
|
days-before-stale: 30
|
||||||
@ -79,7 +79,7 @@ jobs:
|
|||||||
# - No Issues marked as no-stale or help-wanted
|
# - No Issues marked as no-stale or help-wanted
|
||||||
# - No PRs (-1)
|
# - No PRs (-1)
|
||||||
- name: Needs more information stale issues policy
|
- name: Needs more information stale issues policy
|
||||||
uses: actions/stale@v6.0.0
|
uses: actions/stale@v6.0.1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
only-labels: "needs-more-information"
|
only-labels: "needs-more-information"
|
||||||
|
8
.github/workflows/translations.yaml
vendored
8
.github/workflows/translations.yaml
vendored
@ -21,10 +21,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v4.1.0
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
|
15
.github/workflows/wheels.yml
vendored
15
.github/workflows/wheels.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
architectures: ${{ steps.info.outputs.architectures }}
|
architectures: ${{ steps.info.outputs.architectures }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Get information
|
- name: Get information
|
||||||
id: info
|
id: info
|
||||||
@ -57,13 +57,13 @@ jobs:
|
|||||||
) > .env_file
|
) > .env_file
|
||||||
|
|
||||||
- name: Upload env_file
|
- name: Upload env_file
|
||||||
uses: actions/upload-artifact@v3.1.0
|
uses: actions/upload-artifact@v3.1.1
|
||||||
with:
|
with:
|
||||||
name: env_file
|
name: env_file
|
||||||
path: ./.env_file
|
path: ./.env_file
|
||||||
|
|
||||||
- name: Upload requirements_diff
|
- name: Upload requirements_diff
|
||||||
uses: actions/upload-artifact@v3.1.0
|
uses: actions/upload-artifact@v3.1.1
|
||||||
with:
|
with:
|
||||||
name: requirements_diff
|
name: requirements_diff
|
||||||
path: ./requirements_diff.txt
|
path: ./requirements_diff.txt
|
||||||
@ -79,7 +79,7 @@ jobs:
|
|||||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Download env_file
|
- name: Download env_file
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
@ -92,7 +92,7 @@ jobs:
|
|||||||
name: requirements_diff
|
name: requirements_diff
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: home-assistant/wheels@2022.06.7
|
uses: home-assistant/wheels@2022.10.1
|
||||||
with:
|
with:
|
||||||
abi: cp310
|
abi: cp310
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
@ -116,7 +116,7 @@ jobs:
|
|||||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v3.0.2
|
uses: actions/checkout@v3.1.0
|
||||||
|
|
||||||
- name: Download env_file
|
- name: Download env_file
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
@ -140,7 +140,6 @@ jobs:
|
|||||||
sed -i "s|# pycups|pycups|g" ${requirement_file}
|
sed -i "s|# pycups|pycups|g" ${requirement_file}
|
||||||
sed -i "s|# homekit|homekit|g" ${requirement_file}
|
sed -i "s|# homekit|homekit|g" ${requirement_file}
|
||||||
sed -i "s|# decora_wifi|decora_wifi|g" ${requirement_file}
|
sed -i "s|# decora_wifi|decora_wifi|g" ${requirement_file}
|
||||||
sed -i "s|# face_recognition|face_recognition|g" ${requirement_file}
|
|
||||||
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
|
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
|
||||||
sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file}
|
sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file}
|
||||||
done
|
done
|
||||||
@ -161,7 +160,7 @@ jobs:
|
|||||||
sed -i "/numpy/d" homeassistant/package_constraints.txt
|
sed -i "/numpy/d" homeassistant/package_constraints.txt
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: home-assistant/wheels@2022.06.7
|
uses: home-assistant/wheels@2022.10.1
|
||||||
with:
|
with:
|
||||||
abi: cp310
|
abi: cp310
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.38.0
|
rev: v3.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py39-plus]
|
args: [--py39-plus]
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.8.0
|
rev: 22.10.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args:
|
args:
|
||||||
@ -61,7 +61,7 @@ repos:
|
|||||||
- --branch=master
|
- --branch=master
|
||||||
- --branch=rc
|
- --branch=rc
|
||||||
- repo: https://github.com/adrienverge/yamllint.git
|
- repo: https://github.com/adrienverge/yamllint.git
|
||||||
rev: v1.27.1
|
rev: v1.28.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: yamllint
|
- id: yamllint
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
@ -69,11 +69,12 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
- repo: https://github.com/cdce8p/python-typing-update
|
- repo: https://github.com/cdce8p/python-typing-update
|
||||||
rev: v0.3.5
|
rev: v0.5.0
|
||||||
hooks:
|
hooks:
|
||||||
# Run `python-typing-update` hook manually from time to time
|
# Run `python-typing-update` hook manually from time to time
|
||||||
# to update python typing syntax.
|
# to update python typing syntax.
|
||||||
# Will require manual work, before submitting changes!
|
# Will require manual work, before submitting changes!
|
||||||
|
# pre-commit run --hook-stage manual python-typing-update --all-files
|
||||||
- id: python-typing-update
|
- id: python-typing-update
|
||||||
stages: [manual]
|
stages: [manual]
|
||||||
args:
|
args:
|
||||||
@ -113,7 +114,7 @@ repos:
|
|||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
language: script
|
language: script
|
||||||
types: [text]
|
types: [text]
|
||||||
files: ^(homeassistant/.+/(manifest|strings)\.json|\.coveragerc|homeassistant/.+/services\.yaml|script/hassfest/(?!metadata|mypy_config).+\.py)$
|
files: ^(homeassistant/.+/(manifest|strings)\.json|homeassistant/brands/.*\.json|\.coveragerc|homeassistant/.+/services\.yaml|script/hassfest/(?!metadata|mypy_config).+\.py)$
|
||||||
- id: hassfest-metadata
|
- id: hassfest-metadata
|
||||||
name: hassfest-metadata
|
name: hassfest-metadata
|
||||||
entry: script/run-in-env.sh python3 -m script.hassfest -p metadata
|
entry: script/run-in-env.sh python3 -m script.hassfest -p metadata
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# If component is fully covered with type annotations, please add it here
|
# If component is fully covered with type annotations, please add it here
|
||||||
# to enable strict mypy checks.
|
# to enable strict mypy checks.
|
||||||
|
|
||||||
# Stict typing is enabled by default for core files.
|
# Strict typing is enabled by default for core files.
|
||||||
# Add it here to add 'disallow_any_generics'.
|
# Add it here to add 'disallow_any_generics'.
|
||||||
# --- Only for core file! ---
|
# --- Only for core file! ---
|
||||||
homeassistant.exceptions
|
homeassistant.exceptions
|
||||||
@ -57,6 +57,7 @@ homeassistant.components.ambient_station.*
|
|||||||
homeassistant.components.amcrest.*
|
homeassistant.components.amcrest.*
|
||||||
homeassistant.components.ampio.*
|
homeassistant.components.ampio.*
|
||||||
homeassistant.components.anthemav.*
|
homeassistant.components.anthemav.*
|
||||||
|
homeassistant.components.aqualogic.*
|
||||||
homeassistant.components.aseko_pool_live.*
|
homeassistant.components.aseko_pool_live.*
|
||||||
homeassistant.components.asuswrt.*
|
homeassistant.components.asuswrt.*
|
||||||
homeassistant.components.auth.*
|
homeassistant.components.auth.*
|
||||||
@ -64,7 +65,9 @@ homeassistant.components.automation.*
|
|||||||
homeassistant.components.awair.*
|
homeassistant.components.awair.*
|
||||||
homeassistant.components.backup.*
|
homeassistant.components.backup.*
|
||||||
homeassistant.components.baf.*
|
homeassistant.components.baf.*
|
||||||
|
homeassistant.components.bayesian.*
|
||||||
homeassistant.components.binary_sensor.*
|
homeassistant.components.binary_sensor.*
|
||||||
|
homeassistant.components.blockchain.*
|
||||||
homeassistant.components.bluetooth.*
|
homeassistant.components.bluetooth.*
|
||||||
homeassistant.components.bluetooth_tracker.*
|
homeassistant.components.bluetooth_tracker.*
|
||||||
homeassistant.components.bmw_connected_drive.*
|
homeassistant.components.bmw_connected_drive.*
|
||||||
@ -77,6 +80,8 @@ homeassistant.components.calendar.*
|
|||||||
homeassistant.components.camera.*
|
homeassistant.components.camera.*
|
||||||
homeassistant.components.canary.*
|
homeassistant.components.canary.*
|
||||||
homeassistant.components.cover.*
|
homeassistant.components.cover.*
|
||||||
|
homeassistant.components.clickatell.*
|
||||||
|
homeassistant.components.clicksend.*
|
||||||
homeassistant.components.cpuspeed.*
|
homeassistant.components.cpuspeed.*
|
||||||
homeassistant.components.crownstone.*
|
homeassistant.components.crownstone.*
|
||||||
homeassistant.components.deconz.*
|
homeassistant.components.deconz.*
|
||||||
@ -116,6 +121,7 @@ homeassistant.components.geocaching.*
|
|||||||
homeassistant.components.gios.*
|
homeassistant.components.gios.*
|
||||||
homeassistant.components.goalzero.*
|
homeassistant.components.goalzero.*
|
||||||
homeassistant.components.google.*
|
homeassistant.components.google.*
|
||||||
|
homeassistant.components.google_sheets.*
|
||||||
homeassistant.components.greeneye_monitor.*
|
homeassistant.components.greeneye_monitor.*
|
||||||
homeassistant.components.group.*
|
homeassistant.components.group.*
|
||||||
homeassistant.components.guardian.*
|
homeassistant.components.guardian.*
|
||||||
@ -160,6 +166,7 @@ homeassistant.components.lacrosse_view.*
|
|||||||
homeassistant.components.lametric.*
|
homeassistant.components.lametric.*
|
||||||
homeassistant.components.laundrify.*
|
homeassistant.components.laundrify.*
|
||||||
homeassistant.components.lcn.*
|
homeassistant.components.lcn.*
|
||||||
|
homeassistant.components.lidarr.*
|
||||||
homeassistant.components.lifx.*
|
homeassistant.components.lifx.*
|
||||||
homeassistant.components.light.*
|
homeassistant.components.light.*
|
||||||
homeassistant.components.litterrobot.*
|
homeassistant.components.litterrobot.*
|
||||||
@ -208,6 +215,7 @@ homeassistant.components.pvoutput.*
|
|||||||
homeassistant.components.qnap_qsw.*
|
homeassistant.components.qnap_qsw.*
|
||||||
homeassistant.components.rainmachine.*
|
homeassistant.components.rainmachine.*
|
||||||
homeassistant.components.rdw.*
|
homeassistant.components.rdw.*
|
||||||
|
homeassistant.components.radarr.*
|
||||||
homeassistant.components.recollect_waste.*
|
homeassistant.components.recollect_waste.*
|
||||||
homeassistant.components.recorder.*
|
homeassistant.components.recorder.*
|
||||||
homeassistant.components.remote.*
|
homeassistant.components.remote.*
|
||||||
@ -230,9 +238,12 @@ homeassistant.components.sensor.*
|
|||||||
homeassistant.components.senz.*
|
homeassistant.components.senz.*
|
||||||
homeassistant.components.shelly.*
|
homeassistant.components.shelly.*
|
||||||
homeassistant.components.simplisafe.*
|
homeassistant.components.simplisafe.*
|
||||||
|
homeassistant.components.skybell.*
|
||||||
homeassistant.components.slack.*
|
homeassistant.components.slack.*
|
||||||
homeassistant.components.sleepiq.*
|
homeassistant.components.sleepiq.*
|
||||||
homeassistant.components.smhi.*
|
homeassistant.components.smhi.*
|
||||||
|
homeassistant.components.snooz.*
|
||||||
|
homeassistant.components.sonarr.*
|
||||||
homeassistant.components.ssdp.*
|
homeassistant.components.ssdp.*
|
||||||
homeassistant.components.statistics.*
|
homeassistant.components.statistics.*
|
||||||
homeassistant.components.steamist.*
|
homeassistant.components.steamist.*
|
||||||
@ -249,6 +260,7 @@ homeassistant.components.tag.*
|
|||||||
homeassistant.components.tailscale.*
|
homeassistant.components.tailscale.*
|
||||||
homeassistant.components.tautulli.*
|
homeassistant.components.tautulli.*
|
||||||
homeassistant.components.tcp.*
|
homeassistant.components.tcp.*
|
||||||
|
homeassistant.components.tibber.*
|
||||||
homeassistant.components.tile.*
|
homeassistant.components.tile.*
|
||||||
homeassistant.components.tilt_ble.*
|
homeassistant.components.tilt_ble.*
|
||||||
homeassistant.components.tolo.*
|
homeassistant.components.tolo.*
|
||||||
@ -260,6 +272,7 @@ homeassistant.components.trafikverket_train.*
|
|||||||
homeassistant.components.trafikverket_weatherstation.*
|
homeassistant.components.trafikverket_weatherstation.*
|
||||||
homeassistant.components.tts.*
|
homeassistant.components.tts.*
|
||||||
homeassistant.components.twentemilieu.*
|
homeassistant.components.twentemilieu.*
|
||||||
|
homeassistant.components.unifi.update
|
||||||
homeassistant.components.unifiprotect.*
|
homeassistant.components.unifiprotect.*
|
||||||
homeassistant.components.upcloud.*
|
homeassistant.components.upcloud.*
|
||||||
homeassistant.components.update.*
|
homeassistant.components.update.*
|
||||||
@ -279,6 +292,7 @@ homeassistant.components.websocket_api.*
|
|||||||
homeassistant.components.wemo.*
|
homeassistant.components.wemo.*
|
||||||
homeassistant.components.whois.*
|
homeassistant.components.whois.*
|
||||||
homeassistant.components.wiz.*
|
homeassistant.components.wiz.*
|
||||||
|
homeassistant.components.wled.*
|
||||||
homeassistant.components.worldclock.*
|
homeassistant.components.worldclock.*
|
||||||
homeassistant.components.yale_smart_alarm.*
|
homeassistant.components.yale_smart_alarm.*
|
||||||
homeassistant.components.zeroconf.*
|
homeassistant.components.zeroconf.*
|
||||||
|
41
CODEOWNERS
41
CODEOWNERS
@ -19,6 +19,8 @@ build.json @home-assistant/supervisor
|
|||||||
|
|
||||||
# Other code
|
# Other code
|
||||||
/homeassistant/scripts/check_config.py @kellerza
|
/homeassistant/scripts/check_config.py @kellerza
|
||||||
|
/homeassistant/const.py @epenet
|
||||||
|
/homeassistant/util/ @epenet
|
||||||
|
|
||||||
# Integrations
|
# Integrations
|
||||||
/homeassistant/components/abode/ @shred86
|
/homeassistant/components/abode/ @shred86
|
||||||
@ -45,6 +47,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/airnow/ @asymworks
|
/tests/components/airnow/ @asymworks
|
||||||
/homeassistant/components/airthings/ @danielhiversen
|
/homeassistant/components/airthings/ @danielhiversen
|
||||||
/tests/components/airthings/ @danielhiversen
|
/tests/components/airthings/ @danielhiversen
|
||||||
|
/homeassistant/components/airthings_ble/ @vincegio
|
||||||
|
/tests/components/airthings_ble/ @vincegio
|
||||||
/homeassistant/components/airtouch4/ @LonePurpleWolf
|
/homeassistant/components/airtouch4/ @LonePurpleWolf
|
||||||
/tests/components/airtouch4/ @LonePurpleWolf
|
/tests/components/airtouch4/ @LonePurpleWolf
|
||||||
/homeassistant/components/airvisual/ @bachya
|
/homeassistant/components/airvisual/ @bachya
|
||||||
@ -55,8 +59,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/aladdin_connect/ @mkmer
|
/tests/components/aladdin_connect/ @mkmer
|
||||||
/homeassistant/components/alarm_control_panel/ @home-assistant/core
|
/homeassistant/components/alarm_control_panel/ @home-assistant/core
|
||||||
/tests/components/alarm_control_panel/ @home-assistant/core
|
/tests/components/alarm_control_panel/ @home-assistant/core
|
||||||
/homeassistant/components/alert/ @home-assistant/core
|
/homeassistant/components/alert/ @home-assistant/core @frenck
|
||||||
/tests/components/alert/ @home-assistant/core
|
/tests/components/alert/ @home-assistant/core @frenck
|
||||||
/homeassistant/components/alexa/ @home-assistant/cloud @ochlocracy
|
/homeassistant/components/alexa/ @home-assistant/cloud @ochlocracy
|
||||||
/tests/components/alexa/ @home-assistant/cloud @ochlocracy
|
/tests/components/alexa/ @home-assistant/cloud @ochlocracy
|
||||||
/homeassistant/components/almond/ @gcampax @balloob
|
/homeassistant/components/almond/ @gcampax @balloob
|
||||||
@ -281,7 +285,6 @@ build.json @home-assistant/supervisor
|
|||||||
/homeassistant/components/ecovacs/ @OverloadUT @mib1185
|
/homeassistant/components/ecovacs/ @OverloadUT @mib1185
|
||||||
/homeassistant/components/ecowitt/ @pvizeli
|
/homeassistant/components/ecowitt/ @pvizeli
|
||||||
/tests/components/ecowitt/ @pvizeli
|
/tests/components/ecowitt/ @pvizeli
|
||||||
/homeassistant/components/edl21/ @mtdcr
|
|
||||||
/homeassistant/components/efergy/ @tkdrob
|
/homeassistant/components/efergy/ @tkdrob
|
||||||
/tests/components/efergy/ @tkdrob
|
/tests/components/efergy/ @tkdrob
|
||||||
/homeassistant/components/egardia/ @jeroenterheerdt
|
/homeassistant/components/egardia/ @jeroenterheerdt
|
||||||
@ -566,8 +569,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/isy994/ @bdraco @shbatm
|
/tests/components/isy994/ @bdraco @shbatm
|
||||||
/homeassistant/components/izone/ @Swamp-Ig
|
/homeassistant/components/izone/ @Swamp-Ig
|
||||||
/tests/components/izone/ @Swamp-Ig
|
/tests/components/izone/ @Swamp-Ig
|
||||||
/homeassistant/components/jellyfin/ @j-stienstra
|
/homeassistant/components/jellyfin/ @j-stienstra @ctalkington
|
||||||
/tests/components/jellyfin/ @j-stienstra
|
/tests/components/jellyfin/ @j-stienstra @ctalkington
|
||||||
/homeassistant/components/jewish_calendar/ @tsvi
|
/homeassistant/components/jewish_calendar/ @tsvi
|
||||||
/tests/components/jewish_calendar/ @tsvi
|
/tests/components/jewish_calendar/ @tsvi
|
||||||
/homeassistant/components/juicenet/ @jesserockz
|
/homeassistant/components/juicenet/ @jesserockz
|
||||||
@ -602,8 +605,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/kulersky/ @emlove
|
/tests/components/kulersky/ @emlove
|
||||||
/homeassistant/components/lacrosse_view/ @IceBotYT
|
/homeassistant/components/lacrosse_view/ @IceBotYT
|
||||||
/tests/components/lacrosse_view/ @IceBotYT
|
/tests/components/lacrosse_view/ @IceBotYT
|
||||||
/homeassistant/components/lametric/ @robbiet480 @frenck
|
/homeassistant/components/lametric/ @robbiet480 @frenck @bachya
|
||||||
/tests/components/lametric/ @robbiet480 @frenck
|
/tests/components/lametric/ @robbiet480 @frenck @bachya
|
||||||
/homeassistant/components/landisgyr_heat_meter/ @vpathuis
|
/homeassistant/components/landisgyr_heat_meter/ @vpathuis
|
||||||
/tests/components/landisgyr_heat_meter/ @vpathuis
|
/tests/components/landisgyr_heat_meter/ @vpathuis
|
||||||
/homeassistant/components/launch_library/ @ludeeus @DurgNomis-drol
|
/homeassistant/components/launch_library/ @ludeeus @DurgNomis-drol
|
||||||
@ -794,8 +797,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/omnilogic/ @oliver84 @djtimca @gentoosu
|
/tests/components/omnilogic/ @oliver84 @djtimca @gentoosu
|
||||||
/homeassistant/components/onboarding/ @home-assistant/core
|
/homeassistant/components/onboarding/ @home-assistant/core
|
||||||
/tests/components/onboarding/ @home-assistant/core
|
/tests/components/onboarding/ @home-assistant/core
|
||||||
/homeassistant/components/oncue/ @bdraco
|
/homeassistant/components/oncue/ @bdraco @peterager
|
||||||
/tests/components/oncue/ @bdraco
|
/tests/components/oncue/ @bdraco @peterager
|
||||||
/homeassistant/components/ondilo_ico/ @JeromeHXP
|
/homeassistant/components/ondilo_ico/ @JeromeHXP
|
||||||
/tests/components/ondilo_ico/ @JeromeHXP
|
/tests/components/ondilo_ico/ @JeromeHXP
|
||||||
/homeassistant/components/onewire/ @garbled1 @epenet
|
/homeassistant/components/onewire/ @garbled1 @epenet
|
||||||
@ -819,6 +822,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/openweathermap/ @fabaff @freekode @nzapponi
|
/tests/components/openweathermap/ @fabaff @freekode @nzapponi
|
||||||
/homeassistant/components/opnsense/ @mtreinish
|
/homeassistant/components/opnsense/ @mtreinish
|
||||||
/tests/components/opnsense/ @mtreinish
|
/tests/components/opnsense/ @mtreinish
|
||||||
|
/homeassistant/components/oralb/ @bdraco
|
||||||
|
/tests/components/oralb/ @bdraco
|
||||||
/homeassistant/components/oru/ @bvlaicu
|
/homeassistant/components/oru/ @bvlaicu
|
||||||
/homeassistant/components/overkiz/ @imicknl @vlebourl @tetienne
|
/homeassistant/components/overkiz/ @imicknl @vlebourl @tetienne
|
||||||
/tests/components/overkiz/ @imicknl @vlebourl @tetienne
|
/tests/components/overkiz/ @imicknl @vlebourl @tetienne
|
||||||
@ -930,8 +935,6 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/rhasspy/ @balloob @synesthesiam
|
/tests/components/rhasspy/ @balloob @synesthesiam
|
||||||
/homeassistant/components/ridwell/ @bachya
|
/homeassistant/components/ridwell/ @bachya
|
||||||
/tests/components/ridwell/ @bachya
|
/tests/components/ridwell/ @bachya
|
||||||
/homeassistant/components/ring/ @balloob
|
|
||||||
/tests/components/ring/ @balloob
|
|
||||||
/homeassistant/components/risco/ @OnFreund
|
/homeassistant/components/risco/ @OnFreund
|
||||||
/tests/components/risco/ @OnFreund
|
/tests/components/risco/ @OnFreund
|
||||||
/homeassistant/components/rituals_perfume_genie/ @milanmeu
|
/homeassistant/components/rituals_perfume_genie/ @milanmeu
|
||||||
@ -964,8 +967,8 @@ build.json @home-assistant/supervisor
|
|||||||
/homeassistant/components/schedule/ @home-assistant/core
|
/homeassistant/components/schedule/ @home-assistant/core
|
||||||
/tests/components/schedule/ @home-assistant/core
|
/tests/components/schedule/ @home-assistant/core
|
||||||
/homeassistant/components/schluter/ @prairieapps
|
/homeassistant/components/schluter/ @prairieapps
|
||||||
/homeassistant/components/scrape/ @fabaff
|
/homeassistant/components/scrape/ @fabaff @gjohansson-ST @epenet
|
||||||
/tests/components/scrape/ @fabaff
|
/tests/components/scrape/ @fabaff @gjohansson-ST @epenet
|
||||||
/homeassistant/components/screenlogic/ @dieselrabbit @bdraco
|
/homeassistant/components/screenlogic/ @dieselrabbit @bdraco
|
||||||
/tests/components/screenlogic/ @dieselrabbit @bdraco
|
/tests/components/screenlogic/ @dieselrabbit @bdraco
|
||||||
/homeassistant/components/script/ @home-assistant/core
|
/homeassistant/components/script/ @home-assistant/core
|
||||||
@ -1039,6 +1042,8 @@ build.json @home-assistant/supervisor
|
|||||||
/homeassistant/components/smhi/ @gjohansson-ST
|
/homeassistant/components/smhi/ @gjohansson-ST
|
||||||
/tests/components/smhi/ @gjohansson-ST
|
/tests/components/smhi/ @gjohansson-ST
|
||||||
/homeassistant/components/sms/ @ocalvo
|
/homeassistant/components/sms/ @ocalvo
|
||||||
|
/homeassistant/components/snooz/ @AustinBrunkhorst
|
||||||
|
/tests/components/snooz/ @AustinBrunkhorst
|
||||||
/homeassistant/components/solaredge/ @frenck
|
/homeassistant/components/solaredge/ @frenck
|
||||||
/tests/components/solaredge/ @frenck
|
/tests/components/solaredge/ @frenck
|
||||||
/homeassistant/components/solaredge_local/ @drobtravels @scheric
|
/homeassistant/components/solaredge_local/ @drobtravels @scheric
|
||||||
@ -1198,8 +1203,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/upcloud/ @scop
|
/tests/components/upcloud/ @scop
|
||||||
/homeassistant/components/update/ @home-assistant/core
|
/homeassistant/components/update/ @home-assistant/core
|
||||||
/tests/components/update/ @home-assistant/core
|
/tests/components/update/ @home-assistant/core
|
||||||
/homeassistant/components/upnp/ @StevenLooman @ehendrix23
|
/homeassistant/components/upnp/ @StevenLooman
|
||||||
/tests/components/upnp/ @StevenLooman @ehendrix23
|
/tests/components/upnp/ @StevenLooman
|
||||||
/homeassistant/components/uptime/ @frenck
|
/homeassistant/components/uptime/ @frenck
|
||||||
/tests/components/uptime/ @frenck
|
/tests/components/uptime/ @frenck
|
||||||
/homeassistant/components/uptimerobot/ @ludeeus @chemelli74
|
/homeassistant/components/uptimerobot/ @ludeeus @chemelli74
|
||||||
@ -1293,8 +1298,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/xiaomi_aqara/ @danielhiversen @syssi
|
/tests/components/xiaomi_aqara/ @danielhiversen @syssi
|
||||||
/homeassistant/components/xiaomi_ble/ @Jc2k @Ernst79
|
/homeassistant/components/xiaomi_ble/ @Jc2k @Ernst79
|
||||||
/tests/components/xiaomi_ble/ @Jc2k @Ernst79
|
/tests/components/xiaomi_ble/ @Jc2k @Ernst79
|
||||||
/homeassistant/components/xiaomi_miio/ @rytilahti @syssi @starkillerOG @bieniu
|
/homeassistant/components/xiaomi_miio/ @rytilahti @syssi @starkillerOG
|
||||||
/tests/components/xiaomi_miio/ @rytilahti @syssi @starkillerOG @bieniu
|
/tests/components/xiaomi_miio/ @rytilahti @syssi @starkillerOG
|
||||||
/homeassistant/components/xiaomi_tv/ @simse
|
/homeassistant/components/xiaomi_tv/ @simse
|
||||||
/homeassistant/components/xmpp/ @fabaff @flowolf
|
/homeassistant/components/xmpp/ @fabaff @flowolf
|
||||||
/homeassistant/components/yale_smart_alarm/ @gjohansson-ST
|
/homeassistant/components/yale_smart_alarm/ @gjohansson-ST
|
||||||
@ -1313,6 +1318,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/yolink/ @matrixd2
|
/tests/components/yolink/ @matrixd2
|
||||||
/homeassistant/components/youless/ @gjong
|
/homeassistant/components/youless/ @gjong
|
||||||
/tests/components/youless/ @gjong
|
/tests/components/youless/ @gjong
|
||||||
|
/homeassistant/components/zamg/ @killer0071234
|
||||||
|
/tests/components/zamg/ @killer0071234
|
||||||
/homeassistant/components/zengge/ @emontnemery
|
/homeassistant/components/zengge/ @emontnemery
|
||||||
/homeassistant/components/zeroconf/ @bdraco
|
/homeassistant/components/zeroconf/ @bdraco
|
||||||
/tests/components/zeroconf/ @bdraco
|
/tests/components/zeroconf/ @bdraco
|
||||||
|
@ -2,6 +2,15 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.9
|
|||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||||
|
|
||||||
|
# Uninstall pre-installed formatting and linting tools
|
||||||
|
# They would conflict with our pinned versions
|
||||||
|
RUN pipx uninstall black
|
||||||
|
RUN pipx uninstall flake8
|
||||||
|
RUN pipx uninstall pydocstyle
|
||||||
|
RUN pipx uninstall pycodestyle
|
||||||
|
RUN pipx uninstall mypy
|
||||||
|
RUN pipx uninstall pylint
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
|
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
|
10
build.yaml
10
build.yaml
@ -1,11 +1,11 @@
|
|||||||
image: homeassistant/{arch}-homeassistant
|
image: homeassistant/{arch}-homeassistant
|
||||||
shadow_repository: ghcr.io/home-assistant
|
shadow_repository: ghcr.io/home-assistant
|
||||||
build_from:
|
build_from:
|
||||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2022.07.0
|
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2022.10.0
|
||||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2022.07.0
|
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2022.10.0
|
||||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2022.07.0
|
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2022.10.0
|
||||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2022.07.0
|
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2022.10.0
|
||||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2022.07.0
|
i386: ghcr.io/home-assistant/i386-homeassistant-base:2022.10.0
|
||||||
codenotary:
|
codenotary:
|
||||||
signer: notary@home-assistant.io
|
signer: notary@home-assistant.io
|
||||||
base_image: notary@home-assistant.io
|
base_image: notary@home-assistant.io
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
@ -21,7 +21,7 @@ from .components import http, persistent_notification
|
|||||||
from .const import (
|
from .const import (
|
||||||
REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||||
REQUIRED_NEXT_PYTHON_VER,
|
REQUIRED_NEXT_PYTHON_VER,
|
||||||
SIGNAL_BOOTSTRAP_INTEGRATONS,
|
SIGNAL_BOOTSTRAP_INTEGRATIONS,
|
||||||
)
|
)
|
||||||
from .exceptions import HomeAssistantError
|
from .exceptions import HomeAssistantError
|
||||||
from .helpers import (
|
from .helpers import (
|
||||||
@ -431,7 +431,7 @@ async def _async_watch_pending_setups(hass: core.HomeAssistant) -> None:
|
|||||||
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
|
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
|
||||||
if remaining_with_setup_started or not previous_was_empty:
|
if remaining_with_setup_started or not previous_was_empty:
|
||||||
async_dispatcher_send(
|
async_dispatcher_send(
|
||||||
hass, SIGNAL_BOOTSTRAP_INTEGRATONS, remaining_with_setup_started
|
hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, remaining_with_setup_started
|
||||||
)
|
)
|
||||||
previous_was_empty = not remaining_with_setup_started
|
previous_was_empty = not remaining_with_setup_started
|
||||||
await asyncio.sleep(SLOW_STARTUP_CHECK_INTERVAL)
|
await asyncio.sleep(SLOW_STARTUP_CHECK_INTERVAL)
|
||||||
@ -622,7 +622,7 @@ async def _async_set_up_integrations(
|
|||||||
_LOGGER.warning("Setup timed out for bootstrap - moving forward")
|
_LOGGER.warning("Setup timed out for bootstrap - moving forward")
|
||||||
|
|
||||||
watch_task.cancel()
|
watch_task.cancel()
|
||||||
async_dispatcher_send(hass, SIGNAL_BOOTSTRAP_INTEGRATONS, {})
|
async_dispatcher_send(hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, {})
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Integration setup times: %s",
|
"Integration setup times: %s",
|
||||||
|
5
homeassistant/brands/airthings.json
Normal file
5
homeassistant/brands/airthings.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"domain": "airthings",
|
||||||
|
"name": "Airthings",
|
||||||
|
"integrations": ["airthings", "airthings_ble"]
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"domain": "devolo",
|
"domain": "devolo",
|
||||||
"name": "devolo",
|
"name": "devolo",
|
||||||
"integrations": ["devolo_home_control", "devolo_home_network"]
|
"integrations": ["devolo_home_control", "devolo_home_network"],
|
||||||
|
"iot_standards": ["zwave"]
|
||||||
}
|
}
|
||||||
|
5
homeassistant/brands/ikea.json
Normal file
5
homeassistant/brands/ikea.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"domain": "ikea",
|
||||||
|
"name": "IKEA",
|
||||||
|
"integrations": ["symfonisk", "tradfri"]
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "raspberry_pi",
|
|
||||||
"name": "Raspberry Pi",
|
|
||||||
"integrations": ["rpi_camera", "rpi_power", "remote_rpi_gpio"]
|
|
||||||
}
|
|
5
homeassistant/brands/raspberry_pi.json
Normal file
5
homeassistant/brands/raspberry_pi.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"domain": "raspberry_pi",
|
||||||
|
"name": "Raspberry Pi",
|
||||||
|
"integrations": ["raspberry_pi", "rpi_camera", "rpi_power", "remote_rpi_gpio"]
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"domain": "u_tec",
|
"domain": "u_tec",
|
||||||
"name": "U-tec",
|
"name": "U-tec",
|
||||||
"iot_standards": ["zwave"]
|
"integrations": ["ultraloq"]
|
||||||
}
|
}
|
||||||
|
6
homeassistant/components/3_day_blinds/manifest.json
Normal file
6
homeassistant/components/3_day_blinds/manifest.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"domain": "3_day_blinds",
|
||||||
|
"name": "3 Day Blinds",
|
||||||
|
"integration_type": "virtual",
|
||||||
|
"supported_by": "motion_blinds"
|
||||||
|
}
|
@ -11,13 +11,13 @@
|
|||||||
"reauth_confirm": {
|
"reauth_confirm": {
|
||||||
"data": {
|
"data": {
|
||||||
"password": "\u041f\u0430\u0440\u043e\u043b\u0430",
|
"password": "\u041f\u0430\u0440\u043e\u043b\u0430",
|
||||||
"username": "Email"
|
"username": "\u0418\u043c\u0435\u0439\u043b"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"data": {
|
"data": {
|
||||||
"password": "\u041f\u0430\u0440\u043e\u043b\u0430",
|
"password": "\u041f\u0430\u0440\u043e\u043b\u0430",
|
||||||
"username": "E-mail \u0430\u0434\u0440\u0435\u0441"
|
"username": "\u0418\u043c\u0435\u0439\u043b"
|
||||||
},
|
},
|
||||||
"title": "\u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0412\u0430\u0448\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0432\u0445\u043e\u0434 \u0432 Abode"
|
"title": "\u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0412\u0430\u0448\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0432\u0445\u043e\u0434 \u0432 Abode"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"reauth_successful": "Godkjenning p\u00e5 nytt var vellykket",
|
"reauth_successful": "Re-autentisering var vellykket",
|
||||||
"single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig."
|
"single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
@ -17,6 +17,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||||
|
|
||||||
from .const import ATTR_FORECAST, CONF_FORECAST, DOMAIN, MANUFACTURER
|
from .const import ATTR_FORECAST, CONF_FORECAST, DOMAIN, MANUFACTURER
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
current = await self.accuweather.async_get_current_conditions()
|
current = await self.accuweather.async_get_current_conditions()
|
||||||
forecast = (
|
forecast = (
|
||||||
await self.accuweather.async_get_forecast(
|
await self.accuweather.async_get_forecast(
|
||||||
metric=self.hass.config.units.is_metric
|
metric=self.hass.config.units is METRIC_SYSTEM
|
||||||
)
|
)
|
||||||
if self.forecast
|
if self.forecast
|
||||||
else {}
|
else {}
|
||||||
|
@ -7,5 +7,6 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["accuweather"]
|
"loggers": ["accuweather"],
|
||||||
|
"integration_type": "service"
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ from homeassistant.core import HomeAssistant, callback
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||||
|
|
||||||
from . import AccuWeatherDataUpdateCoordinator
|
from . import AccuWeatherDataUpdateCoordinator
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -189,6 +190,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="WindGustDay",
|
key="WindGustDay",
|
||||||
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
icon="mdi:weather-windy",
|
icon="mdi:weather-windy",
|
||||||
name="Wind gust day",
|
name="Wind gust day",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
@ -200,6 +202,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="WindGustNight",
|
key="WindGustNight",
|
||||||
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
icon="mdi:weather-windy",
|
icon="mdi:weather-windy",
|
||||||
name="Wind gust night",
|
name="Wind gust night",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
@ -211,6 +214,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="WindDay",
|
key="WindDay",
|
||||||
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
icon="mdi:weather-windy",
|
icon="mdi:weather-windy",
|
||||||
name="Wind day",
|
name="Wind day",
|
||||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||||
@ -221,6 +225,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="WindNight",
|
key="WindNight",
|
||||||
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
icon="mdi:weather-windy",
|
icon="mdi:weather-windy",
|
||||||
name="Wind night",
|
name="Wind night",
|
||||||
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
unit_fn=lambda metric: SPEED_KILOMETERS_PER_HOUR
|
||||||
@ -243,6 +248,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="Ceiling",
|
key="Ceiling",
|
||||||
|
device_class=SensorDeviceClass.DISTANCE,
|
||||||
icon="mdi:weather-fog",
|
icon="mdi:weather-fog",
|
||||||
name="Cloud ceiling",
|
name="Cloud ceiling",
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
@ -329,6 +335,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="Wind",
|
key="Wind",
|
||||||
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
icon="mdi:weather-windy",
|
icon="mdi:weather-windy",
|
||||||
name="Wind",
|
name="Wind",
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
@ -339,6 +346,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
|||||||
),
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="WindGust",
|
key="WindGust",
|
||||||
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
icon="mdi:weather-windy",
|
icon="mdi:weather-windy",
|
||||||
name="Wind gust",
|
name="Wind gust",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
@ -405,12 +413,12 @@ class AccuWeatherSensor(
|
|||||||
self._attr_unique_id = (
|
self._attr_unique_id = (
|
||||||
f"{coordinator.location_key}-{description.key}".lower()
|
f"{coordinator.location_key}-{description.key}".lower()
|
||||||
)
|
)
|
||||||
if self.coordinator.hass.config.units.is_metric:
|
if self.coordinator.hass.config.units is METRIC_SYSTEM:
|
||||||
self._unit_system = API_METRIC
|
self._unit_system = API_METRIC
|
||||||
else:
|
else:
|
||||||
self._unit_system = API_IMPERIAL
|
self._unit_system = API_IMPERIAL
|
||||||
self._attr_native_unit_of_measurement = self.entity_description.unit_fn(
|
self._attr_native_unit_of_measurement = self.entity_description.unit_fn(
|
||||||
self.coordinator.hass.config.units.is_metric
|
self.coordinator.hass.config.units is METRIC_SYSTEM
|
||||||
)
|
)
|
||||||
self._attr_device_info = coordinator.device_info
|
self._attr_device_info = coordinator.device_info
|
||||||
if forecast_day is not None:
|
if forecast_day is not None:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"single_instance_allowed": "\u0412\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e. \u0412\u044a\u0437\u043c\u043e\u0436\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f."
|
"single_instance_allowed": "\u0412\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e. \u0412\u044a\u0437\u043c\u043e\u0436\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0445 \u043f\u0440\u0438 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435",
|
"cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435",
|
||||||
"invalid_api_key": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d API \u043a\u043b\u044e\u0447"
|
"invalid_api_key": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d API \u043a\u043b\u044e\u0447"
|
||||||
},
|
},
|
||||||
"step": {
|
"step": {
|
||||||
|
@ -33,6 +33,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
from homeassistant.util.dt import utc_from_timestamp
|
from homeassistant.util.dt import utc_from_timestamp
|
||||||
|
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||||
|
|
||||||
from . import AccuWeatherDataUpdateCoordinator
|
from . import AccuWeatherDataUpdateCoordinator
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -70,7 +71,7 @@ class AccuWeatherEntity(
|
|||||||
# Coordinator data is used also for sensors which don't have units automatically
|
# Coordinator data is used also for sensors which don't have units automatically
|
||||||
# converted, hence the weather entity's native units follow the configured unit
|
# converted, hence the weather entity's native units follow the configured unit
|
||||||
# system
|
# system
|
||||||
if coordinator.hass.config.units.is_metric:
|
if coordinator.hass.config.units is METRIC_SYSTEM:
|
||||||
self._attr_native_precipitation_unit = LENGTH_MILLIMETERS
|
self._attr_native_precipitation_unit = LENGTH_MILLIMETERS
|
||||||
self._attr_native_pressure_unit = PRESSURE_HPA
|
self._attr_native_pressure_unit = PRESSURE_HPA
|
||||||
self._attr_native_temperature_unit = TEMP_CELSIUS
|
self._attr_native_temperature_unit = TEMP_CELSIUS
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Adax",
|
"name": "Adax",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/adax",
|
"documentation": "https://www.home-assistant.io/integrations/adax",
|
||||||
"requirements": ["adax==0.2.0", "Adax-local==0.1.4"],
|
"requirements": ["adax==0.2.0", "Adax-local==0.1.5"],
|
||||||
"codeowners": ["@danielhiversen"],
|
"codeowners": ["@danielhiversen"],
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["adax", "adax_local"]
|
"loggers": ["adax", "adax_local"]
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
"requirements": ["adguardhome==0.5.1"],
|
"requirements": ["adguardhome==0.5.1"],
|
||||||
"codeowners": ["@frenck"],
|
"codeowners": ["@frenck"],
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
|
"integration_type": "service",
|
||||||
"loggers": ["adguardhome"]
|
"loggers": ["adguardhome"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
|
"already_configured": "\u0423\u0441\u043b\u0443\u0433\u0430\u0442\u0430 \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u0430",
|
||||||
"existing_instance_updated": "\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430\u0449\u0430\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f."
|
"existing_instance_updated": "\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430\u0449\u0430\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
@ -21,11 +21,11 @@ from homeassistant.components.weather import (
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
DEGREE,
|
DEGREE,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
PRECIPITATION_MILLIMETERS_PER_HOUR,
|
|
||||||
PRESSURE_HPA,
|
PRESSURE_HPA,
|
||||||
SPEED_KILOMETERS_PER_HOUR,
|
SPEED_KILOMETERS_PER_HOUR,
|
||||||
TEMP_CELSIUS,
|
TEMP_CELSIUS,
|
||||||
Platform,
|
Platform,
|
||||||
|
UnitOfVolumetricFlux,
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTRIBUTION = "Powered by AEMET OpenData"
|
ATTRIBUTION = "Powered by AEMET OpenData"
|
||||||
@ -208,7 +208,8 @@ FORECAST_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
|||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=ATTR_API_FORECAST_PRECIPITATION,
|
key=ATTR_API_FORECAST_PRECIPITATION,
|
||||||
name="Precipitation",
|
name="Precipitation",
|
||||||
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
|
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
||||||
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
|
key=ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
|
||||||
@ -265,7 +266,8 @@ WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
|||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=ATTR_API_RAIN,
|
key=ATTR_API_RAIN,
|
||||||
name="Rain",
|
name="Rain",
|
||||||
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
|
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
||||||
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=ATTR_API_RAIN_PROB,
|
key=ATTR_API_RAIN_PROB,
|
||||||
@ -276,7 +278,8 @@ WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
|||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=ATTR_API_SNOW,
|
key=ATTR_API_SNOW,
|
||||||
name="Snow",
|
name="Snow",
|
||||||
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
|
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
||||||
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=ATTR_API_SNOW_PROB,
|
key=ATTR_API_SNOW_PROB,
|
||||||
|
@ -84,8 +84,7 @@ async def async_setup_entry(
|
|||||||
unique_id = f"{config_entry.unique_id} {mode}"
|
unique_id = f"{config_entry.unique_id} {mode}"
|
||||||
entities.append(AemetWeather(name, unique_id, weather_coordinator, mode))
|
entities.append(AemetWeather(name, unique_id, weather_coordinator, mode))
|
||||||
|
|
||||||
if entities:
|
async_add_entities(entities, False)
|
||||||
async_add_entities(entities, False)
|
|
||||||
|
|
||||||
|
|
||||||
class AemetWeather(CoordinatorEntity[WeatherUpdateCoordinator], WeatherEntity):
|
class AemetWeather(CoordinatorEntity[WeatherUpdateCoordinator], WeatherEntity):
|
||||||
|
@ -7,5 +7,6 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["airly"]
|
"loggers": ["airly"],
|
||||||
|
"integration_type": "service"
|
||||||
}
|
}
|
||||||
|
53
homeassistant/components/airnow/diagnostics.py
Normal file
53
homeassistant/components/airnow/diagnostics.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
"""Diagnostics support for AirNow."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_API_KEY,
|
||||||
|
CONF_LATITUDE,
|
||||||
|
CONF_LONGITUDE,
|
||||||
|
CONF_UNIQUE_ID,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from . import AirNowDataUpdateCoordinator
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
ATTR_LATITUDE_CAP = "Latitude"
|
||||||
|
ATTR_LONGITUDE_CAP = "Longitude"
|
||||||
|
ATTR_REPORTING_AREA = "ReportingArea"
|
||||||
|
ATTR_STATE_CODE = "StateCode"
|
||||||
|
|
||||||
|
CONF_TITLE = "title"
|
||||||
|
|
||||||
|
TO_REDACT = {
|
||||||
|
ATTR_LATITUDE_CAP,
|
||||||
|
ATTR_LONGITUDE_CAP,
|
||||||
|
ATTR_REPORTING_AREA,
|
||||||
|
ATTR_STATE_CODE,
|
||||||
|
CONF_API_KEY,
|
||||||
|
CONF_LATITUDE,
|
||||||
|
CONF_LONGITUDE,
|
||||||
|
# The config entry title has latitude/longitude:
|
||||||
|
CONF_TITLE,
|
||||||
|
# The config entry unique ID has latitude/longitude:
|
||||||
|
CONF_UNIQUE_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_config_entry_diagnostics(
|
||||||
|
hass: HomeAssistant, entry: ConfigEntry
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Return diagnostics for a config entry."""
|
||||||
|
coordinator: AirNowDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
|
||||||
|
return async_redact_data(
|
||||||
|
{
|
||||||
|
"entry": entry.as_dict(),
|
||||||
|
"data": coordinator.data,
|
||||||
|
},
|
||||||
|
TO_REDACT,
|
||||||
|
)
|
7
homeassistant/components/airnow/translations/nb.json
Normal file
7
homeassistant/components/airnow/translations/nb.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"unknown": "Uventet feil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
homeassistant/components/airthings/translations/nb.json
Normal file
7
homeassistant/components/airthings/translations/nb.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"unknown": "Uventet feil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
homeassistant/components/airthings_ble/__init__.py
Normal file
74
homeassistant/components/airthings_ble/__init__.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
"""The Airthings BLE integration."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from airthings_ble import AirthingsBluetoothDeviceData
|
||||||
|
|
||||||
|
from homeassistant.components import bluetooth
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||||
|
|
||||||
|
from .const import DEFAULT_SCAN_INTERVAL, DOMAIN
|
||||||
|
|
||||||
|
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
"""Set up Airthings BLE device from a config entry."""
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
address = entry.unique_id
|
||||||
|
|
||||||
|
elevation = hass.config.elevation
|
||||||
|
is_metric = hass.config.units is METRIC_SYSTEM
|
||||||
|
assert address is not None
|
||||||
|
|
||||||
|
ble_device = bluetooth.async_ble_device_from_address(hass, address)
|
||||||
|
|
||||||
|
if not ble_device:
|
||||||
|
raise ConfigEntryNotReady(
|
||||||
|
f"Could not find Airthings device with address {address}"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
except Exception as err:
|
||||||
|
raise UpdateFailed(f"Unable to fetch data: {err}") from err
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
coordinator = DataUpdateCoordinator(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name=DOMAIN,
|
||||||
|
update_method=_async_update_method,
|
||||||
|
update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
|
||||||
|
)
|
||||||
|
|
||||||
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
|
hass.data[DOMAIN][entry.entry_id] = coordinator
|
||||||
|
|
||||||
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
|
|
||||||
|
return unload_ok
|
169
homeassistant/components/airthings_ble/config_flow.py
Normal file
169
homeassistant/components/airthings_ble/config_flow.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
"""Config flow for Airthings BlE integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from airthings_ble import AirthingsBluetoothDeviceData, AirthingsDevice
|
||||||
|
from bleak import BleakError
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components import bluetooth
|
||||||
|
from homeassistant.components.bluetooth import (
|
||||||
|
BluetoothServiceInfo,
|
||||||
|
async_discovered_service_info,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigFlow
|
||||||
|
from homeassistant.const import CONF_ADDRESS
|
||||||
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
|
||||||
|
from .const import DOMAIN, MFCT_ID
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class Discovery:
|
||||||
|
"""A discovered bluetooth device."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
discovery_info: BluetoothServiceInfo
|
||||||
|
device: AirthingsDevice
|
||||||
|
|
||||||
|
|
||||||
|
def get_name(device: AirthingsDevice) -> str:
|
||||||
|
"""Generate name with identifier for device."""
|
||||||
|
return f"{device.name} ({device.identifier})"
|
||||||
|
|
||||||
|
|
||||||
|
class AirthingsDeviceUpdateError(Exception):
|
||||||
|
"""Custom error class for device updates."""
|
||||||
|
|
||||||
|
|
||||||
|
class AirthingsConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
|
"""Handle a config flow for Airthings BLE."""
|
||||||
|
|
||||||
|
VERSION = 1
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""Initialize the config flow."""
|
||||||
|
self._discovered_device: Discovery | None = None
|
||||||
|
self._discovered_devices: dict[str, Discovery] = {}
|
||||||
|
|
||||||
|
async def _get_device_data(
|
||||||
|
self, discovery_info: BluetoothServiceInfo
|
||||||
|
) -> AirthingsDevice:
|
||||||
|
ble_device = bluetooth.async_ble_device_from_address(
|
||||||
|
self.hass, discovery_info.address
|
||||||
|
)
|
||||||
|
if ble_device is None:
|
||||||
|
_LOGGER.debug("no ble_device in _get_device_data")
|
||||||
|
raise AirthingsDeviceUpdateError("No ble_device")
|
||||||
|
|
||||||
|
airthings = AirthingsBluetoothDeviceData(_LOGGER)
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = await airthings.update_device(ble_device)
|
||||||
|
except BleakError as err:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Error connecting to and getting data from %s: %s",
|
||||||
|
discovery_info.address,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
raise AirthingsDeviceUpdateError("Failed getting device data") from err
|
||||||
|
except Exception as err:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Unknown error occurred from %s: %s", discovery_info.address, err
|
||||||
|
)
|
||||||
|
raise err
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def async_step_bluetooth(
|
||||||
|
self, discovery_info: BluetoothServiceInfo
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Handle the bluetooth discovery step."""
|
||||||
|
_LOGGER.debug("Discovered BT device: %s", discovery_info)
|
||||||
|
await self.async_set_unique_id(discovery_info.address)
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
|
try:
|
||||||
|
device = await self._get_device_data(discovery_info)
|
||||||
|
except AirthingsDeviceUpdateError:
|
||||||
|
return self.async_abort(reason="cannot_connect")
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
|
||||||
|
name = get_name(device)
|
||||||
|
self.context["title_placeholders"] = {"name": name}
|
||||||
|
self._discovered_device = Discovery(name, discovery_info, device)
|
||||||
|
|
||||||
|
return await self.async_step_bluetooth_confirm()
|
||||||
|
|
||||||
|
async def async_step_bluetooth_confirm(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Confirm discovery."""
|
||||||
|
if user_input is not None:
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=self.context["title_placeholders"]["name"], data={}
|
||||||
|
)
|
||||||
|
|
||||||
|
self._set_confirm_only()
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="bluetooth_confirm",
|
||||||
|
description_placeholders=self.context["title_placeholders"],
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_user(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Handle the user step to pick discovered device."""
|
||||||
|
if user_input is not None:
|
||||||
|
address = user_input[CONF_ADDRESS]
|
||||||
|
await self.async_set_unique_id(address, raise_on_progress=False)
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
discovery = self._discovered_devices[address]
|
||||||
|
|
||||||
|
self.context["title_placeholders"] = {
|
||||||
|
"name": discovery.name,
|
||||||
|
}
|
||||||
|
|
||||||
|
self._discovered_device = discovery
|
||||||
|
|
||||||
|
return self.async_create_entry(title=discovery.name, data={})
|
||||||
|
|
||||||
|
current_addresses = self._async_current_ids()
|
||||||
|
for discovery_info in async_discovered_service_info(self.hass):
|
||||||
|
address = discovery_info.address
|
||||||
|
if address in current_addresses or address in self._discovered_devices:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if MFCT_ID not in discovery_info.manufacturer_data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
device = await self._get_device_data(discovery_info)
|
||||||
|
except AirthingsDeviceUpdateError:
|
||||||
|
return self.async_abort(reason="cannot_connect")
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
name = get_name(device)
|
||||||
|
self._discovered_devices[address] = Discovery(name, discovery_info, device)
|
||||||
|
|
||||||
|
if not self._discovered_devices:
|
||||||
|
return self.async_abort(reason="no_devices_found")
|
||||||
|
|
||||||
|
titles = {
|
||||||
|
address: get_name(discovery.device)
|
||||||
|
for (address, discovery) in self._discovered_devices.items()
|
||||||
|
}
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_ADDRESS): vol.In(titles),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
9
homeassistant/components/airthings_ble/const.py
Normal file
9
homeassistant/components/airthings_ble/const.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""Constants for Airthings BLE."""
|
||||||
|
|
||||||
|
DOMAIN = "airthings_ble"
|
||||||
|
MFCT_ID = 820
|
||||||
|
|
||||||
|
VOLUME_BECQUEREL = "Bq/m³"
|
||||||
|
VOLUME_PICOCURIE = "pCi/L"
|
||||||
|
|
||||||
|
DEFAULT_SCAN_INTERVAL = 300
|
15
homeassistant/components/airthings_ble/manifest.json
Normal file
15
homeassistant/components/airthings_ble/manifest.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"domain": "airthings_ble",
|
||||||
|
"name": "Airthings BLE",
|
||||||
|
"config_flow": true,
|
||||||
|
"documentation": "https://www.home-assistant.io/integrations/airthings_ble",
|
||||||
|
"requirements": ["airthings-ble==0.5.2"],
|
||||||
|
"dependencies": ["bluetooth"],
|
||||||
|
"codeowners": ["@vincegio"],
|
||||||
|
"iot_class": "local_polling",
|
||||||
|
"bluetooth": [
|
||||||
|
{
|
||||||
|
"manufacturer_id": 820
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
186
homeassistant/components/airthings_ble/sensor.py
Normal file
186
homeassistant/components/airthings_ble/sensor.py
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
"""Support for airthings ble sensors."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from airthings_ble import AirthingsDevice
|
||||||
|
|
||||||
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.sensor import (
|
||||||
|
SensorDeviceClass,
|
||||||
|
SensorEntity,
|
||||||
|
SensorEntityDescription,
|
||||||
|
SensorStateClass,
|
||||||
|
)
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONCENTRATION_PARTS_PER_BILLION,
|
||||||
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
|
LIGHT_LUX,
|
||||||
|
PERCENTAGE,
|
||||||
|
PRESSURE_MBAR,
|
||||||
|
TEMP_CELSIUS,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH
|
||||||
|
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import StateType
|
||||||
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
CoordinatorEntity,
|
||||||
|
DataUpdateCoordinator,
|
||||||
|
)
|
||||||
|
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||||
|
|
||||||
|
from .const import DOMAIN, VOLUME_BECQUEREL, VOLUME_PICOCURIE
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SENSORS_MAPPING_TEMPLATE: dict[str, SensorEntityDescription] = {
|
||||||
|
"radon_1day_avg": SensorEntityDescription(
|
||||||
|
key="radon_1day_avg",
|
||||||
|
native_unit_of_measurement=VOLUME_BECQUEREL,
|
||||||
|
name="Radon 1-day average",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
icon="mdi:radioactive",
|
||||||
|
),
|
||||||
|
"radon_longterm_avg": SensorEntityDescription(
|
||||||
|
key="radon_longterm_avg",
|
||||||
|
native_unit_of_measurement=VOLUME_BECQUEREL,
|
||||||
|
name="Radon longterm average",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
icon="mdi:radioactive",
|
||||||
|
),
|
||||||
|
"radon_1day_level": SensorEntityDescription(
|
||||||
|
key="radon_1day_level",
|
||||||
|
name="Radon 1-day level",
|
||||||
|
icon="mdi:radioactive",
|
||||||
|
),
|
||||||
|
"radon_longterm_level": SensorEntityDescription(
|
||||||
|
key="radon_longterm_level",
|
||||||
|
name="Radon longterm level",
|
||||||
|
icon="mdi:radioactive",
|
||||||
|
),
|
||||||
|
"temperature": SensorEntityDescription(
|
||||||
|
key="temperature",
|
||||||
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
|
native_unit_of_measurement=TEMP_CELSIUS,
|
||||||
|
name="Temperature",
|
||||||
|
),
|
||||||
|
"humidity": SensorEntityDescription(
|
||||||
|
key="humidity",
|
||||||
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
name="Humidity",
|
||||||
|
),
|
||||||
|
"pressure": SensorEntityDescription(
|
||||||
|
key="pressure",
|
||||||
|
device_class=SensorDeviceClass.PRESSURE,
|
||||||
|
native_unit_of_measurement=PRESSURE_MBAR,
|
||||||
|
name="Pressure",
|
||||||
|
),
|
||||||
|
"battery": SensorEntityDescription(
|
||||||
|
key="battery",
|
||||||
|
device_class=SensorDeviceClass.BATTERY,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
name="Battery",
|
||||||
|
),
|
||||||
|
"co2": SensorEntityDescription(
|
||||||
|
key="co2",
|
||||||
|
device_class=SensorDeviceClass.CO2,
|
||||||
|
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||||
|
name="co2",
|
||||||
|
),
|
||||||
|
"voc": SensorEntityDescription(
|
||||||
|
key="voc",
|
||||||
|
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||||
|
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
|
name="VOC",
|
||||||
|
icon="mdi:cloud",
|
||||||
|
),
|
||||||
|
"illuminance": SensorEntityDescription(
|
||||||
|
key="illuminance",
|
||||||
|
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||||
|
native_unit_of_measurement=LIGHT_LUX,
|
||||||
|
name="Illuminance",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: config_entries.ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the Airthings BLE sensors."""
|
||||||
|
is_metric = hass.config.units is METRIC_SYSTEM
|
||||||
|
|
||||||
|
coordinator: DataUpdateCoordinator[AirthingsDevice] = hass.data[DOMAIN][
|
||||||
|
entry.entry_id
|
||||||
|
]
|
||||||
|
|
||||||
|
# we need to change some units
|
||||||
|
sensors_mapping = SENSORS_MAPPING_TEMPLATE.copy()
|
||||||
|
if not is_metric:
|
||||||
|
for val in sensors_mapping.values():
|
||||||
|
if val.native_unit_of_measurement is not VOLUME_BECQUEREL:
|
||||||
|
continue
|
||||||
|
val.native_unit_of_measurement = VOLUME_PICOCURIE
|
||||||
|
|
||||||
|
entities = []
|
||||||
|
_LOGGER.debug("got sensors: %s", coordinator.data.sensors)
|
||||||
|
for sensor_type, sensor_value in coordinator.data.sensors.items():
|
||||||
|
if sensor_type not in sensors_mapping:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Unknown sensor type detected: %s, %s",
|
||||||
|
sensor_type,
|
||||||
|
sensor_value,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
entities.append(
|
||||||
|
AirthingsSensor(coordinator, coordinator.data, sensors_mapping[sensor_type])
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
|
class AirthingsSensor(
|
||||||
|
CoordinatorEntity[DataUpdateCoordinator[AirthingsDevice]], SensorEntity
|
||||||
|
):
|
||||||
|
"""Airthings BLE sensors for the device."""
|
||||||
|
|
||||||
|
_attr_state_class = SensorStateClass.MEASUREMENT
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: DataUpdateCoordinator,
|
||||||
|
airthings_device: AirthingsDevice,
|
||||||
|
entity_description: SensorEntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Populate the airthings entity with relevant data."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = entity_description
|
||||||
|
|
||||||
|
name = f"{airthings_device.name} {airthings_device.identifier}"
|
||||||
|
|
||||||
|
self._attr_unique_id = f"{name}_{entity_description.key}"
|
||||||
|
|
||||||
|
self._id = airthings_device.address
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
connections={
|
||||||
|
(
|
||||||
|
CONNECTION_BLUETOOTH,
|
||||||
|
airthings_device.address,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
name=name,
|
||||||
|
manufacturer="Airthings",
|
||||||
|
hw_version=airthings_device.hw_version,
|
||||||
|
sw_version=airthings_device.sw_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> StateType:
|
||||||
|
"""Return the value reported by the sensor."""
|
||||||
|
return self.coordinator.data.sensors[self.entity_description.key]
|
23
homeassistant/components/airthings_ble/strings.json
Normal file
23
homeassistant/components/airthings_ble/strings.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"flow_title": "[%key:component::bluetooth::config::flow_title%]",
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"description": "[%key:component::bluetooth::config::step::user::description%]",
|
||||||
|
"data": {
|
||||||
|
"address": "[%key:component::bluetooth::config::step::user::data::address%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "[%key:component::bluetooth::config::step::bluetooth_confirm::description%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"abort": {
|
||||||
|
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
|
||||||
|
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||||
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||||
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
|
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
homeassistant/components/airthings_ble/translations/bg.json
Normal file
22
homeassistant/components/airthings_ble/translations/bg.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e",
|
||||||
|
"cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435",
|
||||||
|
"no_devices_found": "\u041d\u044f\u043c\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u043c\u0440\u0435\u0436\u0430\u0442\u0430",
|
||||||
|
"unknown": "\u041d\u0435\u043e\u0447\u0430\u043a\u0432\u0430\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u0418\u0441\u043a\u0430\u0442\u0435 \u043b\u0438 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e"
|
||||||
|
},
|
||||||
|
"description": "\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/ca.json
Normal file
23
homeassistant/components/airthings_ble/translations/ca.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "El dispositiu ja est\u00e0 configurat",
|
||||||
|
"already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs",
|
||||||
|
"cannot_connect": "Ha fallat la connexi\u00f3",
|
||||||
|
"no_devices_found": "No s'han trobat dispositius a la xarxa",
|
||||||
|
"unknown": "Error inesperat"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Vols configurar {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Dispositiu"
|
||||||
|
},
|
||||||
|
"description": "Tria un dispositiu a configurar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/de.json
Normal file
23
homeassistant/components/airthings_ble/translations/de.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Ger\u00e4t ist bereits konfiguriert",
|
||||||
|
"already_in_progress": "Der Konfigurationsablauf wird bereits ausgef\u00fchrt",
|
||||||
|
"cannot_connect": "Verbindung fehlgeschlagen",
|
||||||
|
"no_devices_found": "Keine Ger\u00e4te im Netzwerk gefunden",
|
||||||
|
"unknown": "Unerwarteter Fehler"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "M\u00f6chtest du {name} einrichten?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Ger\u00e4t"
|
||||||
|
},
|
||||||
|
"description": "W\u00e4hle ein Ger\u00e4t zum Einrichten aus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/el.json
Normal file
23
homeassistant/components/airthings_ble/translations/el.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u0397 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af",
|
||||||
|
"already_in_progress": "\u0397 \u03c1\u03bf\u03ae \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7\u03c2 \u03b2\u03c1\u03af\u03c3\u03ba\u03b5\u03c4\u03b1\u03b9 \u03ae\u03b4\u03b7 \u03c3\u03b5 \u03b5\u03be\u03ad\u03bb\u03b9\u03be\u03b7",
|
||||||
|
"cannot_connect": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2",
|
||||||
|
"no_devices_found": "\u0394\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b1\u03bd \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ad\u03c2 \u03c3\u03c4\u03bf \u03b4\u03af\u03ba\u03c4\u03c5\u03bf",
|
||||||
|
"unknown": "\u0391\u03c0\u03c1\u03cc\u03c3\u03bc\u03b5\u03bd\u03bf \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf {name};"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u03a3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae"
|
||||||
|
},
|
||||||
|
"description": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03b3\u03b9\u03b1 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/en.json
Normal file
23
homeassistant/components/airthings_ble/translations/en.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Device is already configured",
|
||||||
|
"already_in_progress": "Configuration flow is already in progress",
|
||||||
|
"cannot_connect": "Failed to connect",
|
||||||
|
"no_devices_found": "No devices found on the network",
|
||||||
|
"unknown": "Unexpected error"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Do you want to setup {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Device"
|
||||||
|
},
|
||||||
|
"description": "Choose a device to setup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/es.json
Normal file
23
homeassistant/components/airthings_ble/translations/es.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "El dispositivo ya est\u00e1 configurado",
|
||||||
|
"already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en curso",
|
||||||
|
"cannot_connect": "No se pudo conectar",
|
||||||
|
"no_devices_found": "No se encontraron dispositivos en la red",
|
||||||
|
"unknown": "Error inesperado"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u00bfQuieres configurar {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Dispositivo"
|
||||||
|
},
|
||||||
|
"description": "Elige un dispositivo para configurar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/et.json
Normal file
23
homeassistant/components/airthings_ble/translations/et.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Seade on juba h\u00e4\u00e4lestatud",
|
||||||
|
"already_in_progress": "Seadistamine on juba k\u00e4imas",
|
||||||
|
"cannot_connect": "\u00dchendamine nurjus",
|
||||||
|
"no_devices_found": "V\u00f5rgust seadmeid ei leitud",
|
||||||
|
"unknown": "Ootamatu t\u00f5rge"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Kas seadistada {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Seade"
|
||||||
|
},
|
||||||
|
"description": "Vali h\u00e4\u00e4lestatav seade"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/fr.json
Normal file
23
homeassistant/components/airthings_ble/translations/fr.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9",
|
||||||
|
"already_in_progress": "La configuration est d\u00e9j\u00e0 en cours",
|
||||||
|
"cannot_connect": "\u00c9chec de connexion",
|
||||||
|
"no_devices_found": "Aucun appareil trouv\u00e9 sur le r\u00e9seau",
|
||||||
|
"unknown": "Erreur inattendue"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Voulez-vous configurer {name}\u00a0?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Appareil"
|
||||||
|
},
|
||||||
|
"description": "S\u00e9lectionnez l'appareil \u00e0 configurer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/he.json
Normal file
23
homeassistant/components/airthings_ble/translations/he.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u05ea\u05e6\u05d5\u05e8\u05ea \u05d4\u05d4\u05ea\u05e7\u05df \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4",
|
||||||
|
"already_in_progress": "\u05d6\u05e8\u05d9\u05de\u05ea \u05d4\u05ea\u05e6\u05d5\u05e8\u05d4 \u05db\u05d1\u05e8 \u05de\u05ea\u05d1\u05e6\u05e2\u05ea",
|
||||||
|
"cannot_connect": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4",
|
||||||
|
"no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05db\u05e9\u05d9\u05e8\u05d9\u05dd \u05d1\u05e8\u05e9\u05ea",
|
||||||
|
"unknown": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05d1\u05dc\u05ea\u05d9 \u05e6\u05e4\u05d5\u05d9\u05d4"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u05d4\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d0\u05ea {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u05d4\u05ea\u05e7\u05df"
|
||||||
|
},
|
||||||
|
"description": "\u05d1\u05d7\u05d9\u05e8\u05ea \u05d4\u05ea\u05e7\u05df \u05dc\u05d4\u05d2\u05d3\u05e8\u05d4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/hu.json
Normal file
23
homeassistant/components/airthings_ble/translations/hu.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van",
|
||||||
|
"already_in_progress": "A be\u00e1ll\u00edt\u00e1si folyamat m\u00e1r el lett kezdve",
|
||||||
|
"cannot_connect": "Sikertelen csatlakoz\u00e1s",
|
||||||
|
"no_devices_found": "Nem tal\u00e1lhat\u00f3 eszk\u00f6z a h\u00e1l\u00f3zaton",
|
||||||
|
"unknown": "V\u00e1ratlan hiba t\u00f6rt\u00e9nt"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Szeretn\u00e9 be\u00e1ll\u00edtani: {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Eszk\u00f6z"
|
||||||
|
},
|
||||||
|
"description": "V\u00e1lasszon egy be\u00e1ll\u00edtand\u00f3 eszk\u00f6zt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/id.json
Normal file
23
homeassistant/components/airthings_ble/translations/id.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Perangkat sudah dikonfigurasi",
|
||||||
|
"already_in_progress": "Alur konfigurasi sedang berlangsung",
|
||||||
|
"cannot_connect": "Gagal terhubung",
|
||||||
|
"no_devices_found": "Tidak ada perangkat yang ditemukan di jaringan",
|
||||||
|
"unknown": "Kesalahan yang tidak diharapkan"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Ingin menyiapkan {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Perangkat"
|
||||||
|
},
|
||||||
|
"description": "Pilih perangkat untuk disiapkan"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/it.json
Normal file
23
homeassistant/components/airthings_ble/translations/it.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato",
|
||||||
|
"already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso",
|
||||||
|
"cannot_connect": "Impossibile connettersi",
|
||||||
|
"no_devices_found": "Nessun dispositivo trovato sulla rete",
|
||||||
|
"unknown": "Errore imprevisto"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Vuoi configurare {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Dispositivo"
|
||||||
|
},
|
||||||
|
"description": "Seleziona un dispositivo da configurare"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/ja.json
Normal file
23
homeassistant/components/airthings_ble/translations/ja.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u30c7\u30d0\u30a4\u30b9\u306f\u3059\u3067\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059",
|
||||||
|
"already_in_progress": "\u69cb\u6210\u30d5\u30ed\u30fc\u306f\u3059\u3067\u306b\u9032\u884c\u4e2d\u3067\u3059",
|
||||||
|
"cannot_connect": "\u63a5\u7d9a\u306b\u5931\u6557\u3057\u307e\u3057\u305f",
|
||||||
|
"no_devices_found": "\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u4e0a\u306b\u30c7\u30d0\u30a4\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093",
|
||||||
|
"unknown": "\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "{name} \u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3057\u307e\u3059\u304b\uff1f"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u30c7\u30d0\u30a4\u30b9"
|
||||||
|
},
|
||||||
|
"description": "\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3059\u308b\u30c7\u30d0\u30a4\u30b9\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Enheten er allerede konfigurert",
|
||||||
|
"cannot_connect": "Tilkobling mislyktes",
|
||||||
|
"unknown": "Uventet feil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/nl.json
Normal file
23
homeassistant/components/airthings_ble/translations/nl.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Nederlands",
|
||||||
|
"already_in_progress": "Nederlands",
|
||||||
|
"cannot_connect": "Nederlands",
|
||||||
|
"no_devices_found": "Nederlands",
|
||||||
|
"unknown": "Nederlands"
|
||||||
|
},
|
||||||
|
"flow_title": "Nederlands",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Nederlands"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Nederlands"
|
||||||
|
},
|
||||||
|
"description": "Nederlands"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/no.json
Normal file
23
homeassistant/components/airthings_ble/translations/no.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Enheten er allerede konfigurert",
|
||||||
|
"already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede",
|
||||||
|
"cannot_connect": "Tilkobling mislyktes",
|
||||||
|
"no_devices_found": "Ingen enheter funnet p\u00e5 nettverket",
|
||||||
|
"unknown": "Uventet feil"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Vil du konfigurere {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Enhet"
|
||||||
|
},
|
||||||
|
"description": "Velg en enhet du vil konfigurere"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/pl.json
Normal file
23
homeassistant/components/airthings_ble/translations/pl.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane",
|
||||||
|
"already_in_progress": "Konfiguracja jest ju\u017c w toku",
|
||||||
|
"cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia",
|
||||||
|
"no_devices_found": "Nie znaleziono urz\u0105dze\u0144 w sieci",
|
||||||
|
"unknown": "Nieoczekiwany b\u0142\u0105d"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Czy chcesz skonfigurowa\u0107 {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Urz\u0105dzenie"
|
||||||
|
},
|
||||||
|
"description": "Wybierz urz\u0105dzenie do skonfigurowania"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Dispositivo j\u00e1 est\u00e1 configurado",
|
||||||
|
"already_in_progress": "O fluxo de configura\u00e7\u00e3o j\u00e1 est\u00e1 em andamento",
|
||||||
|
"cannot_connect": "Falha ao conectar",
|
||||||
|
"no_devices_found": "Nenhum dispositivo encontrado na rede",
|
||||||
|
"unknown": "Erro inesperado"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Deseja configurar {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Dispositivo"
|
||||||
|
},
|
||||||
|
"description": "Escolha um dispositivo para configurar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/ru.json
Normal file
23
homeassistant/components/airthings_ble/translations/ru.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.",
|
||||||
|
"already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.",
|
||||||
|
"cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.",
|
||||||
|
"no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.",
|
||||||
|
"unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430."
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e"
|
||||||
|
},
|
||||||
|
"description": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/sv.json
Normal file
23
homeassistant/components/airthings_ble/translations/sv.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Enheten \u00e4r redan konfigurerad",
|
||||||
|
"already_in_progress": "Konfigurationsfl\u00f6det p\u00e5g\u00e5r redan",
|
||||||
|
"cannot_connect": "Det gick inte att ansluta.",
|
||||||
|
"no_devices_found": "Inga enheter hittades i n\u00e4tverket",
|
||||||
|
"unknown": "Ov\u00e4ntat fel"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "Vill du konfigurera {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Enhet"
|
||||||
|
},
|
||||||
|
"description": "V\u00e4lj en enhet att konfigurera"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
homeassistant/components/airthings_ble/translations/tr.json
Normal file
23
homeassistant/components/airthings_ble/translations/tr.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Cihaz zaten yap\u0131land\u0131r\u0131lm\u0131\u015f",
|
||||||
|
"already_in_progress": "Yap\u0131land\u0131rma ak\u0131\u015f\u0131 zaten devam ediyor",
|
||||||
|
"cannot_connect": "Ba\u011flanma hatas\u0131",
|
||||||
|
"no_devices_found": "A\u011fda cihaz bulunamad\u0131",
|
||||||
|
"unknown": "Beklenmeyen hata"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "{name} kurulumunu yapmak istiyor musunuz?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Cihaz"
|
||||||
|
},
|
||||||
|
"description": "Kurulum i\u00e7in bir cihaz se\u00e7in"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u8bbe\u5907\u5df2\u7ecf\u914d\u7f6e",
|
||||||
|
"already_in_progress": "\u914d\u7f6e\u6d41\u7a0b\u5df2\u5728\u8fdb\u884c\u4e2d",
|
||||||
|
"cannot_connect": "\u65e0\u6cd5\u8fde\u63a5",
|
||||||
|
"no_devices_found": "\u5728\u6b64\u7f51\u7edc\u4e0a\u672a\u627e\u5230\u8bbe\u5907",
|
||||||
|
"unknown": "\u672a\u77e5\u9519\u8bef"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u60a8\u60f3\u8bbe\u7f6e\u7684\u8bbe\u5907\u662f\u5426\u662f\uff1a {name}?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u8bbe\u5907"
|
||||||
|
},
|
||||||
|
"description": "\u9009\u62e9\u4e00\u4e2a\u8bbe\u5907\u4ee5\u914d\u7f6e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u88dd\u7f6e\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210",
|
||||||
|
"already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d",
|
||||||
|
"cannot_connect": "\u9023\u7dda\u5931\u6557",
|
||||||
|
"no_devices_found": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u88dd\u7f6e",
|
||||||
|
"unknown": "\u672a\u9810\u671f\u932f\u8aa4"
|
||||||
|
},
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "\u662f\u5426\u8981\u8a2d\u5b9a {name}\uff1f"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "\u88dd\u7f6e"
|
||||||
|
},
|
||||||
|
"description": "\u9078\u64c7\u6240\u8981\u8a2d\u5b9a\u7684\u88dd\u7f6e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,13 +5,20 @@ from typing import Any
|
|||||||
|
|
||||||
from homeassistant.components.diagnostics import async_redact_data
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_STATE
|
from homeassistant.const import (
|
||||||
|
CONF_API_KEY,
|
||||||
|
CONF_LATITUDE,
|
||||||
|
CONF_LONGITUDE,
|
||||||
|
CONF_STATE,
|
||||||
|
CONF_UNIQUE_ID,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
from .const import CONF_CITY, CONF_COUNTRY, DOMAIN
|
from .const import CONF_CITY, CONF_COUNTRY, DOMAIN
|
||||||
|
|
||||||
CONF_COORDINATES = "coordinates"
|
CONF_COORDINATES = "coordinates"
|
||||||
|
CONF_TITLE = "title"
|
||||||
|
|
||||||
TO_REDACT = {
|
TO_REDACT = {
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
@ -21,6 +28,9 @@ TO_REDACT = {
|
|||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
CONF_LONGITUDE,
|
CONF_LONGITUDE,
|
||||||
CONF_STATE,
|
CONF_STATE,
|
||||||
|
# Config entry title and unique ID may contain sensitive data:
|
||||||
|
CONF_TITLE,
|
||||||
|
CONF_UNIQUE_ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -31,10 +41,6 @@ async def async_get_config_entry_diagnostics(
|
|||||||
coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"entry": {
|
"entry": async_redact_data(entry.as_dict(), TO_REDACT),
|
||||||
"title": entry.title,
|
|
||||||
"data": async_redact_data(entry.data, TO_REDACT),
|
|
||||||
"options": async_redact_data(entry.options, TO_REDACT),
|
|
||||||
},
|
|
||||||
"data": async_redact_data(coordinator.data["data"], TO_REDACT),
|
"data": async_redact_data(coordinator.data["data"], TO_REDACT),
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
"requirements": ["pyairvisual==2022.07.0"],
|
"requirements": ["pyairvisual==2022.07.0"],
|
||||||
"codeowners": ["@bachya"],
|
"codeowners": ["@bachya"],
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["pyairvisual", "pysmb"]
|
"loggers": ["pyairvisual", "pysmb"],
|
||||||
|
"integration_type": "device"
|
||||||
}
|
}
|
||||||
|
7
homeassistant/components/airvisual/translations/nb.json
Normal file
7
homeassistant/components/airvisual/translations/nb.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"general_error": "Uventet feil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Plasseringen er allerede konfigurert eller Node / Pro ID er allerede registrert.",
|
"already_configured": "Plasseringen er allerede konfigurert eller Node / Pro ID er allerede registrert.",
|
||||||
"reauth_successful": "Godkjenning p\u00e5 nytt var vellykket"
|
"reauth_successful": "Re-autentisering var vellykket"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "Tilkobling mislyktes",
|
"cannot_connect": "Tilkobling mislyktes",
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"airvisual__pollutant_level": {
|
"airvisual__pollutant_level": {
|
||||||
"good": "\u05d8\u05d5\u05d1",
|
"good": "\u05d8\u05d5\u05d1",
|
||||||
"unhealthy": "\u05dc\u05d0 \u05d1\u05e8\u05d9\u05d0",
|
"unhealthy": "\u05dc\u05d0 \u05d1\u05e8\u05d9\u05d0",
|
||||||
"unhealthy_sensitive": "\u05dc\u05d0 \u05d1\u05e8\u05d9\u05d0 \u05dc\u05e7\u05d1\u05d5\u05e6\u05d5\u05ea \u05e8\u05d2\u05d9\u05e9\u05d5\u05ea"
|
"unhealthy_sensitive": "\u05dc\u05d0 \u05d1\u05e8\u05d9\u05d0 \u05dc\u05e7\u05d1\u05d5\u05e6\u05d5\u05ea \u05e8\u05d2\u05d9\u05e9\u05d5\u05ea",
|
||||||
|
"very_unhealthy": "\u05de\u05d0\u05d5\u05d3 \u05dc\u05d0 \u05d1\u05e8\u05d9\u05d0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Enheten er allerede konfigurert",
|
"already_configured": "Enheten er allerede konfigurert",
|
||||||
"reauth_successful": "Godkjenning p\u00e5 nytt var vellykket"
|
"reauth_successful": "Re-autentisering var vellykket"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "Tilkobling mislyktes",
|
"cannot_connect": "Tilkobling mislyktes",
|
||||||
|
@ -1,4 +1,18 @@
|
|||||||
{
|
{
|
||||||
|
"device_automation": {
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} er \u00e1 ver\u00f0i \u00fati",
|
||||||
|
"is_armed_home": "{entity_name} er \u00e1 ver\u00f0i heima",
|
||||||
|
"is_armed_night": "{entity_name} er \u00e1 ver\u00f0i n\u00f3tt",
|
||||||
|
"is_disarmed": "{entity_name} er ekki \u00e1 ver\u00f0i"
|
||||||
|
},
|
||||||
|
"trigger_type": {
|
||||||
|
"armed_away": "{entity_name} \u00e1 ver\u00f0i \u00fati",
|
||||||
|
"armed_home": "\u00e1 ver\u00f0i heima",
|
||||||
|
"armed_night": "\u00e1 ver\u00f0i n\u00f3tt",
|
||||||
|
"disarmed": "ekki \u00e1 ver\u00f0i"
|
||||||
|
}
|
||||||
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"_": {
|
"_": {
|
||||||
"armed": "\u00c1 ver\u00f0i",
|
"armed": "\u00c1 ver\u00f0i",
|
||||||
@ -6,7 +20,7 @@
|
|||||||
"armed_home": "\u00c1 ver\u00f0i heima",
|
"armed_home": "\u00c1 ver\u00f0i heima",
|
||||||
"armed_night": "\u00c1 ver\u00f0i n\u00f3tt",
|
"armed_night": "\u00c1 ver\u00f0i n\u00f3tt",
|
||||||
"arming": "Set \u00e1 v\u00f6r\u00f0",
|
"arming": "Set \u00e1 v\u00f6r\u00f0",
|
||||||
"disarmed": "ekki \u00e1 ver\u00f0i",
|
"disarmed": "Ekki \u00e1 ver\u00f0i",
|
||||||
"disarming": "tek af ver\u00f0i",
|
"disarming": "tek af ver\u00f0i",
|
||||||
"pending": "B\u00ed\u00f0ur",
|
"pending": "B\u00ed\u00f0ur",
|
||||||
"triggered": "R\u00e6st"
|
"triggered": "R\u00e6st"
|
||||||
|
@ -3,8 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
from typing import Any
|
||||||
from typing import Any, final
|
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -15,7 +14,6 @@ from homeassistant.components.notify import (
|
|||||||
DOMAIN as DOMAIN_NOTIFY,
|
DOMAIN as DOMAIN_NOTIFY,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
|
||||||
CONF_ENTITY_ID,
|
CONF_ENTITY_ID,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_REPEAT,
|
CONF_REPEAT,
|
||||||
@ -27,10 +25,10 @@ from homeassistant.const import (
|
|||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
)
|
)
|
||||||
from homeassistant.core import Event, HomeAssistant, ServiceCall
|
from homeassistant.core import Event, HomeAssistant
|
||||||
from homeassistant.helpers import service
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
async_track_point_in_time,
|
async_track_point_in_time,
|
||||||
async_track_state_change_event,
|
async_track_state_change_event,
|
||||||
@ -39,39 +37,40 @@ from homeassistant.helpers.template import Template
|
|||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.util.dt import now
|
from homeassistant.util.dt import now
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
from .const import (
|
||||||
|
CONF_ALERT_MESSAGE,
|
||||||
DOMAIN = "alert"
|
CONF_CAN_ACK,
|
||||||
|
CONF_DATA,
|
||||||
CONF_CAN_ACK = "can_acknowledge"
|
CONF_DONE_MESSAGE,
|
||||||
CONF_NOTIFIERS = "notifiers"
|
CONF_NOTIFIERS,
|
||||||
CONF_SKIP_FIRST = "skip_first"
|
CONF_SKIP_FIRST,
|
||||||
CONF_ALERT_MESSAGE = "message"
|
CONF_TITLE,
|
||||||
CONF_DONE_MESSAGE = "done_message"
|
DEFAULT_CAN_ACK,
|
||||||
CONF_TITLE = "title"
|
DEFAULT_SKIP_FIRST,
|
||||||
CONF_DATA = "data"
|
DOMAIN,
|
||||||
|
LOGGER,
|
||||||
DEFAULT_CAN_ACK = True
|
)
|
||||||
DEFAULT_SKIP_FIRST = False
|
|
||||||
|
|
||||||
ALERT_SCHEMA = vol.Schema(
|
ALERT_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_NAME): cv.string,
|
vol.Required(CONF_NAME): cv.string,
|
||||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||||
vol.Required(CONF_STATE, default=STATE_ON): cv.string,
|
vol.Optional(CONF_STATE, default=STATE_ON): cv.string,
|
||||||
vol.Required(CONF_REPEAT): vol.All(
|
vol.Required(CONF_REPEAT): vol.All(
|
||||||
cv.ensure_list,
|
cv.ensure_list,
|
||||||
[vol.Coerce(float)],
|
[vol.Coerce(float)],
|
||||||
# Minimum delay is 1 second = 0.016 minutes
|
# Minimum delay is 1 second = 0.016 minutes
|
||||||
[vol.Range(min=0.016)],
|
[vol.Range(min=0.016)],
|
||||||
),
|
),
|
||||||
vol.Required(CONF_CAN_ACK, default=DEFAULT_CAN_ACK): cv.boolean,
|
vol.Optional(CONF_CAN_ACK, default=DEFAULT_CAN_ACK): cv.boolean,
|
||||||
vol.Required(CONF_SKIP_FIRST, default=DEFAULT_SKIP_FIRST): cv.boolean,
|
vol.Optional(CONF_SKIP_FIRST, default=DEFAULT_SKIP_FIRST): cv.boolean,
|
||||||
vol.Optional(CONF_ALERT_MESSAGE): cv.template,
|
vol.Optional(CONF_ALERT_MESSAGE): cv.template,
|
||||||
vol.Optional(CONF_DONE_MESSAGE): cv.template,
|
vol.Optional(CONF_DONE_MESSAGE): cv.template,
|
||||||
vol.Optional(CONF_TITLE): cv.template,
|
vol.Optional(CONF_TITLE): cv.template,
|
||||||
vol.Optional(CONF_DATA): dict,
|
vol.Optional(CONF_DATA): dict,
|
||||||
vol.Required(CONF_NOTIFIERS): vol.All(cv.ensure_list, [cv.string]),
|
vol.Optional(CONF_NOTIFIERS, default=list): vol.All(
|
||||||
|
cv.ensure_list, [cv.string]
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,16 +78,11 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
{DOMAIN: cv.schema_with_slug_keys(ALERT_SCHEMA)}, extra=vol.ALLOW_EXTRA
|
{DOMAIN: cv.schema_with_slug_keys(ALERT_SCHEMA)}, extra=vol.ALLOW_EXTRA
|
||||||
)
|
)
|
||||||
|
|
||||||
ALERT_SERVICE_SCHEMA = vol.Schema({vol.Required(ATTR_ENTITY_ID): cv.entity_ids})
|
|
||||||
|
|
||||||
|
|
||||||
def is_on(hass: HomeAssistant, entity_id: str) -> bool:
|
|
||||||
"""Return if the alert is firing and not acknowledged."""
|
|
||||||
return hass.states.is_state(entity_id, STATE_ON)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Set up the Alert component."""
|
"""Set up the Alert component."""
|
||||||
|
component = EntityComponent[Alert](LOGGER, DOMAIN, hass)
|
||||||
|
|
||||||
entities: list[Alert] = []
|
entities: list[Alert] = []
|
||||||
|
|
||||||
for object_id, cfg in config[DOMAIN].items():
|
for object_id, cfg in config[DOMAIN].items():
|
||||||
@ -128,50 +122,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
if not entities:
|
if not entities:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def async_handle_alert_service(service_call: ServiceCall) -> None:
|
component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off")
|
||||||
"""Handle calls to alert services."""
|
component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on")
|
||||||
alert_ids = await service.async_extract_entity_ids(hass, service_call)
|
component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle")
|
||||||
|
|
||||||
for alert_id in alert_ids:
|
await component.async_add_entities(entities)
|
||||||
for alert in entities:
|
|
||||||
if alert.entity_id != alert_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
alert.async_set_context(service_call.context)
|
|
||||||
if service_call.service == SERVICE_TURN_ON:
|
|
||||||
await alert.async_turn_on()
|
|
||||||
elif service_call.service == SERVICE_TOGGLE:
|
|
||||||
await alert.async_toggle()
|
|
||||||
else:
|
|
||||||
await alert.async_turn_off()
|
|
||||||
|
|
||||||
# Setup service calls
|
|
||||||
hass.services.async_register(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_TURN_OFF,
|
|
||||||
async_handle_alert_service,
|
|
||||||
schema=ALERT_SERVICE_SCHEMA,
|
|
||||||
)
|
|
||||||
hass.services.async_register(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_TURN_ON,
|
|
||||||
async_handle_alert_service,
|
|
||||||
schema=ALERT_SERVICE_SCHEMA,
|
|
||||||
)
|
|
||||||
hass.services.async_register(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_TOGGLE,
|
|
||||||
async_handle_alert_service,
|
|
||||||
schema=ALERT_SERVICE_SCHEMA,
|
|
||||||
)
|
|
||||||
|
|
||||||
for alert in entities:
|
|
||||||
alert.async_write_ha_state()
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Alert(ToggleEntity):
|
class Alert(Entity):
|
||||||
"""Representation of an alert."""
|
"""Representation of an alert."""
|
||||||
|
|
||||||
_attr_should_poll = False
|
_attr_should_poll = False
|
||||||
@ -227,10 +187,8 @@ class Alert(ToggleEntity):
|
|||||||
hass, [watched_entity_id], self.watched_entity_change
|
hass, [watched_entity_id], self.watched_entity_change
|
||||||
)
|
)
|
||||||
|
|
||||||
@final # type: ignore[misc]
|
|
||||||
@property
|
@property
|
||||||
# pylint: disable=overridden-final-method
|
def state(self) -> str:
|
||||||
def state(self) -> str: # type: ignore[override]
|
|
||||||
"""Return the alert status."""
|
"""Return the alert status."""
|
||||||
if self._firing:
|
if self._firing:
|
||||||
if self._ack:
|
if self._ack:
|
||||||
@ -242,7 +200,7 @@ class Alert(ToggleEntity):
|
|||||||
"""Determine if the alert should start or stop."""
|
"""Determine if the alert should start or stop."""
|
||||||
if (to_state := event.data.get("new_state")) is None:
|
if (to_state := event.data.get("new_state")) is None:
|
||||||
return
|
return
|
||||||
_LOGGER.debug("Watched entity (%s) has changed", event.data.get("entity_id"))
|
LOGGER.debug("Watched entity (%s) has changed", event.data.get("entity_id"))
|
||||||
if to_state.state == self._alert_state and not self._firing:
|
if to_state.state == self._alert_state and not self._firing:
|
||||||
await self.begin_alerting()
|
await self.begin_alerting()
|
||||||
if to_state.state != self._alert_state and self._firing:
|
if to_state.state != self._alert_state and self._firing:
|
||||||
@ -250,7 +208,7 @@ class Alert(ToggleEntity):
|
|||||||
|
|
||||||
async def begin_alerting(self) -> None:
|
async def begin_alerting(self) -> None:
|
||||||
"""Begin the alert procedures."""
|
"""Begin the alert procedures."""
|
||||||
_LOGGER.debug("Beginning Alert: %s", self._attr_name)
|
LOGGER.debug("Beginning Alert: %s", self._attr_name)
|
||||||
self._ack = False
|
self._ack = False
|
||||||
self._firing = True
|
self._firing = True
|
||||||
self._next_delay = 0
|
self._next_delay = 0
|
||||||
@ -264,7 +222,7 @@ class Alert(ToggleEntity):
|
|||||||
|
|
||||||
async def end_alerting(self) -> None:
|
async def end_alerting(self) -> None:
|
||||||
"""End the alert procedures."""
|
"""End the alert procedures."""
|
||||||
_LOGGER.debug("Ending Alert: %s", self._attr_name)
|
LOGGER.debug("Ending Alert: %s", self._attr_name)
|
||||||
if self._cancel is not None:
|
if self._cancel is not None:
|
||||||
self._cancel()
|
self._cancel()
|
||||||
self._cancel = None
|
self._cancel = None
|
||||||
@ -288,7 +246,7 @@ class Alert(ToggleEntity):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not self._ack:
|
if not self._ack:
|
||||||
_LOGGER.info("Alerting: %s", self._attr_name)
|
LOGGER.info("Alerting: %s", self._attr_name)
|
||||||
self._send_done_message = True
|
self._send_done_message = True
|
||||||
|
|
||||||
if self._message_template is not None:
|
if self._message_template is not None:
|
||||||
@ -301,7 +259,7 @@ class Alert(ToggleEntity):
|
|||||||
|
|
||||||
async def _notify_done_message(self) -> None:
|
async def _notify_done_message(self) -> None:
|
||||||
"""Send notification of complete alert."""
|
"""Send notification of complete alert."""
|
||||||
_LOGGER.info("Alerting: %s", self._done_message_template)
|
LOGGER.info("Alerting: %s", self._done_message_template)
|
||||||
self._send_done_message = False
|
self._send_done_message = False
|
||||||
|
|
||||||
if self._done_message_template is None:
|
if self._done_message_template is None:
|
||||||
@ -313,6 +271,9 @@ class Alert(ToggleEntity):
|
|||||||
|
|
||||||
async def _send_notification_message(self, message: Any) -> None:
|
async def _send_notification_message(self, message: Any) -> None:
|
||||||
|
|
||||||
|
if not self._notifiers:
|
||||||
|
return
|
||||||
|
|
||||||
msg_payload = {ATTR_MESSAGE: message}
|
msg_payload = {ATTR_MESSAGE: message}
|
||||||
|
|
||||||
if self._title_template is not None:
|
if self._title_template is not None:
|
||||||
@ -321,7 +282,7 @@ class Alert(ToggleEntity):
|
|||||||
if self._data:
|
if self._data:
|
||||||
msg_payload[ATTR_DATA] = self._data
|
msg_payload[ATTR_DATA] = self._data
|
||||||
|
|
||||||
_LOGGER.debug(msg_payload)
|
LOGGER.debug(msg_payload)
|
||||||
|
|
||||||
for target in self._notifiers:
|
for target in self._notifiers:
|
||||||
await self.hass.services.async_call(
|
await self.hass.services.async_call(
|
||||||
@ -330,13 +291,13 @@ class Alert(ToggleEntity):
|
|||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Async Unacknowledge alert."""
|
"""Async Unacknowledge alert."""
|
||||||
_LOGGER.debug("Reset Alert: %s", self._attr_name)
|
LOGGER.debug("Reset Alert: %s", self._attr_name)
|
||||||
self._ack = False
|
self._ack = False
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Async Acknowledge alert."""
|
"""Async Acknowledge alert."""
|
||||||
_LOGGER.debug("Acknowledged Alert: %s", self._attr_name)
|
LOGGER.debug("Acknowledged Alert: %s", self._attr_name)
|
||||||
self._ack = True
|
self._ack = True
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
19
homeassistant/components/alert/const.py
Normal file
19
homeassistant/components/alert/const.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
"""Constants for the Alert integration."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
|
DOMAIN: Final = "alert"
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
|
CONF_CAN_ACK = "can_acknowledge"
|
||||||
|
CONF_NOTIFIERS = "notifiers"
|
||||||
|
CONF_SKIP_FIRST = "skip_first"
|
||||||
|
CONF_ALERT_MESSAGE = "message"
|
||||||
|
CONF_DONE_MESSAGE = "done_message"
|
||||||
|
CONF_TITLE = "title"
|
||||||
|
CONF_DATA = "data"
|
||||||
|
|
||||||
|
DEFAULT_CAN_ACK = True
|
||||||
|
DEFAULT_SKIP_FIRST = False
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Alert",
|
"name": "Alert",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/alert",
|
"documentation": "https://www.home-assistant.io/integrations/alert",
|
||||||
"after_dependencies": ["notify"],
|
"after_dependencies": ["notify"],
|
||||||
"codeowners": ["@home-assistant/core"],
|
"codeowners": ["@home-assistant/core", "@frenck"],
|
||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"iot_class": "local_push"
|
"iot_class": "local_push"
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
import logging
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -15,9 +14,7 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import Context, HomeAssistant, State
|
from homeassistant.core import Context, HomeAssistant, State
|
||||||
|
|
||||||
from . import DOMAIN
|
from .const import DOMAIN, LOGGER
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
VALID_STATES = {STATE_ON, STATE_OFF}
|
VALID_STATES = {STATE_ON, STATE_OFF}
|
||||||
|
|
||||||
@ -31,11 +28,11 @@ async def _async_reproduce_state(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Reproduce a single state."""
|
"""Reproduce a single state."""
|
||||||
if (cur_state := hass.states.get(state.entity_id)) is None:
|
if (cur_state := hass.states.get(state.entity_id)) is None:
|
||||||
_LOGGER.warning("Unable to find entity %s", state.entity_id)
|
LOGGER.warning("Unable to find entity %s", state.entity_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
if state.state not in VALID_STATES:
|
if state.state not in VALID_STATES:
|
||||||
_LOGGER.warning(
|
LOGGER.warning(
|
||||||
"Invalid state specified for %s: %s", state.entity_id, state.state
|
"Invalid state specified for %s: %s", state.entity_id, state.state
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -20,7 +20,7 @@ from homeassistant.components.sensor import (
|
|||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CURRENCY_DOLLAR, ENERGY_KILO_WATT_HOUR
|
from homeassistant.const import CURRENCY_DOLLAR, ENERGY_KILO_WATT_HOUR, PERCENTAGE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
@ -247,7 +247,7 @@ async def async_setup_entry(
|
|||||||
renewables_description = SensorEntityDescription(
|
renewables_description = SensorEntityDescription(
|
||||||
key="renewables",
|
key="renewables",
|
||||||
name=f"{entry.title} - Renewables",
|
name=f"{entry.title} - Renewables",
|
||||||
native_unit_of_measurement="%",
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
icon="mdi:solar-power",
|
icon="mdi:solar-power",
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"unknown_error": "Uventet feil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_api_token": "Ongeldige API-sleutel",
|
"invalid_api_token": "Ongeldige API-sleutel",
|
||||||
|
"no_site": "Geen site opgegeven",
|
||||||
"unknown_error": "Onverwachte fout"
|
"unknown_error": "Onverwachte fout"
|
||||||
},
|
},
|
||||||
"step": {
|
"step": {
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"invalid_api_token": "Ogiltig API-nyckel",
|
||||||
|
"no_site": "Ingen plats har tillhandah\u00e5llits.",
|
||||||
|
"unknown_error": "Ov\u00e4ntat fel"
|
||||||
|
},
|
||||||
"step": {
|
"step": {
|
||||||
"site": {
|
"site": {
|
||||||
"data": {
|
"data": {
|
||||||
|
@ -5,7 +5,7 @@ from typing import Any
|
|||||||
|
|
||||||
from homeassistant.components.diagnostics import async_redact_data
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_API_KEY, CONF_LOCATION
|
from homeassistant.const import CONF_API_KEY, CONF_LOCATION, CONF_UNIQUE_ID
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import AmbientStation
|
from . import AmbientStation
|
||||||
@ -16,6 +16,7 @@ CONF_APP_KEY_CAMEL = "appKey"
|
|||||||
CONF_DEVICE_ID_CAMEL = "deviceId"
|
CONF_DEVICE_ID_CAMEL = "deviceId"
|
||||||
CONF_MAC_ADDRESS = "mac_address"
|
CONF_MAC_ADDRESS = "mac_address"
|
||||||
CONF_MAC_ADDRESS_CAMEL = "macAddress"
|
CONF_MAC_ADDRESS_CAMEL = "macAddress"
|
||||||
|
CONF_TITLE = "title"
|
||||||
CONF_TZ = "tz"
|
CONF_TZ = "tz"
|
||||||
|
|
||||||
TO_REDACT = {
|
TO_REDACT = {
|
||||||
@ -28,6 +29,9 @@ TO_REDACT = {
|
|||||||
CONF_MAC_ADDRESS,
|
CONF_MAC_ADDRESS,
|
||||||
CONF_MAC_ADDRESS_CAMEL,
|
CONF_MAC_ADDRESS_CAMEL,
|
||||||
CONF_TZ,
|
CONF_TZ,
|
||||||
|
# Config entry title and unique ID may contain sensitive data:
|
||||||
|
CONF_TITLE,
|
||||||
|
CONF_UNIQUE_ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -38,9 +42,6 @@ async def async_get_config_entry_diagnostics(
|
|||||||
ambient: AmbientStation = hass.data[DOMAIN][entry.entry_id]
|
ambient: AmbientStation = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"entry": {
|
"entry": async_redact_data(entry.as_dict(), TO_REDACT),
|
||||||
"title": entry.title,
|
|
||||||
"data": async_redact_data(entry.data, TO_REDACT),
|
|
||||||
},
|
|
||||||
"stations": async_redact_data(ambient.stations, TO_REDACT),
|
"stations": async_redact_data(ambient.stations, TO_REDACT),
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
"requirements": ["aioambient==2021.11.0"],
|
"requirements": ["aioambient==2021.11.0"],
|
||||||
"codeowners": ["@bachya"],
|
"codeowners": ["@bachya"],
|
||||||
"iot_class": "cloud_push",
|
"iot_class": "cloud_push",
|
||||||
"loggers": ["aioambient"]
|
"loggers": ["aioambient"],
|
||||||
|
"integration_type": "hub"
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ from homeassistant.const import (
|
|||||||
LIGHT_LUX,
|
LIGHT_LUX,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
PRECIPITATION_INCHES,
|
PRECIPITATION_INCHES,
|
||||||
PRECIPITATION_INCHES_PER_HOUR,
|
|
||||||
PRESSURE_INHG,
|
PRESSURE_INHG,
|
||||||
SPEED_MILES_PER_HOUR,
|
SPEED_MILES_PER_HOUR,
|
||||||
TEMP_FAHRENHEIT,
|
TEMP_FAHRENHEIT,
|
||||||
|
UnitOfVolumetricFlux,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity import EntityDescription
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
@ -194,9 +194,9 @@ SENSOR_DESCRIPTIONS = (
|
|||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=TYPE_HOURLYRAININ,
|
key=TYPE_HOURLYRAININ,
|
||||||
name="Hourly rain rate",
|
name="Hourly rain rate",
|
||||||
icon="mdi:water",
|
native_unit_of_measurement=UnitOfVolumetricFlux.INCHES_PER_HOUR,
|
||||||
native_unit_of_measurement=PRECIPITATION_INCHES_PER_HOUR,
|
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key=TYPE_HUMIDITY10,
|
key=TYPE_HUMIDITY10,
|
||||||
|
6
homeassistant/components/amp_motorization/manifest.json
Normal file
6
homeassistant/components/amp_motorization/manifest.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"domain": "amp_motorization",
|
||||||
|
"name": "AMP Motorization",
|
||||||
|
"integration_type": "virtual",
|
||||||
|
"supported_by": "motion_blinds"
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
"""Send instance and usage analytics."""
|
"""Send instance and usage analytics."""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import websocket_api
|
from homeassistant.components import websocket_api
|
||||||
@ -41,7 +43,7 @@ async def async_setup(hass: HomeAssistant, _: ConfigType) -> bool:
|
|||||||
async def websocket_analytics(
|
async def websocket_analytics(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
connection: websocket_api.connection.ActiveConnection,
|
connection: websocket_api.connection.ActiveConnection,
|
||||||
msg: dict,
|
msg: dict[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Return analytics preferences."""
|
"""Return analytics preferences."""
|
||||||
analytics: Analytics = hass.data[DOMAIN]
|
analytics: Analytics = hass.data[DOMAIN]
|
||||||
@ -62,7 +64,7 @@ async def websocket_analytics(
|
|||||||
async def websocket_analytics_preferences(
|
async def websocket_analytics_preferences(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
connection: websocket_api.connection.ActiveConnection,
|
connection: websocket_api.connection.ActiveConnection,
|
||||||
msg: dict,
|
msg: dict[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Update analytics preferences."""
|
"""Update analytics preferences."""
|
||||||
preferences = msg[ATTR_PREFERENCES]
|
preferences = msg[ATTR_PREFERENCES]
|
||||||
|
@ -2,37 +2,20 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pydroid_ipcam import PyDroidIPCam
|
from pydroid_ipcam import PyDroidIPCam
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
CONF_SCAN_INTERVAL,
|
|
||||||
CONF_SENSORS,
|
|
||||||
CONF_SWITCHES,
|
|
||||||
CONF_TIMEOUT,
|
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
Platform,
|
Platform,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
||||||
from homeassistant.helpers.typing import ConfigType
|
|
||||||
|
|
||||||
from .const import (
|
from .const import DOMAIN
|
||||||
CONF_MOTION_SENSOR,
|
|
||||||
DEFAULT_NAME,
|
|
||||||
DEFAULT_PORT,
|
|
||||||
DEFAULT_TIMEOUT,
|
|
||||||
DOMAIN,
|
|
||||||
SCAN_INTERVAL,
|
|
||||||
SENSORS,
|
|
||||||
SWITCHES,
|
|
||||||
)
|
|
||||||
from .coordinator import AndroidIPCamDataUpdateCoordinator
|
from .coordinator import AndroidIPCamDataUpdateCoordinator
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [
|
PLATFORMS: list[Platform] = [
|
||||||
@ -43,66 +26,7 @@ PLATFORMS: list[Platform] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
|
||||||
vol.All(
|
|
||||||
cv.deprecated(DOMAIN),
|
|
||||||
{
|
|
||||||
DOMAIN: vol.All(
|
|
||||||
cv.ensure_list,
|
|
||||||
[
|
|
||||||
vol.Schema(
|
|
||||||
{
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
vol.Required(CONF_HOST): cv.string,
|
|
||||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
|
||||||
vol.Optional(
|
|
||||||
CONF_TIMEOUT, default=DEFAULT_TIMEOUT
|
|
||||||
): cv.positive_int,
|
|
||||||
vol.Optional(
|
|
||||||
CONF_SCAN_INTERVAL, default=SCAN_INTERVAL
|
|
||||||
): cv.time_period,
|
|
||||||
vol.Inclusive(CONF_USERNAME, "authentication"): cv.string,
|
|
||||||
vol.Inclusive(CONF_PASSWORD, "authentication"): cv.string,
|
|
||||||
vol.Optional(CONF_SWITCHES): vol.All(
|
|
||||||
cv.ensure_list, [vol.In(SWITCHES)]
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_SENSORS): vol.All(
|
|
||||||
cv.ensure_list, [vol.In(SENSORS)]
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_MOTION_SENSOR): cv.boolean,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
extra=vol.ALLOW_EXTRA,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|
||||||
"""Set up the IP Webcam component."""
|
|
||||||
|
|
||||||
if DOMAIN not in config:
|
|
||||||
return True
|
|
||||||
|
|
||||||
async_create_issue(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
"deprecated_yaml",
|
|
||||||
breaks_in_ha_version="2022.11.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml",
|
|
||||||
)
|
|
||||||
for entry in config[DOMAIN]:
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=entry
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
@ -8,15 +8,7 @@ from pydroid_ipcam.exceptions import PyDroidIPCamException, Unauthorized
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import (
|
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
|
||||||
CONF_HOST,
|
|
||||||
CONF_NAME,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
CONF_PORT,
|
|
||||||
CONF_SCAN_INTERVAL,
|
|
||||||
CONF_TIMEOUT,
|
|
||||||
CONF_USERNAME,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
@ -75,19 +67,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
self._async_abort_entries_match(
|
self._async_abort_entries_match(
|
||||||
{CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]}
|
{CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]}
|
||||||
)
|
)
|
||||||
# to be removed when YAML import is removed
|
|
||||||
title = user_input.get(CONF_NAME) or user_input[CONF_HOST]
|
|
||||||
if not (errors := await validate_input(self.hass, user_input)):
|
if not (errors := await validate_input(self.hass, user_input)):
|
||||||
return self.async_create_entry(title=title, data=user_input)
|
return self.async_create_entry(title=user_input[CONF_HOST], data=user_input)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user",
|
step_id="user",
|
||||||
data_schema=STEP_USER_DATA_SCHEMA,
|
data_schema=STEP_USER_DATA_SCHEMA,
|
||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_import(self, import_config: dict[str, Any]) -> FlowResult:
|
|
||||||
"""Import a config entry from configuration.yaml."""
|
|
||||||
import_config.pop(CONF_SCAN_INTERVAL)
|
|
||||||
import_config.pop(CONF_TIMEOUT)
|
|
||||||
return await self.async_step_user(import_config)
|
|
||||||
|
@ -4,38 +4,6 @@ from datetime import timedelta
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
DOMAIN: Final = "android_ip_webcam"
|
DOMAIN: Final = "android_ip_webcam"
|
||||||
DEFAULT_NAME: Final = "IP Webcam"
|
|
||||||
DEFAULT_PORT: Final = 8080
|
DEFAULT_PORT: Final = 8080
|
||||||
DEFAULT_TIMEOUT: Final = 10
|
|
||||||
|
|
||||||
CONF_MOTION_SENSOR: Final = "motion_sensor"
|
|
||||||
|
|
||||||
MOTION_ACTIVE: Final = "motion_active"
|
MOTION_ACTIVE: Final = "motion_active"
|
||||||
SCAN_INTERVAL: Final = timedelta(seconds=10)
|
SCAN_INTERVAL: Final = timedelta(seconds=10)
|
||||||
|
|
||||||
|
|
||||||
SWITCHES = [
|
|
||||||
"exposure_lock",
|
|
||||||
"ffc",
|
|
||||||
"focus",
|
|
||||||
"gps_active",
|
|
||||||
"motion_detect",
|
|
||||||
"night_vision",
|
|
||||||
"overlay",
|
|
||||||
"torch",
|
|
||||||
"whitebalance_lock",
|
|
||||||
"video_recording",
|
|
||||||
]
|
|
||||||
|
|
||||||
SENSORS = [
|
|
||||||
"audio_connections",
|
|
||||||
"battery_level",
|
|
||||||
"battery_temp",
|
|
||||||
"battery_voltage",
|
|
||||||
"light",
|
|
||||||
"motion",
|
|
||||||
"pressure",
|
|
||||||
"proximity",
|
|
||||||
"sound",
|
|
||||||
"video_connections",
|
|
||||||
]
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\u05ea\u05e6\u05d5\u05e8\u05ea \u05d4\u05d4\u05ea\u05e7\u05df \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"cannot_connect": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4",
|
||||||
|
"invalid_auth": "\u05d0\u05d9\u05de\u05d5\u05ea \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"host": "\u05de\u05d0\u05e8\u05d7",
|
||||||
|
"password": "\u05e1\u05d9\u05e1\u05de\u05d4",
|
||||||
|
"port": "\u05e4\u05ea\u05d7\u05d4",
|
||||||
|
"username": "\u05e9\u05dd \u05de\u05e9\u05ea\u05de\u05e9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,8 +20,8 @@
|
|||||||
},
|
},
|
||||||
"issues": {
|
"issues": {
|
||||||
"deprecated_yaml": {
|
"deprecated_yaml": {
|
||||||
"description": "Proses konfigurasi Android IP Webcam lewat YAML dalam proses penghapusan.\n\nKonfigurasi YAML yang ada telah diimpor ke antarmuka secara otomatis.\n\nHapus konfigurasi YAML Android IP Webcam dari file configuration.yaml dan mulai ulang Home Assistant untuk memperbaiki masalah ini.",
|
"description": "Proses konfigurasi Integrasi Android IP Webcam lewat YAML dalam proses penghapusan.\n\nKonfigurasi YAML yang ada telah diimpor ke antarmuka secara otomatis.\n\nHapus konfigurasi YAML Integrasi Android IP Webcam dari file configuration.yaml dan mulai ulang Home Assistant untuk memperbaiki masalah ini.",
|
||||||
"title": "Konfigurasi YAML Android IP Webcam dalam proses penghapusan"
|
"title": "Konfigurasi YAML Integrasi Android IP Webcam dalam proses penghapusan"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/androidtv",
|
"documentation": "https://www.home-assistant.io/integrations/androidtv",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"adb-shell[async]==0.4.3",
|
"adb-shell[async]==0.4.3",
|
||||||
"androidtv[async]==0.0.67",
|
"androidtv[async]==0.0.69",
|
||||||
"pure-python-adb[async]==0.3.0.dev0"
|
"pure-python-adb[async]==0.3.0.dev0"
|
||||||
],
|
],
|
||||||
"codeowners": ["@JeffLIrion", "@ollo69"],
|
"codeowners": ["@JeffLIrion", "@ollo69"],
|
||||||
|
7
homeassistant/components/androidtv/translations/nb.json
Normal file
7
homeassistant/components/androidtv/translations/nb.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"unknown": "Uventet feil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -92,9 +92,3 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_import(
|
|
||||||
self, user_input: dict[str, Any] | None = None
|
|
||||||
) -> FlowResult:
|
|
||||||
"""Import a config entry from configuration.yaml."""
|
|
||||||
return await self.async_step_user(user_input)
|
|
||||||
|
@ -5,73 +5,24 @@ import logging
|
|||||||
|
|
||||||
from anthemav.connection import Connection
|
from anthemav.connection import Connection
|
||||||
from anthemav.protocol import AVR
|
from anthemav.protocol import AVR
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.media_player import (
|
from homeassistant.components.media_player import (
|
||||||
PLATFORM_SCHEMA,
|
|
||||||
MediaPlayerDeviceClass,
|
MediaPlayerDeviceClass,
|
||||||
MediaPlayerEntity,
|
MediaPlayerEntity,
|
||||||
MediaPlayerEntityFeature,
|
MediaPlayerEntityFeature,
|
||||||
MediaPlayerState,
|
MediaPlayerState,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_PORT
|
from homeassistant.const import CONF_MAC, CONF_NAME
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
||||||
|
|
||||||
from .const import (
|
from .const import ANTHEMAV_UDATE_SIGNAL, CONF_MODEL, DOMAIN, MANUFACTURER
|
||||||
ANTHEMAV_UDATE_SIGNAL,
|
|
||||||
CONF_MODEL,
|
|
||||||
DEFAULT_NAME,
|
|
||||||
DEFAULT_PORT,
|
|
||||||
DOMAIN,
|
|
||||||
MANUFACTURER,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_HOST): cv.string,
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
async_add_entities: AddEntitiesCallback,
|
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Set up our socket to the AVR."""
|
|
||||||
async_create_issue(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
"deprecated_yaml",
|
|
||||||
breaks_in_ha_version="2022.10.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml",
|
|
||||||
)
|
|
||||||
_LOGGER.warning(
|
|
||||||
"Configuration of the Anthem A/V Receivers integration in YAML is "
|
|
||||||
"deprecated and will be removed in Home Assistant 2022.10; Your "
|
|
||||||
"existing configuration has been imported into the UI automatically "
|
|
||||||
"and can be safely removed from your configuration.yaml file"
|
|
||||||
)
|
|
||||||
await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": SOURCE_IMPORT},
|
|
||||||
data=config,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -15,11 +15,5 @@
|
|||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"issues": {
|
|
||||||
"deprecated_yaml": {
|
|
||||||
"title": "The Anthem A/V Receivers YAML configuration is being removed",
|
|
||||||
"description": "Configuring Anthem A/V Receivers using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the Anthem A/V Receivers YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"issues": {
|
|
||||||
"deprecated_yaml": {
|
|
||||||
"description": "Configuring Anthem A/V Receivers using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the Anthem A/V Receivers YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue.",
|
|
||||||
"title": "The Anthem A/V Receivers YAML configuration is being removed"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user