This commit is contained in:
Franck Nijhof 2023-02-01 19:33:00 +01:00 committed by GitHub
commit 5fe3adff57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4221 changed files with 99908 additions and 27349 deletions

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ on:
env:
BUILD_TYPE: core
DEFAULT_PYTHON: 3.9
DEFAULT_PYTHON: "3.10"
jobs:
init:
@ -24,12 +24,12 @@ jobs:
publish: ${{ steps.version.outputs.publish }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
with:
fetch-depth: 0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -67,10 +67,10 @@ jobs:
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -100,7 +100,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Download nightly wheels of frontend
if: needs.init.outputs.channel == 'dev'
@ -113,9 +113,20 @@ jobs:
workflow_conclusion: success
name: wheels
- name: Download nightly wheels of intents
if: needs.init.outputs.channel == 'dev'
uses: dawidd6/action-download-artifact@v2
with:
github_token: ${{secrets.GITHUB_TOKEN}}
repo: home-assistant/intents
branch: main
workflow: nightly.yaml
workflow_conclusion: success
name: package
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
if: needs.init.outputs.channel == 'dev'
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -140,6 +151,24 @@ jobs:
python -m script.gen_requirements_all
fi
if [[ "$(ls home_assistant_intents*.whl)" =~ ^home_assistant_intents-(.*)-py3-none-any.whl$ ]]; then
echo "Found intents wheel, setting version to: ${BASH_REMATCH[1]}"
yq \
--inplace e -o json \
'del(.requirements[] | select(contains("home-assistant-intents")))' \
homeassistant/components/conversation/manifest.json
intents_version="${BASH_REMATCH[1]}" yq \
--inplace e -o json \
'.requirements += ["home-assistant-intents=="+env(intents_version)]' \
homeassistant/components/conversation/manifest.json
sed -i "s|home-assistant-intents==.*|home-assistant-intents==${BASH_REMATCH[1]}|" \
homeassistant/package_constraints.txt
python -m script.gen_requirements_all
fi
- name: Write meta info file
shell: bash
run: |
@ -198,7 +227,7 @@ jobs:
- yellow
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set build additional args
run: |
@ -241,7 +270,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Initialize git
uses: home-assistant/actions/helpers/git-init@master
@ -280,7 +309,7 @@ jobs:
- "homeassistant"
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Login to DockerHub
if: matrix.registry == 'homeassistant'

View File

@ -18,13 +18,21 @@ on:
description: "Skip pytest"
default: false
type: boolean
pylint-only:
description: "Only run pylint"
default: false
type: boolean
mypy-only:
description: "Only run mypy"
default: false
type: boolean
env:
CACHE_VERSION: 3
PIP_CACHE_VERSION: 3
HA_SHORT_VERSION: 2023.1
DEFAULT_PYTHON: 3.9
ALL_PYTHON_VERSIONS: "['3.9', '3.10']"
HA_SHORT_VERSION: 2023.2
DEFAULT_PYTHON: "3.10"
ALL_PYTHON_VERSIONS: "['3.10']"
PRE_COMMIT_CACHE: ~/.cache/pre-commit
PIP_CACHE: /tmp/pip-cache
SQLALCHEMY_WARN_20: 1
@ -56,7 +64,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Generate partial Python venv restore key
id: generate_python_cache_key
run: >-
@ -163,20 +171,23 @@ jobs:
pre-commit:
name: Prepare pre-commit base
runs-on: ubuntu-20.04
if: |
github.event.inputs.pylint-only != 'true'
&& github.event.inputs.mypy-only != 'true'
needs:
- info
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.2.2
uses: actions/cache@v3.2.3
with:
path: venv
key: >-
@ -191,7 +202,7 @@ jobs:
pip install "$(cat requirements_test.txt | grep pre-commit)"
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v3.2.2
uses: actions/cache@v3.2.3
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
@ -211,16 +222,16 @@ jobs:
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -233,7 +244,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
@ -265,16 +276,16 @@ jobs:
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -287,7 +298,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
@ -313,25 +324,24 @@ jobs:
. venv/bin/activate
shopt -s globstar
pre-commit run --hook-stage manual flake8 --files {homeassistant,tests}/components/${{ needs.info.outputs.integrations_glob }}/{*,**/*}
lint-isort:
name: Check isort
runs-on: ubuntu-20.04
lint-ruff:
name: Check ruff
runs-on: ubuntu-latest
needs:
- info
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -344,7 +354,63 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
needs.info.outputs.pre-commit_cache_key }}
- name: Fail job if pre-commit cache restore failed
if: steps.cache-precommit.outputs.cache-hit != 'true'
run: |
echo "Failed to restore pre-commit environment from cache"
exit 1
- name: Register ruff problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/ruff.json"
- name: Run ruff (fully)
if: needs.info.outputs.test_full_suite == 'true'
run: |
. venv/bin/activate
pre-commit run --hook-stage manual ruff --all-files
- name: Run ruff (partially)
if: needs.info.outputs.test_full_suite == 'false'
shell: bash
run: |
. venv/bin/activate
shopt -s globstar
pre-commit run --hook-stage manual ruff --files {homeassistant,tests}/components/${{ needs.info.outputs.integrations_glob }}/{*,**/*}
lint-isort:
name: Check isort
runs-on: ubuntu-20.04
needs:
- info
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.5.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{
needs.info.outputs.pre-commit_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: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v3.2.3
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
@ -368,16 +434,16 @@ jobs:
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -390,7 +456,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
@ -495,10 +561,10 @@ jobs:
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
@ -509,7 +575,7 @@ jobs:
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.2.2
uses: actions/cache@v3.2.3
with:
path: venv
key: >-
@ -517,7 +583,7 @@ jobs:
needs.info.outputs.python_cache_key }}
- name: Restore pip wheel cache
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache@v3.2.2
uses: actions/cache@v3.2.3
with:
path: ${{ env.PIP_CACHE }}
key: >-
@ -554,21 +620,24 @@ jobs:
hassfest:
name: Check hassfest
runs-on: ubuntu-20.04
if: |
github.event.inputs.pylint-only != 'true'
&& github.event.inputs.mypy-only != 'true'
needs:
- info
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -587,21 +656,24 @@ jobs:
gen-requirements-all:
name: Check all requirements
runs-on: ubuntu-20.04
if: |
github.event.inputs.pylint-only != 'true'
&& github.event.inputs.mypy-only != 'true'
needs:
- info
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -621,21 +693,24 @@ jobs:
name: Check pylint
runs-on: ubuntu-20.04
timeout-minutes: 20
if: |
github.event.inputs.mypy-only != 'true'
|| github.event.inputs.pylint-only == 'true'
needs:
- info
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -666,21 +741,24 @@ jobs:
mypy:
name: Check mypy
runs-on: ubuntu-20.04
if: |
github.event.inputs.pylint-only != 'true'
|| github.event.inputs.mypy-only == 'true'
needs:
- info
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -710,6 +788,9 @@ jobs:
pip-check:
runs-on: ubuntu-20.04
if: |
github.event.inputs.pylint-only != 'true'
&& github.event.inputs.mypy-only != 'true'
needs:
- info
- base
@ -720,16 +801,16 @@ jobs:
name: Run pip check ${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.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/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: >-
@ -750,6 +831,8 @@ jobs:
if: |
(github.event_name != 'push' || github.event.repository.full_name == 'home-assistant/core')
&& github.event.inputs.lint-only != 'true'
&& github.event.inputs.pylint-only != 'true'
&& github.event.inputs.mypy-only != 'true'
&& (needs.info.outputs.test_full_suite == 'true' || needs.info.outputs.tests_glob)
needs:
- info
@ -775,16 +858,16 @@ jobs:
bluez \
ffmpeg
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.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/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -852,7 +935,7 @@ jobs:
-p no:sugar \
tests/components/${{ matrix.group }}
- name: Upload coverage artifact
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v3.1.2
with:
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
path: coverage.xml
@ -873,6 +956,8 @@ jobs:
if: |
(github.event_name != 'push' || github.event.repository.full_name == 'home-assistant/core')
&& github.event.inputs.lint-only != 'true'
&& github.event.inputs.pylint-only != 'true'
&& github.event.inputs.mypy-only != 'true'
&& needs.info.outputs.test_full_suite == 'true'
needs:
- info
@ -898,16 +983,16 @@ jobs:
ffmpeg \
libmariadb-dev-compat
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.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/restore@v3.2.2
uses: actions/cache/restore@v3.2.3
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
@ -954,7 +1039,7 @@ jobs:
--dburl=mysql://root:password@127.0.0.1/homeassistant-test \
tests/components/recorder
- name: Upload coverage artifact
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v3.1.2
with:
name: coverage-${{ matrix.python-version }}-mariadb
path: coverage.xml
@ -970,7 +1055,7 @@ jobs:
- pytest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Download all coverage artifacts
uses: actions/download-artifact@v3
- name: Upload coverage to Codecov (full coverage)

30
.github/workflows/matchers/ruff.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
"problemMatcher": [
{
"owner": "ruff-error",
"severity": "error",
"pattern": [
{
"regexp": "^(.*):(\\d+):(\\d+):\\s([EF]\\d{3}\\s.*)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4
}
]
},
{
"owner": "ruff-warning",
"severity": "warning",
"pattern": [
{
"regexp": "^(.*):(\\d+):(\\d+):\\s([CDNW]\\d{3}\\s.*)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4
}
]
}
]
}

View File

@ -11,34 +11,21 @@ jobs:
if: github.repository_owner == 'home-assistant'
runs-on: ubuntu-latest
steps:
# The 90 day stale policy
# The 90 day stale policy for PRs
# Used for:
# - Issues & PRs
# - PRs
# - No PRs marked as no-stale
# - No issues marked as no-stale or help-wanted
- name: 90 days stale issues & PRs policy
# - No issues (-1)
- name: 90 days stale PRs policy
uses: actions/stale@v7.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90
days-before-close: 7
days-before-issue-stale: -1
days-before-issue-close: -1
operations-per-run: 150
remove-stale-when-updated: true
stale-issue-label: "stale"
exempt-issue-labels: "no-stale,help-wanted"
stale-issue-message: >
There hasn't been any activity on this issue recently. Due to the
high number of incoming GitHub notifications, we have to clean some
of the old issues, as many of them have already been resolved with
the latest updates.
Please make sure to update to the latest Home Assistant version and
check if that solves the issue. Let us know if that works for you by
adding a comment 👍
This issue has now been marked as stale and will be closed if no
further activity occurs. Thank you for your contributions.
stale-pr-label: "stale"
exempt-pr-labels: "no-stale"
stale-pr-message: >
@ -48,30 +35,47 @@ jobs:
Thank you for your contributions.
# The 30 day stale policy for PRS
# Generate a token for the GitHub App, we use this method to avoid
# hitting API limits for our GitHub actions + have a higher rate limit.
# This is only used for issues.
- name: Generate app token
id: token
# Pinned to a specific version of the action for security reasons
# v1.7.0
uses: tibdex/github-app-token@021a2405c7f990db57f5eae5397423dcc554159c
with:
app_id: ${{ secrets.ISSUE_TRIAGE_APP_ID }}
private_key: ${{ secrets.ISSUE_TRIAGE_APP_PEM }}
# The 90 day stale policy for issues
# Used for:
# - PRs
# - No PRs marked as no-stale or new-integrations
# - No issues (-1)
- name: 30 days stale PRs policy
# - Issues
# - No issues marked as no-stale or help-wanted
# - No PRs (-1)
- name: 90 days stale issues
uses: actions/stale@v7.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30
repo-token: ${{ steps.token.outputs.token }}
days-before-stale: 90
days-before-close: 7
days-before-issue-close: -1
operations-per-run: 50
days-before-pr-stale: -1
days-before-pr-close: -1
operations-per-run: 250
remove-stale-when-updated: true
stale-pr-label: "stale"
# Exempt new integrations, these often take more time.
# They will automatically be handled by the 90 day version above.
exempt-pr-labels: "no-stale,new-integration"
stale-pr-message: >
There hasn't been any activity on this pull request recently. This
pull request has been automatically marked as stale because of that
and will be closed if no further activity occurs within 7 days.
stale-issue-label: "stale"
exempt-issue-labels: "no-stale,help-wanted,needs-more-information"
stale-issue-message: >
There hasn't been any activity on this issue recently. Due to the
high number of incoming GitHub notifications, we have to clean some
of the old issues, as many of them have already been resolved with
the latest updates.
Thank you for your contributions.
Please make sure to update to the latest Home Assistant version and
check if that solves the issue. Let us know if that works for you by
adding a comment 👍
This issue has now been marked as stale and will be closed if no
further activity occurs. Thank you for your contributions.
# The 30 day stale policy for issues
# Used for:
@ -81,12 +85,13 @@ jobs:
- name: Needs more information stale issues policy
uses: actions/stale@v7.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token: ${{ steps.token.outputs.token }}
only-labels: "needs-more-information"
days-before-stale: 14
days-before-close: 7
days-before-pr-stale: -1
days-before-pr-close: -1
operations-per-run: 50
operations-per-run: 250
remove-stale-when-updated: true
stale-issue-label: "stale"
exempt-issue-labels: "no-stale,help-wanted"

View File

@ -12,7 +12,7 @@ on:
- "**strings.json"
env:
DEFAULT_PYTHON: 3.9
DEFAULT_PYTHON: "3.10"
jobs:
upload:
@ -21,10 +21,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@ -40,10 +40,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}

View File

@ -22,7 +22,7 @@ jobs:
architectures: ${{ steps.info.outputs.architectures }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Get information
id: info
@ -57,13 +57,13 @@ jobs:
) > .env_file
- name: Upload env_file
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v3.1.2
with:
name: env_file
path: ./.env_file
- name: Upload requirements_diff
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v3.1.2
with:
name: requirements_diff
path: ./requirements_diff.txt
@ -79,7 +79,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Download env_file
uses: actions/download-artifact@v3
@ -116,7 +116,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.3.0
- name: Download env_file
uses: actions/download-artifact@v3
@ -144,6 +144,14 @@ jobs:
sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file}
done
- name: Split requirements all
run: |
# We split requirements all into two different files.
# This is to prevent the build from running out of memory when
# resolving packages on 32-bits systems (like armhf, armv7).
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 2) requirements_all.txt requirements_all.txt
- name: Adjust build env
run: |
if [ "${{ matrix.arch }}" = "i386" ]; then
@ -159,7 +167,7 @@ jobs:
# Do not pin numpy in wheels building
sed -i "/numpy/d" homeassistant/package_constraints.txt
- name: Build wheels
- name: Build wheels (part 1)
uses: home-assistant/wheels@2022.10.1
with:
abi: cp310
@ -172,4 +180,19 @@ jobs:
legacy: true
constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txt"
requirements: "requirements_all.txtaa"
- name: Build wheels (part 2)
uses: home-assistant/wheels@2022.10.1
with:
abi: cp310
tag: musllinux_1_2
arch: ${{ matrix.arch }}
wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true
apk: "libexecinfo-dev;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev"
skip-binary: aiohttp;grpcio
legacy: true
constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtab"

View File

@ -1,9 +1,16 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.231
hooks:
- id: ruff
args:
- --fix
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args: [--py39-plus]
args: [--py310-plus]
stages: [manual]
- repo: https://github.com/PyCQA/autoflake
rev: v2.0.0
hooks:
@ -11,6 +18,7 @@ repos:
args:
- --in-place
- --remove-all-unused-imports
stages: [manual]
- repo: https://github.com/psf/black
rev: 22.12.0
hooks:
@ -36,11 +44,12 @@ repos:
- pycodestyle==2.10.0
- pyflakes==3.0.1
- flake8-docstrings==1.6.0
- pydocstyle==6.1.1
- pydocstyle==6.2.3
- flake8-comprehensions==3.10.1
- flake8-noqa==1.3.0
- mccabe==0.7.0
files: ^(homeassistant|script|tests)/.+\.py$
exclude: docs/source/conf.py
stages: [manual]
- repo: https://github.com/PyCQA/bandit
rev: 1.7.4
hooks:
@ -51,11 +60,11 @@ repos:
- --configfile=tests/bandit.yaml
files: ^(homeassistant|script|tests)/.+\.py$
- repo: https://github.com/PyCQA/isort
rev: 5.11.4
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
rev: v4.4.0
hooks:
- id: check-executables-have-shebangs
stages: [manual]
@ -84,7 +93,7 @@ repos:
- id: python-typing-update
stages: [manual]
args:
- --py39-plus
- --py310-plus
- --force
- --keep-updates
files: ^(homeassistant|tests|script)/.+\.py$

View File

@ -58,6 +58,7 @@ homeassistant.components.amcrest.*
homeassistant.components.ampio.*
homeassistant.components.analytics.*
homeassistant.components.anthemav.*
homeassistant.components.apcupsd.*
homeassistant.components.aqualogic.*
homeassistant.components.aseko_pool_live.*
homeassistant.components.asuswrt.*
@ -68,6 +69,7 @@ homeassistant.components.backup.*
homeassistant.components.baf.*
homeassistant.components.bayesian.*
homeassistant.components.binary_sensor.*
homeassistant.components.bitcoin.*
homeassistant.components.blockchain.*
homeassistant.components.bluetooth.*
homeassistant.components.bluetooth_tracker.*
@ -110,6 +112,7 @@ homeassistant.components.fastdotcom.*
homeassistant.components.feedreader.*
homeassistant.components.file_upload.*
homeassistant.components.filesize.*
homeassistant.components.filter.*
homeassistant.components.fitbit.*
homeassistant.components.flux_led.*
homeassistant.components.forecast_solar.*
@ -172,10 +175,12 @@ homeassistant.components.jewish_calendar.*
homeassistant.components.kaleidescape.*
homeassistant.components.knx.*
homeassistant.components.kraken.*
homeassistant.components.lacrosse.*
homeassistant.components.lacrosse_view.*
homeassistant.components.lametric.*
homeassistant.components.laundrify.*
homeassistant.components.lcn.*
homeassistant.components.ld2410_ble.*
homeassistant.components.lidarr.*
homeassistant.components.lifx.*
homeassistant.components.light.*
@ -198,6 +203,7 @@ homeassistant.components.mjpeg.*
homeassistant.components.modbus.*
homeassistant.components.modem_callerid.*
homeassistant.components.moon.*
homeassistant.components.mopeka.*
homeassistant.components.mqtt.*
homeassistant.components.mysensors.*
homeassistant.components.nam.*
@ -219,6 +225,7 @@ homeassistant.components.onewire.*
homeassistant.components.open_meteo.*
homeassistant.components.openexchangerates.*
homeassistant.components.openuv.*
homeassistant.components.otbr.*
homeassistant.components.overkiz.*
homeassistant.components.peco.*
homeassistant.components.persistent_notification.*
@ -245,17 +252,21 @@ homeassistant.components.ridwell.*
homeassistant.components.rituals_perfume_genie.*
homeassistant.components.roku.*
homeassistant.components.rpi_power.*
homeassistant.components.rss_feed_template.*
homeassistant.components.rtsp_to_webrtc.*
homeassistant.components.ruuvi_gateway.*
homeassistant.components.ruuvitag_ble.*
homeassistant.components.samsungtv.*
homeassistant.components.scene.*
homeassistant.components.schedule.*
homeassistant.components.scrape.*
homeassistant.components.select.*
homeassistant.components.senseme.*
homeassistant.components.sensibo.*
homeassistant.components.sensirion_ble.*
homeassistant.components.sensor.*
homeassistant.components.senz.*
homeassistant.components.sfr_box.*
homeassistant.components.shelly.*
homeassistant.components.simplepush.*
homeassistant.components.simplisafe.*

14
.vscode/tasks.json vendored
View File

@ -41,6 +41,20 @@
},
"problemMatcher": []
},
{
"label": "Ruff",
"type": "shell",
"command": "pre-commit run ruff --all-files",
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Pylint",
"type": "shell",

View File

@ -67,8 +67,6 @@ build.json @home-assistant/supervisor
/tests/components/alert/ @home-assistant/core @frenck
/homeassistant/components/alexa/ @home-assistant/cloud @ochlocracy @jbouwh
/tests/components/alexa/ @home-assistant/cloud @ochlocracy @jbouwh
/homeassistant/components/almond/ @gcampax @balloob
/tests/components/almond/ @gcampax @balloob
/homeassistant/components/amberelectric/ @madpilot
/tests/components/amberelectric/ @madpilot
/homeassistant/components/ambiclimate/ @danielhiversen
@ -156,6 +154,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/bluesound/ @thrawnarn
/homeassistant/components/bluetooth/ @bdraco
/tests/components/bluetooth/ @bdraco
/homeassistant/components/bluetooth_adapters/ @bdraco
/tests/components/bluetooth_adapters/ @bdraco
/homeassistant/components/bmw_connected_drive/ @gerard33 @rikroe
/tests/components/bmw_connected_drive/ @gerard33 @rikroe
/homeassistant/components/bond/ @bdraco @prystupa @joshs85 @marciogranzotto
@ -265,6 +265,8 @@ build.json @home-assistant/supervisor
/tests/components/discord/ @tkdrob
/homeassistant/components/discovery/ @home-assistant/core
/tests/components/discovery/ @home-assistant/core
/homeassistant/components/dlink/ @tkdrob
/tests/components/dlink/ @tkdrob
/homeassistant/components/dlna_dmr/ @StevenLooman @chishm
/tests/components/dlna_dmr/ @StevenLooman @chishm
/homeassistant/components/dlna_dms/ @chishm
@ -313,6 +315,8 @@ build.json @home-assistant/supervisor
/tests/components/emulated_kasa/ @kbickar
/homeassistant/components/energy/ @home-assistant/core
/tests/components/energy/ @home-assistant/core
/homeassistant/components/energyzero/ @klaasnicolaas
/tests/components/energyzero/ @klaasnicolaas
/homeassistant/components/enigma2/ @fbradyirl
/homeassistant/components/enocean/ @bdurrer
/tests/components/enocean/ @bdurrer
@ -331,6 +335,8 @@ build.json @home-assistant/supervisor
/tests/components/escea/ @lazdavila
/homeassistant/components/esphome/ @OttoWinter @jesserockz
/tests/components/esphome/ @OttoWinter @jesserockz
/homeassistant/components/eufylife_ble/ @bdr99
/tests/components/eufylife_ble/ @bdr99
/homeassistant/components/evil_genius_labs/ @balloob
/tests/components/evil_genius_labs/ @balloob
/homeassistant/components/evohome/ @zxdavb
@ -433,6 +439,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/google_assistant_sdk/ @tronikos
/tests/components/google_assistant_sdk/ @tronikos
/homeassistant/components/google_cloud/ @lufton
/homeassistant/components/google_mail/ @tkdrob
/tests/components/google_mail/ @tkdrob
/homeassistant/components/google_sheets/ @tkdrob
/tests/components/google_sheets/ @tkdrob
/homeassistant/components/google_travel_time/ @eifinger
@ -499,8 +507,8 @@ build.json @home-assistant/supervisor
/tests/components/homematic/ @pvizeli @danielperna84
/homeassistant/components/homewizard/ @DCSBL
/tests/components/homewizard/ @DCSBL
/homeassistant/components/honeywell/ @rdfurman
/tests/components/honeywell/ @rdfurman
/homeassistant/components/honeywell/ @rdfurman @mkmer
/tests/components/honeywell/ @rdfurman @mkmer
/homeassistant/components/http/ @home-assistant/core
/tests/components/http/ @home-assistant/core
/homeassistant/components/huawei_lte/ @scop @fphammerle
@ -533,6 +541,8 @@ build.json @home-assistant/supervisor
/tests/components/image_processing/ @home-assistant/core
/homeassistant/components/image_upload/ @home-assistant/core
/tests/components/image_upload/ @home-assistant/core
/homeassistant/components/imap/ @engrbm87
/tests/components/imap/ @engrbm87
/homeassistant/components/incomfort/ @zxdavb
/homeassistant/components/influxdb/ @mdegat01
/tests/components/influxdb/ @mdegat01
@ -599,6 +609,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/keyboard_remote/ @bendavid @lanrat
/homeassistant/components/keymitt_ble/ @spycle
/tests/components/keymitt_ble/ @spycle
/homeassistant/components/kitchen_sink/ @home-assistant/core
/tests/components/kitchen_sink/ @home-assistant/core
/homeassistant/components/kmtronic/ @dgomes
/tests/components/kmtronic/ @dgomes
/homeassistant/components/knx/ @Julius2342 @farmio @marvin-w
@ -625,6 +637,8 @@ build.json @home-assistant/supervisor
/tests/components/laundrify/ @xLarry
/homeassistant/components/lcn/ @alengwenus
/tests/components/lcn/ @alengwenus
/homeassistant/components/ld2410_ble/ @930913
/tests/components/ld2410_ble/ @930913
/homeassistant/components/led_ble/ @bdraco
/tests/components/led_ble/ @bdraco
/homeassistant/components/lg_netcast/ @Drafteed
@ -669,7 +683,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/lyric/ @timmo001
/tests/components/lyric/ @timmo001
/homeassistant/components/mastodon/ @fabaff
/homeassistant/components/matrix/ @tinloaf
/homeassistant/components/matter/ @home-assistant/matter
/tests/components/matter/ @home-assistant/matter
/homeassistant/components/mazda/ @bdr99
@ -725,6 +738,8 @@ build.json @home-assistant/supervisor
/tests/components/monoprice/ @etsinko @OnFreund
/homeassistant/components/moon/ @fabaff @frenck
/tests/components/moon/ @fabaff @frenck
/homeassistant/components/mopeka/ @bdraco
/tests/components/mopeka/ @bdraco
/homeassistant/components/motion_blinds/ @starkillerOG
/tests/components/motion_blinds/ @starkillerOG
/homeassistant/components/motioneye/ @dermotduffy
@ -825,6 +840,8 @@ build.json @home-assistant/supervisor
/tests/components/onvif/ @hunterjm
/homeassistant/components/open_meteo/ @frenck
/tests/components/open_meteo/ @frenck
/homeassistant/components/openai_conversation/ @balloob
/tests/components/openai_conversation/ @balloob
/homeassistant/components/openerz/ @misialq
/tests/components/openerz/ @misialq
/homeassistant/components/openexchangerates/ @MartinHjelmare
@ -840,9 +857,11 @@ build.json @home-assistant/supervisor
/tests/components/openweathermap/ @fabaff @freekode @nzapponi
/homeassistant/components/opnsense/ @mtreinish
/tests/components/opnsense/ @mtreinish
/homeassistant/components/oralb/ @bdraco
/tests/components/oralb/ @bdraco
/homeassistant/components/oralb/ @bdraco @Lash-L
/tests/components/oralb/ @bdraco @Lash-L
/homeassistant/components/oru/ @bvlaicu
/homeassistant/components/otbr/ @home-assistant/core
/tests/components/otbr/ @home-assistant/core
/homeassistant/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev
/tests/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev
/homeassistant/components/ovo_energy/ @timmo001
@ -877,8 +896,8 @@ build.json @home-assistant/supervisor
/tests/components/point/ @fredrike
/homeassistant/components/poolsense/ @haemishkyd
/tests/components/poolsense/ @haemishkyd
/homeassistant/components/powerwall/ @bdraco @jrester
/tests/components/powerwall/ @bdraco @jrester
/homeassistant/components/powerwall/ @bdraco @jrester @daniel-simpson
/tests/components/powerwall/ @bdraco @jrester @daniel-simpson
/homeassistant/components/profiler/ @bdraco
/tests/components/profiler/ @bdraco
/homeassistant/components/progettihwsw/ @ardaseremet
@ -980,8 +999,12 @@ build.json @home-assistant/supervisor
/tests/components/rtsp_to_webrtc/ @allenporter
/homeassistant/components/ruckus_unleashed/ @gabe565
/tests/components/ruckus_unleashed/ @gabe565
/homeassistant/components/ruuvi_gateway/ @akx
/tests/components/ruuvi_gateway/ @akx
/homeassistant/components/ruuvitag_ble/ @akx
/tests/components/ruuvitag_ble/ @akx
/homeassistant/components/rympro/ @OnFreund
/tests/components/rympro/ @OnFreund
/homeassistant/components/sabnzbd/ @shaiu
/tests/components/sabnzbd/ @shaiu
/homeassistant/components/safe_mode/ @home-assistant/core
@ -1026,6 +1049,8 @@ build.json @home-assistant/supervisor
/tests/components/senz/ @milanmeu
/homeassistant/components/serial/ @fabaff
/homeassistant/components/seven_segments/ @fabaff
/homeassistant/components/sfr_box/ @epenet
/tests/components/sfr_box/ @epenet
/homeassistant/components/sharkiq/ @JeffResc @funkybunch @AritroSaha10
/tests/components/sharkiq/ @JeffResc @funkybunch @AritroSaha10
/homeassistant/components/shell_command/ @home-assistant/core
@ -1107,6 +1132,8 @@ build.json @home-assistant/supervisor
/tests/components/srp_energy/ @briglx
/homeassistant/components/starline/ @anonym-tsk
/tests/components/starline/ @anonym-tsk
/homeassistant/components/starlink/ @boswelja
/tests/components/starlink/ @boswelja
/homeassistant/components/statistics/ @fabaff @ThomDietrich
/tests/components/statistics/ @fabaff @ThomDietrich
/homeassistant/components/steam_online/ @tkdrob
@ -1116,6 +1143,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/stiebel_eltron/ @fucm
/homeassistant/components/stookalert/ @fwestenberg @frenck
/tests/components/stookalert/ @fwestenberg @frenck
/homeassistant/components/stookwijzer/ @fwestenberg
/tests/components/stookwijzer/ @fwestenberg
/homeassistant/components/stream/ @hunterjm @uvjustin @allenporter
/tests/components/stream/ @hunterjm @uvjustin @allenporter
/homeassistant/components/stt/ @pvizeli
@ -1177,6 +1206,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/thermopro/ @bdraco
/tests/components/thermopro/ @bdraco
/homeassistant/components/thethingsnetwork/ @fabaff
/homeassistant/components/thread/ @home-assistant/core
/tests/components/thread/ @home-assistant/core
/homeassistant/components/threshold/ @fabaff
/tests/components/threshold/ @fabaff
/homeassistant/components/tibber/ @danielhiversen
@ -1299,8 +1330,8 @@ build.json @home-assistant/supervisor
/tests/components/websocket_api/ @home-assistant/core
/homeassistant/components/wemo/ @esev
/tests/components/wemo/ @esev
/homeassistant/components/whirlpool/ @abmantis
/tests/components/whirlpool/ @abmantis
/homeassistant/components/whirlpool/ @abmantis @mkmer
/tests/components/whirlpool/ @abmantis @mkmer
/homeassistant/components/whois/ @frenck
/tests/components/whois/ @frenck
/homeassistant/components/wiffi/ @mampfes
@ -1356,6 +1387,8 @@ build.json @home-assistant/supervisor
/tests/components/zeroconf/ @bdraco
/homeassistant/components/zerproc/ @emlove
/tests/components/zerproc/ @emlove
/homeassistant/components/zeversolar/ @kvanzuijlen
/tests/components/zeversolar/ @kvanzuijlen
/homeassistant/components/zha/ @dmulcahey @adminiuga @puddly
/tests/components/zha/ @dmulcahey @adminiuga @puddly
/homeassistant/components/zodiac/ @JulienTant
@ -1365,8 +1398,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/zoneminder/ @rohankapoorcom
/homeassistant/components/zwave_js/ @home-assistant/z-wave
/tests/components/zwave_js/ @home-assistant/z-wave
/homeassistant/components/zwave_me/ @lawfulchaos @Z-Wave-Me
/tests/components/zwave_me/ @lawfulchaos @Z-Wave-Me
/homeassistant/components/zwave_me/ @lawfulchaos @Z-Wave-Me @PoltoS
/tests/components/zwave_me/ @lawfulchaos @Z-Wave-Me @PoltoS
# Individual files
/homeassistant/components/demo/weather.py @fabaff

View File

@ -5,6 +5,8 @@ FROM ${BUILD_FROM}
ENV \
S6_SERVICES_GRACETIME=220000
ARG QEMU_CPU
WORKDIR /usr/src
## Setup Home Assistant Core dependencies
@ -19,7 +21,7 @@ RUN \
--use-deprecated=legacy-resolver \
-r homeassistant/requirements.txt
COPY requirements_all.txt home_assistant_frontend-* homeassistant/
COPY requirements_all.txt home_assistant_frontend-* home_assistant_intents-* homeassistant/
RUN \
if ls homeassistant/home_assistant_frontend*.whl 1> /dev/null 2>&1; then \
pip3 install \
@ -27,6 +29,12 @@ RUN \
--no-index \
homeassistant/home_assistant_frontend-*.whl; \
fi \
&& if ls homeassistant/home_assistant_intents*.whl 1> /dev/null 2>&1; then \
pip3 install \
--no-cache-dir \
--no-index \
homeassistant/home_assistant_intents-*.whl; \
fi \
&& \
LD_PRELOAD="/usr/local/lib/libjemalloc.so.2" \
MALLOC_CONF="background_thread:true,metadata_thp:auto,dirty_decay_ms:20000,muzzy_decay_ms:20000" \

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.9
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.10
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

View File

@ -6,19 +6,37 @@ coverage:
default:
target: 90
threshold: 0.09
config-flows:
required:
target: auto
threshold: 1
paths:
- homeassistant/components/*/config_flow.py
- homeassistant/components/*/device_action.py
- homeassistant/components/*/device_condition.py
- homeassistant/components/*/device_trigger.py
- homeassistant/components/*/diagnostics.py
- homeassistant/components/*/group.py
- homeassistant/components/*/intent.py
- homeassistant/components/*/logbook.py
- homeassistant/components/*/media_source.py
- homeassistant/components/*/scene.py
patch:
default:
target: auto
config-flows:
required:
target: 100
threshold: 0
paths:
- homeassistant/components/*/config_flow.py
- homeassistant/components/*/device_action.py
- homeassistant/components/*/device_condition.py
- homeassistant/components/*/device_trigger.py
- homeassistant/components/*/diagnostics.py
- homeassistant/components/*/group.py
- homeassistant/components/*/intent.py
- homeassistant/components/*/logbook.py
- homeassistant/components/*/media_source.py
- homeassistant/components/*/scene.py
comment: false
# To make partial tests possible,

View File

@ -1,6 +1,5 @@
"""
Sphinx extension to add ReadTheDocs-style "Edit on GitHub" links to the
sidebar.
Sphinx extension for ReadTheDocs-style "Edit on GitHub" links on the sidebar.
Loosely based on https://github.com/astropy/astropy/pull/347
"""
@ -12,6 +11,7 @@ __licence__ = "BSD (3 clause)"
def get_github_url(app, view, path):
"""Build the GitHub URL."""
return (
f"https://github.com/{app.config.edit_on_github_project}/"
f"{view}/{app.config.edit_on_github_branch}/"
@ -20,6 +20,7 @@ def get_github_url(app, view, path):
def html_page_context(app, pagename, templatename, context, doctree):
"""Build the HTML page."""
if templatename != "page.html":
return
@ -38,6 +39,7 @@ def html_page_context(app, pagename, templatename, context, doctree):
def setup(app):
"""Set up the app."""
app.add_config_value("edit_on_github_project", "", True)
app.add_config_value("edit_on_github_branch", "master", True)
app.add_config_value("edit_on_github_src_path", "", True) # 'eg' "docs/"

View File

@ -1,21 +1,20 @@
#!/usr/bin/env python3
#
# Home-Assistant documentation build configuration file, created by
# sphinx-quickstart on Sun Aug 28 13:13:10 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
"""Home Assistant documentation build configuration file.
This file is execfile()d with the current directory set to its
containing dir.
Note that not all possible configuration values are present in this
autogenerated file.
All configuration values have a default; values that are commented out
serve to show the default.
If extensions (or modules to document with autodoc) are in another directory,
add these directories to sys.path here. If the directory is relative to the
documentation root, use os.path.abspath to make it absolute, like shown here.
"""
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import inspect
import os
import sys
@ -25,7 +24,7 @@ from homeassistant.const import __short_version__, __version__
PROJECT_NAME = "Home Assistant"
PROJECT_PACKAGE_NAME = "homeassistant"
PROJECT_AUTHOR = "The Home Assistant Authors"
PROJECT_COPYRIGHT = f" 2013-2020, {PROJECT_AUTHOR}"
PROJECT_COPYRIGHT = PROJECT_AUTHOR
PROJECT_LONG_DESCRIPTION = (
"Home Assistant is an open-source "
"home automation platform running on Python 3. "
@ -110,17 +109,17 @@ def linkcode_resolve(domain, info):
for part in fullname.split("."):
try:
obj = getattr(obj, part)
except:
except Exception: # pylint: disable=broad-except
return None
try:
fn = inspect.getsourcefile(obj)
except:
except Exception: # pylint: disable=broad-except
fn = None
if not fn:
return None
try:
source, lineno = inspect.findsource(obj)
except:
except Exception: # pylint: disable=broad-except
lineno = None
if lineno:
linespec = "#L%d" % (lineno + 1)

View File

@ -15,7 +15,10 @@ FAULT_LOG_FILENAME = "home-assistant.log.fault"
def validate_os() -> None:
"""Validate that Home Assistant is running in a supported operating system."""
if not sys.platform.startswith(("darwin", "linux")):
print("Home Assistant only supports Linux, OSX and Windows using WSL")
print(
"Home Assistant only supports Linux, OSX and Windows using WSL",
file=sys.stderr,
)
sys.exit(1)
@ -24,14 +27,15 @@ def validate_python() -> None:
if sys.version_info[:3] < REQUIRED_PYTHON_VER:
print(
"Home Assistant requires at least Python "
f"{REQUIRED_PYTHON_VER[0]}.{REQUIRED_PYTHON_VER[1]}.{REQUIRED_PYTHON_VER[2]}"
f"{REQUIRED_PYTHON_VER[0]}.{REQUIRED_PYTHON_VER[1]}.{REQUIRED_PYTHON_VER[2]}",
file=sys.stderr,
)
sys.exit(1)
def ensure_config_path(config_dir: str) -> None:
"""Validate the configuration directory."""
# pylint: disable=import-outside-toplevel
# pylint: disable-next=import-outside-toplevel
from . import config as config_util
lib_dir = os.path.join(config_dir, "deps")
@ -39,18 +43,23 @@ def ensure_config_path(config_dir: str) -> None:
# Test if configuration directory exists
if not os.path.isdir(config_dir):
if config_dir != config_util.get_default_config_dir():
if os.path.exists(config_dir):
reason = "is not a directory"
else:
reason = "does not exist"
print(
f"Fatal Error: Specified configuration directory {config_dir} "
"does not exist"
f"Fatal Error: Specified configuration directory {config_dir} {reason}",
file=sys.stderr,
)
sys.exit(1)
try:
os.mkdir(config_dir)
except OSError:
except OSError as ex:
print(
"Fatal Error: Unable to create default configuration "
f"directory {config_dir}"
f"directory {config_dir}: {ex}",
file=sys.stderr,
)
sys.exit(1)
@ -58,14 +67,17 @@ def ensure_config_path(config_dir: str) -> None:
if not os.path.isdir(lib_dir):
try:
os.mkdir(lib_dir)
except OSError:
print(f"Fatal Error: Unable to create library directory {lib_dir}")
except OSError as ex:
print(
f"Fatal Error: Unable to create library directory {lib_dir}: {ex}",
file=sys.stderr,
)
sys.exit(1)
def get_arguments() -> argparse.Namespace:
"""Get parsed passed in arguments."""
# pylint: disable=import-outside-toplevel
# pylint: disable-next=import-outside-toplevel
from . import config as config_util
parser = argparse.ArgumentParser(
@ -172,7 +184,7 @@ def main() -> int:
validate_os()
if args.script is not None:
# pylint: disable=import-outside-toplevel
# pylint: disable-next=import-outside-toplevel
from . import scripts
return scripts.run(args.script)
@ -180,7 +192,7 @@ def main() -> int:
config_dir = os.path.abspath(os.path.join(os.getcwd(), args.config))
ensure_config_path(config_dir)
# pylint: disable=import-outside-toplevel
# pylint: disable-next=import-outside-toplevel
from . import runner
runtime_conf = runner.RuntimeConfig(

View File

@ -5,7 +5,7 @@ import asyncio
from collections import OrderedDict
from collections.abc import Mapping
from datetime import timedelta
from typing import Any, Optional, cast
from typing import Any, cast
import jwt
@ -24,7 +24,7 @@ EVENT_USER_UPDATED = "user_updated"
EVENT_USER_REMOVED = "user_removed"
_MfaModuleDict = dict[str, MultiFactorAuthModule]
_ProviderKey = tuple[str, Optional[str]]
_ProviderKey = tuple[str, str | None]
_ProviderDict = dict[_ProviderKey, AuthProvider]

View File

@ -555,7 +555,9 @@ class AuthStore:
"client_icon": refresh_token.client_icon,
"token_type": refresh_token.token_type,
"created_at": refresh_token.created_at.isoformat(),
"access_token_expiration": refresh_token.access_token_expiration.total_seconds(),
"access_token_expiration": (
refresh_token.access_token_expiration.total_seconds()
),
"token": refresh_token.token,
"jwt_key": refresh_token.jwt_key,
"last_used_at": refresh_token.last_used_at.isoformat()

View File

@ -1,29 +1,28 @@
"""Common code for permissions."""
from collections.abc import Mapping
from typing import Union
# MyPy doesn't support recursion yet. So writing it out as far as we need.
ValueType = Union[
ValueType = (
# Example: entities.all = { read: true, control: true }
Mapping[str, bool],
bool,
None,
]
Mapping[str, bool]
| bool
| None
)
# Example: entities.domains = { light: … }
SubCategoryDict = Mapping[str, ValueType]
SubCategoryType = Union[SubCategoryDict, bool, None]
SubCategoryType = SubCategoryDict | bool | None
CategoryType = Union[
CategoryType = (
# Example: entities.domains
Mapping[str, SubCategoryType],
Mapping[str, SubCategoryType]
# Example: entities.all
Mapping[str, ValueType],
bool,
None,
]
| Mapping[str, ValueType]
| bool
| None
)
# Example: { entities: … }
PolicyType = Mapping[str, CategoryType]

View File

@ -3,13 +3,13 @@ from __future__ import annotations
from collections.abc import Callable
from functools import wraps
from typing import Optional, cast
from typing import cast
from .const import SUBCAT_ALL
from .models import PermissionLookup
from .types import CategoryType, SubCategoryDict, ValueType
LookupFunc = Callable[[PermissionLookup, SubCategoryDict, str], Optional[ValueType]]
LookupFunc = Callable[[PermissionLookup, SubCategoryDict, str], ValueType | None]
SubCatLookupType = dict[str, LookupFunc]

View File

@ -14,7 +14,7 @@ from ipaddress import (
ip_address,
ip_network,
)
from typing import Any, Union, cast
from typing import Any, cast
import voluptuous as vol
@ -27,8 +27,8 @@ from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
from .. import InvalidAuthError
from ..models import Credentials, RefreshToken, UserMeta
IPAddress = Union[IPv4Address, IPv6Address]
IPNetwork = Union[IPv4Network, IPv6Network]
IPAddress = IPv4Address | IPv6Address
IPNetwork = IPv4Network | IPv6Network
CONF_TRUSTED_NETWORKS = "trusted_networks"
CONF_TRUSTED_USERS = "trusted_users"

View File

@ -8,7 +8,9 @@ from .util.async_ import protect_loop
def enable() -> None:
"""Enable the detection of blocking calls in the event loop."""
# Prevent urllib3 and requests doing I/O in event loop
HTTPConnection.putrequest = protect_loop(HTTPConnection.putrequest) # type: ignore[assignment]
HTTPConnection.putrequest = protect_loop( # type: ignore[assignment]
HTTPConnection.putrequest
)
# Prevent sleeping in event loop. Non-strict since 2022.02
time.sleep = protect_loop(time.sleep, strict=False)

View File

@ -346,7 +346,7 @@ def async_enable_logging(
if not log_no_color:
try:
# pylint: disable=import-outside-toplevel
# pylint: disable-next=import-outside-toplevel
from colorlog import ColoredFormatter
# basicConfig must be called after importing colorlog in order to
@ -385,7 +385,11 @@ def async_enable_logging(
)
threading.excepthook = lambda args: logging.getLogger(None).exception(
"Uncaught thread exception",
exc_info=(args.exc_type, args.exc_value, args.exc_traceback), # type: ignore[arg-type]
exc_info=( # type: ignore[arg-type]
args.exc_type,
args.exc_value,
args.exc_traceback,
),
)
# Log errors to a file if we have write access to file or config dir
@ -403,7 +407,10 @@ def async_enable_logging(
not err_path_exists and os.access(err_dir, os.W_OK)
):
err_handler: logging.handlers.RotatingFileHandler | logging.handlers.TimedRotatingFileHandler
err_handler: (
logging.handlers.RotatingFileHandler
| logging.handlers.TimedRotatingFileHandler
)
if log_rotate_days:
err_handler = logging.handlers.TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days
@ -462,7 +469,10 @@ def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
async def _async_watch_pending_setups(hass: core.HomeAssistant) -> None:
"""Periodic log of setups that are pending for longer than LOG_SLOW_STARTUP_INTERVAL."""
"""Periodic log of setups that are pending.
Pending for longer than LOG_SLOW_STARTUP_INTERVAL.
"""
loop_count = 0
setup_started: dict[str, datetime] = hass.data[DATA_SETUP_STARTED]
previous_was_empty = True

View File

@ -1,5 +1,5 @@
{
"domain": "amazon",
"name": "Amazon",
"integrations": ["alexa", "amazon_polly", "aws", "route53"]
"integrations": ["alexa", "amazon_polly", "aws", "fire_tv", "route53"]
}

View File

@ -0,0 +1,6 @@
{
"domain": "eufy",
"name": "eufy",
"integrations": ["eufy", "eufylife_ble"],
"iot_standards": []
}

View File

@ -6,6 +6,7 @@
"google_assistant_sdk",
"google_cloud",
"google_domains",
"google_mail",
"google_maps",
"google_pubsub",
"google_sheets",

View File

@ -3,10 +3,14 @@ from __future__ import annotations
from functools import partial
from abodepy import Abode, AbodeAutomation as AbodeAuto
from abodepy.devices import AbodeDevice as AbodeDev
from abodepy.exceptions import AbodeAuthenticationException, AbodeException
import abodepy.helpers.timeline as TIMELINE
from jaraco.abode.automation import Automation as AbodeAuto
from jaraco.abode.client import Client as Abode
from jaraco.abode.devices.base import Device as AbodeDev
from jaraco.abode.exceptions import (
AuthenticationException as AbodeAuthenticationException,
Exception as AbodeException,
)
from jaraco.abode.helpers.timeline import Groups as GROUPS
from requests.exceptions import ConnectTimeout, HTTPError
import voluptuous as vol
@ -26,7 +30,7 @@ from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv, entity
from homeassistant.helpers.dispatcher import dispatcher_send
from .const import ATTRIBUTION, CONF_POLLING, DEFAULT_CACHEDB, DOMAIN, LOGGER
from .const import ATTRIBUTION, CONF_POLLING, DOMAIN, LOGGER
SERVICE_SETTINGS = "change_setting"
SERVICE_CAPTURE_IMAGE = "capture_image"
@ -82,7 +86,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
username = entry.data[CONF_USERNAME]
password = entry.data[CONF_PASSWORD]
polling = entry.data[CONF_POLLING]
cache = hass.config.path(DEFAULT_CACHEDB)
# For previous config entries where unique_id is None
if entry.unique_id is None:
@ -92,7 +95,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
try:
abode = await hass.async_add_executor_job(
Abode, username, password, True, True, True, cache
Abode, username, password, True, True, True
)
except AbodeAuthenticationException as ex:
@ -225,17 +228,17 @@ def setup_abode_events(hass: HomeAssistant) -> None:
hass.bus.fire(event, data)
events = [
TIMELINE.ALARM_GROUP,
TIMELINE.ALARM_END_GROUP,
TIMELINE.PANEL_FAULT_GROUP,
TIMELINE.PANEL_RESTORE_GROUP,
TIMELINE.AUTOMATION_GROUP,
TIMELINE.DISARM_GROUP,
TIMELINE.ARM_GROUP,
TIMELINE.ARM_FAULT_GROUP,
TIMELINE.TEST_GROUP,
TIMELINE.CAPTURE_GROUP,
TIMELINE.DEVICE_GROUP,
GROUPS.ALARM,
GROUPS.ALARM_END,
GROUPS.PANEL_FAULT,
GROUPS.PANEL_RESTORE,
GROUPS.AUTOMATION,
GROUPS.DISARM,
GROUPS.ARM,
GROUPS.ARM_FAULT,
GROUPS.TEST,
GROUPS.CAPTURE,
GROUPS.DEVICE,
]
for event in events:

View File

@ -1,7 +1,7 @@
"""Support for Abode Security System alarm control panels."""
from __future__ import annotations
from abodepy.devices.alarm import AbodeAlarm as AbodeAl
from jaraco.abode.devices.alarm import Alarm as AbodeAl
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature

View File

@ -4,8 +4,8 @@ from __future__ import annotations
from contextlib import suppress
from typing import cast
from abodepy.devices.binary_sensor import AbodeBinarySensor as ABBinarySensor
import abodepy.helpers.constants as CONST
from jaraco.abode.devices.sensor import BinarySensor as ABBinarySensor
from jaraco.abode.helpers import constants as CONST
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,

View File

@ -4,9 +4,9 @@ from __future__ import annotations
from datetime import timedelta
from typing import Any, cast
from abodepy.devices import CONST, AbodeDevice as AbodeDev
from abodepy.devices.camera import AbodeCamera as AbodeCam
import abodepy.helpers.timeline as TIMELINE
from jaraco.abode.devices.base import Device as AbodeDev
from jaraco.abode.devices.camera import Camera as AbodeCam
from jaraco.abode.helpers import constants as CONST, timeline as TIMELINE
import requests
from requests.models import Response
@ -30,7 +30,7 @@ async def async_setup_entry(
data: AbodeSystem = hass.data[DOMAIN]
async_add_entities(
AbodeCamera(data, device, TIMELINE.CAPTURE_IMAGE)
AbodeCamera(data, device, TIMELINE.CAPTURE_IMAGE) # pylint: disable=no-member
for device in data.abode.get_devices(generic_type=CONST.TYPE_CAMERA)
)

View File

@ -5,9 +5,12 @@ from collections.abc import Mapping
from http import HTTPStatus
from typing import Any, cast
from abodepy import Abode
from abodepy.exceptions import AbodeAuthenticationException, AbodeException
from abodepy.helpers.errors import MFA_CODE_REQUIRED
from jaraco.abode.client import Client as Abode
from jaraco.abode.exceptions import (
AuthenticationException as AbodeAuthenticationException,
Exception as AbodeException,
)
from jaraco.abode.helpers.errors import MFA_CODE_REQUIRED
from requests.exceptions import ConnectTimeout, HTTPError
import voluptuous as vol
@ -15,7 +18,7 @@ from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.data_entry_flow import FlowResult
from .const import CONF_POLLING, DEFAULT_CACHEDB, DOMAIN, LOGGER
from .const import CONF_POLLING, DOMAIN, LOGGER
CONF_MFA = "mfa_code"
@ -35,7 +38,6 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
vol.Required(CONF_MFA): str,
}
self._cache: str | None = None
self._mfa_code: str | None = None
self._password: str | None = None
self._polling: bool = False
@ -43,12 +45,11 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def _async_abode_login(self, step_id: str) -> FlowResult:
"""Handle login with Abode."""
self._cache = self.hass.config.path(DEFAULT_CACHEDB)
errors = {}
try:
await self.hass.async_add_executor_job(
Abode, self._username, self._password, True, False, False, self._cache
Abode, self._username, self._password, True, False, False
)
except AbodeException as ex:
@ -77,12 +78,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle multi-factor authentication (MFA) login with Abode."""
try:
# Create instance to access login method for passing MFA code
abode = Abode(
auto_login=False,
get_devices=False,
get_automations=False,
cache_path=self._cache,
)
abode = Abode(auto_login=False, get_devices=False, get_automations=False)
await self.hass.async_add_executor_job(
abode.login, self._username, self._password, self._mfa_code
)

View File

@ -6,5 +6,4 @@ LOGGER = logging.getLogger(__package__)
DOMAIN = "abode"
ATTRIBUTION = "Data provided by goabode.com"
DEFAULT_CACHEDB = "abodepy_cache.pickle"
CONF_POLLING = "polling"

View File

@ -1,8 +1,8 @@
"""Support for Abode Security System covers."""
from typing import Any
from abodepy.devices.cover import AbodeCover as AbodeCV
import abodepy.helpers.constants as CONST
from jaraco.abode.devices.cover import Cover as AbodeCV
from jaraco.abode.helpers import constants as CONST
from homeassistant.components.cover import CoverEntity
from homeassistant.config_entries import ConfigEntry

View File

@ -4,8 +4,8 @@ from __future__ import annotations
from math import ceil
from typing import Any
from abodepy.devices.light import AbodeLight as AbodeLT
import abodepy.helpers.constants as CONST
from jaraco.abode.devices.light import Light as AbodeLT
from jaraco.abode.helpers import constants as CONST
from homeassistant.components.light import (
ATTR_BRIGHTNESS,

View File

@ -1,8 +1,8 @@
"""Support for the Abode Security System locks."""
from typing import Any
from abodepy.devices.lock import AbodeLock as AbodeLK
import abodepy.helpers.constants as CONST
from jaraco.abode.devices.lock import Lock as AbodeLK
from jaraco.abode.helpers import constants as CONST
from homeassistant.components.lock import LockEntity
from homeassistant.config_entries import ConfigEntry

View File

@ -3,11 +3,11 @@
"name": "Abode",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/abode",
"requirements": ["abodepy==1.2.0"],
"requirements": ["jaraco.abode==3.2.1"],
"codeowners": ["@shred86"],
"homekit": {
"models": ["Abode", "Iota"]
},
"iot_class": "cloud_push",
"loggers": ["abodepy", "lomond"]
"loggers": ["jaraco.abode", "lomond"]
}

View File

@ -3,7 +3,8 @@ from __future__ import annotations
from typing import cast
from abodepy.devices.sensor import CONST, AbodeSensor as AbodeSense
from jaraco.abode.devices.sensor import Sensor as AbodeSense
from jaraco.abode.helpers import constants as CONST
from homeassistant.components.sensor import (
SensorDeviceClass,

View File

@ -3,7 +3,8 @@ from __future__ import annotations
from typing import Any, cast
from abodepy.devices.switch import CONST, AbodeSwitch as AbodeSW
from jaraco.abode.devices.switch import Switch as AbodeSW
from jaraco.abode.helpers import constants as CONST
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry

View File

@ -0,0 +1,12 @@
{
"config": {
"step": {
"user": {
"data": {
"password": "Slapta\u017eodis",
"username": "El. pa\u0161tas"
}
}
}
}
}

View File

@ -1,6 +1,8 @@
"""Diagnostics support for AccuWeather."""
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
@ -14,7 +16,7 @@ TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict:
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator: AccuWeatherDataUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id

View File

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

View File

@ -17,10 +17,10 @@ from homeassistant.const import (
PERCENTAGE,
UV_INDEX,
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfSpeed,
UnitOfTemperature,
UnitOfTime,
UnitOfVolumetricFlux,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -290,11 +290,11 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
),
AccuWeatherSensorDescription(
key="Precipitation",
device_class=SensorDeviceClass.PRECIPITATION,
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
name="Precipitation",
state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfPrecipitationDepth.MILLIMETERS,
us_customary_unit=UnitOfPrecipitationDepth.INCHES,
metric_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_customary_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
attr_fn=lambda data: {"type": data["PrecipitationType"]},
),
@ -452,7 +452,7 @@ def _get_sensor_data(
return sensors[ATTR_FORECAST][forecast_day][kind]
if kind == "Precipitation":
return sensors["PrecipitationSummary"][kind]
return sensors["PrecipitationSummary"]["PastHour"]
return sensors[kind]

View File

@ -22,6 +22,27 @@
}
}
},
"entity": {
"sensor": {
"pressure_tendency": {
"state": {
"falling": "D\u00fc\u015f\u00fcyor",
"rising": "Y\u00fckseliyor",
"steady": "Sabit"
}
}
}
},
"options": {
"step": {
"init": {
"data": {
"forecast": "Hava Durumu tahmini"
},
"description": "AccuWeather API anahtar\u0131n\u0131n \u00fccretsiz s\u00fcr\u00fcm\u00fcn\u00fcn s\u0131n\u0131rlamalar\u0131 nedeniyle, hava tahminini etkinle\u015ftirdi\u011finizde, veri g\u00fcncellemeleri her 40 dakikada bir yerine 80 dakikada bir ger\u00e7ekle\u015ftirilir."
}
}
},
"system_health": {
"info": {
"can_reach_server": "AccuWeather sunucusuna ula\u015f\u0131n",

View File

@ -1,5 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
},
"step": {
"cloud": {
"data": {

View File

@ -0,0 +1,15 @@
{
"config": {
"abort": {
"invalid_auth": "\u041d\u0435\u0434\u0456\u0439\u0441\u043d\u0430 \u0430\u0432\u0442\u0435\u043d\u0442\u0438\u0444\u0456\u043a\u0430\u0446\u0456\u044f"
},
"step": {
"cloud": {
"data": {
"account_id": "ID \u041e\u0431\u043b\u0456\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0438\u0441\u0443",
"password": "\u041f\u0430\u0440\u043e\u043b\u044c"
}
}
}
}
}

View File

@ -58,7 +58,12 @@ class AdGuardHomeEntity(Entity):
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={
(DOMAIN, self.adguard.host, self.adguard.port, self.adguard.base_path) # type: ignore[arg-type]
( # type: ignore[arg-type]
DOMAIN,
self.adguard.host,
self.adguard.port,
self.adguard.base_path,
)
},
manufacturer="AdGuard Team",
name="AdGuard Home",

View File

@ -0,0 +1,11 @@
{
"config": {
"step": {
"user": {
"data": {
"password": "Slapta\u017eodis"
}
}
}
}
}

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
}
}
}

View File

@ -14,7 +14,7 @@
"longitude": "\u0393\u03b5\u03c9\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03cc \u03bc\u03ae\u03ba\u03bf\u03c2",
"name": "\u038c\u03bd\u03bf\u03bc\u03b1 \u03c4\u03b7\u03c2 \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7\u03c2"
},
"description": "\u03a1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 AEMET OpenData. \u0393\u03b9\u03b1 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API \u03bc\u03b5\u03c4\u03b1\u03b2\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 https://opendata.aemet.es/centrodedescargas/altaUsuario"
"description": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API, \u03bc\u03b5\u03c4\u03b1\u03b2\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 https://opendata.aemet.es/centrodedescargas/altaUsuario"
}
}
},

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
}
}
}

View File

@ -150,7 +150,9 @@ class AirlyDataUpdateCoordinator(DataUpdateCoordinator):
"""Initialize."""
self.latitude = latitude
self.longitude = longitude
self.airly = Airly(api_key, session)
# Currently, Airly only supports Polish and English
language = "pl" if hass.config.language == "pl" else "en"
self.airly = Airly(api_key, session, language=language)
self.use_nearest = use_nearest
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)

View File

@ -46,7 +46,7 @@ class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
user_input["longitude"],
)
if not location_point_valid:
await test_location(
location_nearest_valid = await test_location(
websession,
user_input["api_key"],
user_input["latitude"],
@ -60,6 +60,8 @@ class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
errors["base"] = "wrong_location"
else:
if not location_point_valid:
if not location_nearest_valid:
return self.async_abort(reason="wrong_location")
use_nearest = True
return self.async_create_entry(
title=user_input[CONF_NAME],

View File

@ -1,6 +1,8 @@
"""Diagnostics support for Airly."""
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 (
@ -19,7 +21,7 @@ TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_UNIQUE_ID}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict:
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator: AirlyDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]

View File

@ -16,7 +16,8 @@
"invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]"
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]",
"wrong_location": "No Airly measuring stations in this area."
}
},
"system_health": {

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada"
"already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada",
"wrong_location": "No hi ha estacions de mesura Airly en aquesta zona."
},
"error": {
"invalid_api_key": "Clau API inv\u00e0lida",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Standort ist bereits konfiguriert"
"already_configured": "Standort ist bereits konfiguriert",
"wrong_location": "Keine Airly Luftmessstation an diesem Ort"
},
"error": {
"invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "\u0397 \u03c4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c3\u03af\u03b1 \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af"
"already_configured": "\u0397 \u03c4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c3\u03af\u03b1 \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af",
"wrong_location": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03c3\u03c4\u03b1\u03b8\u03bc\u03bf\u03af \u03bc\u03ad\u03c4\u03c1\u03b7\u03c3\u03b7\u03c2 Airly \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7\u03bd \u03c0\u03b5\u03c1\u03b9\u03bf\u03c7\u03ae."
},
"error": {
"invalid_api_key": "\u0386\u03ba\u03c5\u03c1\u03bf API \u03ba\u03bb\u03b5\u03b9\u03b4\u03af",
@ -15,7 +16,7 @@
"longitude": "\u0393\u03b5\u03c9\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03cc \u03bc\u03ae\u03ba\u03bf\u03c2",
"name": "\u038c\u03bd\u03bf\u03bc\u03b1"
},
"description": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7 \u03c0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2 \u03b1\u03ad\u03c1\u03b1 Airly. \u0393\u03b9\u03b1 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API, \u03bc\u03b5\u03c4\u03b1\u03b2\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 https://developer.airly.eu/register"
"description": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API, \u03bc\u03b5\u03c4\u03b1\u03b2\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 https://developer.airly.eu/register"
}
}
},

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Location is already configured"
"already_configured": "Location is already configured",
"wrong_location": "No Airly measuring stations in this area."
},
"error": {
"invalid_api_key": "Invalid API key",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "La ubicaci\u00f3n ya est\u00e1 configurada"
"already_configured": "La ubicaci\u00f3n ya est\u00e1 configurada",
"wrong_location": "No hay estaciones de medici\u00f3n Airly en esta \u00e1rea."
},
"error": {
"invalid_api_key": "Clave API no v\u00e1lida",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Asukoht on juba m\u00e4\u00e4ratud"
"already_configured": "Asukoht on juba m\u00e4\u00e4ratud",
"wrong_location": "Selles piirkonnas pole Airly m\u00f5\u00f5tejaamu."
},
"error": {
"invalid_api_key": "Vigane API v\u00f5ti",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "A hely m\u00e1r konfigur\u00e1lva van"
"already_configured": "A hely m\u00e1r konfigur\u00e1lva van",
"wrong_location": "Ezen a ter\u00fcleten nincs Airly m\u00e9r\u0151\u00e1llom\u00e1s."
},
"error": {
"invalid_api_key": "\u00c9rv\u00e9nytelen API kulcs",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Lokasi sudah dikonfigurasi"
"already_configured": "Lokasi sudah dikonfigurasi",
"wrong_location": "Tidak ada stasiun pengukur Airly di daerah ini."
},
"error": {
"invalid_api_key": "Kunci API tidak valid",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "La posizione \u00e8 gi\u00e0 configurata"
"already_configured": "La posizione \u00e8 gi\u00e0 configurata",
"wrong_location": "Nessuna stazione di misurazione Airly in quest'area."
},
"error": {
"invalid_api_key": "Chiave API non valida",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Locatie is al geconfigureerd"
"already_configured": "Locatie is al geconfigureerd",
"wrong_location": "Geen Airly meetstations in deze ruimte."
},
"error": {
"invalid_api_key": "Ongeldige API-sleutel",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Plasseringen er allerede konfigurert"
"already_configured": "Plasseringen er allerede konfigurert",
"wrong_location": "Ingen Airly m\u00e5lestasjoner i dette omr\u00e5det."
},
"error": {
"invalid_api_key": "Ugyldig API-n\u00f8kkel",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Lokalizacja jest ju\u017c skonfigurowana"
"already_configured": "Lokalizacja jest ju\u017c skonfigurowana",
"wrong_location": "Brak stacji pomiarowych Airly w tym rejonie"
},
"error": {
"invalid_api_key": "Nieprawid\u0142owy klucz API",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Localiza\u00e7\u00e3o j\u00e1 est\u00e1 configurada"
"already_configured": "Localiza\u00e7\u00e3o j\u00e1 est\u00e1 configurada",
"wrong_location": "Nenhuma esta\u00e7\u00e3o de medi\u00e7\u00e3o Airly nesta \u00e1rea."
},
"error": {
"invalid_api_key": "Chave de API inv\u00e1lida",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430."
"already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.",
"wrong_location": "\u0412 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043d\u0435\u0442 \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0430\u043d\u0446\u0438\u0439 Airly."
},
"error": {
"invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Umiestnenie u\u017e je nakonfigurovan\u00e9"
"already_configured": "Umiestnenie u\u017e je nakonfigurovan\u00e9",
"wrong_location": "V tejto oblasti nie s\u00fa \u017eiadne meracie stanice Airly."
},
"error": {
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "Konum zaten yap\u0131land\u0131r\u0131lm\u0131\u015f"
"already_configured": "Konum zaten yap\u0131land\u0131r\u0131lm\u0131\u015f",
"wrong_location": "Bu b\u00f6lgede Airly \u00f6l\u00e7\u00fcm istasyonu yok."
},
"error": {
"invalid_api_key": "Ge\u00e7ersiz API anahtar\u0131",

View File

@ -1,7 +1,8 @@
{
"config": {
"abort": {
"already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210"
"already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210",
"wrong_location": "\u8a72\u5340\u57df\u6c92\u6709 Arily \u76e3\u6e2c\u7ad9\u3002"
},
"error": {
"invalid_api_key": "API \u91d1\u9470\u7121\u6548",

View File

@ -17,7 +17,7 @@
"longitude": "\u0393\u03b5\u03c9\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03cc \u03bc\u03ae\u03ba\u03bf\u03c2",
"radius": "\u0391\u03ba\u03c4\u03af\u03bd\u03b1 \u03c3\u03c4\u03b1\u03b8\u03bc\u03bf\u03cd (\u03bc\u03af\u03bb\u03b9\u03b1, \u03c0\u03c1\u03bf\u03b1\u03b9\u03c1\u03b5\u03c4\u03b9\u03ba\u03cc)"
},
"description": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5 AirNow \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03c0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1 \u03c4\u03bf\u03c5 \u03b1\u03ad\u03c1\u03b1. \u0393\u03b9\u03b1 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API \u03bc\u03b5\u03c4\u03b1\u03b2\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 https://docs.airnowapi.org/account/request/"
"description": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API, \u03bc\u03b5\u03c4\u03b1\u03b2\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 https://docs.airnowapi.org/account/request/"
}
}
}

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
}
}
}

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
}
}
}

View File

@ -0,0 +1,12 @@
{
"config": {
"step": {
"user": {
"data": {
"ip_address": "IP-adress",
"password": "L\u00f6senord"
}
}
}
}
}

View File

@ -0,0 +1,22 @@
{
"config": {
"abort": {
"already_configured": "Cihaz zaten yap\u0131land\u0131r\u0131lm\u0131\u015f"
},
"error": {
"cannot_connect": "Ba\u011flanma hatas\u0131",
"invalid_auth": "Ge\u00e7ersiz kimlik do\u011frulama",
"invalid_input": "Ge\u00e7ersiz ana bilgisayar ad\u0131 veya IP adresi"
},
"step": {
"user": {
"data": {
"ip_address": "IP Adresi",
"password": "Parola"
},
"description": "Cihaz\u0131n IP adresini veya mDNS'sini ve \u015fifresini sa\u011flay\u0131n",
"title": "Cihaz\u0131 tan\u0131mlay\u0131n"
}
}
}
}

View File

@ -0,0 +1,11 @@
{
"config": {
"step": {
"user": {
"data": {
"password": "\u041f\u0430\u0440\u043e\u043b\u044c"
}
}
}
}
}

View File

@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airthings_ble",
"requirements": ["airthings-ble==0.5.3"],
"dependencies": ["bluetooth"],
"dependencies": ["bluetooth_adapters"],
"codeowners": ["@vincegio"],
"iot_class": "local_polling",
"bluetooth": [

View File

@ -154,7 +154,7 @@ class AirthingsSensor(
def __init__(
self,
coordinator: DataUpdateCoordinator,
coordinator: DataUpdateCoordinator[AirthingsDevice],
airthings_device: AirthingsDevice,
entity_description: SensorEntityDescription,
) -> None:

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"unknown": "Neo\u010dek\u00e1van\u00e1 chyba"
}
}
}

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
}
}
}

View File

@ -10,13 +10,13 @@
"flow_title": "{name}",
"step": {
"bluetooth_confirm": {
"description": "{name} kurulumunu yapmak istiyor musunuz?"
"description": "{name} 'i kurmak istiyor musunuz?"
},
"user": {
"data": {
"address": "Cihaz"
},
"description": "Kurulum i\u00e7in bir cihaz se\u00e7in"
"description": "Kurmak i\u00e7in bir cihaz se\u00e7in"
}
}
}

View File

@ -12,7 +12,7 @@
"data": {
"host": "\u039a\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03cc\u03c2 \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ae\u03c2"
},
"title": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b5 \u03c4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 {intergration}."
"title": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b5 \u03c4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2 AirTouch 4."
}
}
}

View File

@ -0,0 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
}
}
}

View File

@ -61,7 +61,6 @@ DOMAIN_AIRVISUAL_PRO = "airvisual_pro"
PLATFORMS = [Platform.SENSOR]
DEFAULT_ATTRIBUTION = "Data provided by AirVisual"
DEFAULT_NODE_PRO_UPDATE_INTERVAL = timedelta(minutes=1)
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
@ -267,8 +266,12 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": source},
data={CONF_API_KEY: entry.data[CONF_API_KEY], **geography},
context={"source": SOURCE_IMPORT},
data={
"import_source": source,
CONF_API_KEY: entry.data[CONF_API_KEY],
**geography,
},
)
)

View File

@ -132,15 +132,14 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
LOGGER.error(err)
errors["base"] = "unknown"
if errors:
return self.async_show_form(
step_id=error_step, data_schema=error_schema, errors=errors
)
valid_keys.add(user_input[CONF_API_KEY])
if errors:
return self.async_show_form(
step_id=error_step, data_schema=error_schema, errors=errors
)
existing_entry = await self.async_set_unique_id(self._geo_id)
if existing_entry:
if existing_entry := await self.async_set_unique_id(self._geo_id):
self.hass.config_entries.async_update_entry(existing_entry, data=user_input)
self.hass.async_create_task(
self.hass.config_entries.async_reload(existing_entry.entry_id)
@ -172,6 +171,13 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Define the config flow to handle options."""
return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
async def async_step_import(self, import_data: dict[str, str]) -> FlowResult:
"""Handle import of config entry version 1 data."""
import_source = import_data.pop("import_source")
if import_source == "geography_by_coords":
return await self.async_step_geography_by_coords(import_data)
return await self.async_step_geography_by_name(import_data)
async def async_step_geography_by_coords(
self, user_input: dict[str, str] | None = None
) -> FlowResult:

View File

@ -19,11 +19,8 @@ from homeassistant.const import (
CONF_LONGITUDE,
CONF_SHOW_ON_MAP,
CONF_STATE,
PERCENTAGE,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
@ -37,17 +34,8 @@ ATTR_POLLUTANT_UNIT = "pollutant_unit"
ATTR_REGION = "region"
SENSOR_KIND_AQI = "air_quality_index"
SENSOR_KIND_BATTERY_LEVEL = "battery_level"
SENSOR_KIND_CO2 = "carbon_dioxide"
SENSOR_KIND_HUMIDITY = "humidity"
SENSOR_KIND_LEVEL = "air_pollution_level"
SENSOR_KIND_PM_0_1 = "particulate_matter_0_1"
SENSOR_KIND_PM_1_0 = "particulate_matter_1_0"
SENSOR_KIND_PM_2_5 = "particulate_matter_2_5"
SENSOR_KIND_POLLUTANT = "main_pollutant"
SENSOR_KIND_SENSOR_LIFE = "sensor_life"
SENSOR_KIND_TEMPERATURE = "temperature"
SENSOR_KIND_VOC = "voc"
GEOGRAPHY_SENSOR_DESCRIPTIONS = (
SensorEntityDescription(
@ -82,70 +70,6 @@ GEOGRAPHY_SENSOR_DESCRIPTIONS = (
)
GEOGRAPHY_SENSOR_LOCALES = {"cn": "Chinese", "us": "U.S."}
NODE_PRO_SENSOR_DESCRIPTIONS = (
SensorEntityDescription(
key=SENSOR_KIND_AQI,
name="Air quality index",
device_class=SensorDeviceClass.AQI,
native_unit_of_measurement="AQI",
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_BATTERY_LEVEL,
name="Battery",
device_class=SensorDeviceClass.BATTERY,
entity_category=EntityCategory.DIAGNOSTIC,
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=SENSOR_KIND_CO2,
name="C02",
device_class=SensorDeviceClass.CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_HUMIDITY,
name="Humidity",
device_class=SensorDeviceClass.HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=SENSOR_KIND_PM_0_1,
name="PM 0.1",
device_class=SensorDeviceClass.PM1,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_PM_1_0,
name="PM 1.0",
device_class=SensorDeviceClass.PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_PM_2_5,
name="PM 2.5",
device_class=SensorDeviceClass.PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_TEMPERATURE,
name="Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_VOC,
name="VOC",
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=SensorStateClass.MEASUREMENT,
),
)
STATE_POLLUTANT_LABEL_CO = "co"
STATE_POLLUTANT_LABEL_N2 = "n2"

View File

@ -22,12 +22,6 @@
"country": "\u0421\u0442\u0440\u0430\u043d\u0430"
}
},
"node_pro": {
"data": {
"ip_address": "\u0425\u043e\u0441\u0442",
"password": "\u041f\u0430\u0440\u043e\u043b\u0430"
}
},
"reauth_confirm": {
"data": {
"api_key": "API \u043a\u043b\u044e\u0447"

View File

@ -30,14 +30,6 @@
"description": "Utilitza l'API d'AirVisual per monitoritzar un/a ciutat/estat/pa\u00eds",
"title": "Configura una ubicaci\u00f3 geogr\u00e0fica"
},
"node_pro": {
"data": {
"ip_address": "Amfitri\u00f3",
"password": "Contrasenya"
},
"description": "Monitoritza una unitat personal d'AirVisual. Pots obtenir la contrasenya des de la interf\u00edcie d'usuari (UI) de la unitat.",
"title": "Configuraci\u00f3 d'AirVisual Node/Pro"
},
"reauth_confirm": {
"data": {
"api_key": "Clau API"

View File

@ -24,13 +24,6 @@
"country": "Zem\u011b"
}
},
"node_pro": {
"data": {
"ip_address": "Hostitel",
"password": "Heslo"
},
"title": "Nastaven\u00ed AirVisual Node/Pro"
},
"reauth_confirm": {
"data": {
"api_key": "Kl\u00ed\u010d API"

View File

@ -30,14 +30,6 @@
"description": "Verwende die AirVisual Cloud API, um ein(e) Stadt/Bundesland/Land zu \u00fcberwachen.",
"title": "Konfiguriere einen Standort"
},
"node_pro": {
"data": {
"ip_address": "Host",
"password": "Passwort"
},
"description": "\u00dcberwache eine pers\u00f6nliche AirVisual-Einheit. Das Passwort kann von der Benutzeroberfl\u00e4che des Ger\u00e4ts abgerufen werden.",
"title": "Konfiguriere einen AirVisual Node/Pro"
},
"reauth_confirm": {
"data": {
"api_key": "API-Schl\u00fcssel"

View File

@ -1,7 +1,7 @@
{
"config": {
"abort": {
"already_configured": "\u0397 \u03c4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c3\u03af\u03b1 \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af \u03ae \u03c4\u03bf Node/Pro ID \u03b5\u03af\u03bd\u03b1\u03b9 \u03ae\u03b4\u03b7 \u03ba\u03b1\u03c4\u03b1\u03c7\u03c9\u03c1\u03b7\u03bc\u03ad\u03bd\u03bf.",
"already_configured": "\u0397 \u03c4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c3\u03af\u03b1 \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af",
"reauth_successful": "\u039f \u03b5\u03ba \u03bd\u03ad\u03bf\u03c5 \u03ad\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 \u03c4\u03b1\u03c5\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2 \u03ae\u03c4\u03b1\u03bd \u03b5\u03c0\u03b9\u03c4\u03c5\u03c7\u03ae\u03c2"
},
"error": {
@ -30,14 +30,6 @@
"description": "\u03a7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03bf AirVisual cloud API \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b5\u03af\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03c0\u03cc\u03bb\u03b7/\u03c0\u03bf\u03bb\u03b9\u03c4\u03b5\u03af\u03b1/\u03c7\u03ce\u03c1\u03b1.",
"title": "\u0394\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03b3\u03b5\u03c9\u03b3\u03c1\u03b1\u03c6\u03af\u03b1\u03c2"
},
"node_pro": {
"data": {
"ip_address": "\u039a\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03cc\u03c2 \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ae\u03c2",
"password": "\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2"
},
"description": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03ae\u03c3\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03c0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ae \u03bc\u03bf\u03bd\u03ac\u03b4\u03b1 AirVisual. \u039f \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2 \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b1\u03bd\u03b1\u03ba\u03c4\u03b7\u03b8\u03b5\u03af \u03b1\u03c0\u03cc \u03c4\u03bf UI \u03c4\u03b7\u03c2 \u03bc\u03bf\u03bd\u03ac\u03b4\u03b1\u03c2.",
"title": "\u0394\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03b5\u03bd\u03cc\u03c2 \u03ba\u03cc\u03bc\u03b2\u03bf\u03c5 AirVisual Node/Pro"
},
"reauth_confirm": {
"data": {
"api_key": "\u039a\u03bb\u03b5\u03b9\u03b4\u03af API"

View File

@ -30,14 +30,6 @@
"description": "Use the AirVisual cloud API to monitor a city/state/country.",
"title": "Configure a Geography"
},
"node_pro": {
"data": {
"ip_address": "Host",
"password": "Password"
},
"description": "Monitor a personal AirVisual unit. The password can be retrieved from the unit's UI.",
"title": "Configure an AirVisual Node/Pro"
},
"reauth_confirm": {
"data": {
"api_key": "API Key"

View File

@ -22,14 +22,6 @@
"description": "Utilice la API en la nube de AirVisual para monitorear una ciudad/estado/pa\u00eds.",
"title": "Configurar una geograf\u00eda"
},
"node_pro": {
"data": {
"ip_address": "Direcci\u00f3n IP/nombre de host de la unidad",
"password": "Contrase\u00f1a de la unidad"
},
"description": "Monitoree una unidad AirVisual personal. La contrase\u00f1a se puede recuperar de la interfaz de usuario de la unidad.",
"title": "Configurar un AirVisual Node/Pro"
},
"reauth_confirm": {
"title": "Vuelva a autenticar AirVisual"
},

View File

@ -30,14 +30,6 @@
"description": "Usar la API de la nube de AirVisual para supervisar una ciudad/estado/pa\u00eds.",
"title": "Configurar una geograf\u00eda"
},
"node_pro": {
"data": {
"ip_address": "Host",
"password": "Contrase\u00f1a"
},
"description": "Supervisar una unidad AirVisual personal. La contrase\u00f1a se puede recuperar desde la IU de la unidad.",
"title": "Configurar un AirVisual Node/Pro"
},
"reauth_confirm": {
"data": {
"api_key": "Clave API"

View File

@ -30,14 +30,6 @@
"description": "Kasuta AirVisual pilve API-t linna/osariigi/riigi j\u00e4lgimiseks.",
"title": "Seadista Geography sidumine"
},
"node_pro": {
"data": {
"ip_address": "\u00dcksuse IP-aadress / hostinimi",
"password": "Salas\u00f5na"
},
"description": "J\u00e4lgige isiklikku AirVisual-seadet. Parooli saab hankida seadme kasutajaliidese kaudu.",
"title": "Seadistage AirVisual Node / Pro"
},
"reauth_confirm": {
"data": {
"api_key": "API v\u00f5ti"

View File

@ -2,13 +2,6 @@
"config": {
"error": {
"general_error": "Tapahtui tuntematon virhe."
},
"step": {
"node_pro": {
"data": {
"password": "Salasana"
}
}
}
}
}

View File

@ -30,14 +30,6 @@
"description": "Utilisez l'API cloud AirVisual pour surveiller une ville / un \u00e9tat / un pays.",
"title": "Configurer un lieu g\u00e9ographique"
},
"node_pro": {
"data": {
"ip_address": "H\u00f4te",
"password": "Mot de passe"
},
"description": "Surveillez une unit\u00e9 personnelle AirVisual. Le mot de passe peut \u00eatre r\u00e9cup\u00e9r\u00e9 dans l'interface utilisateur de l'unit\u00e9.",
"title": "Configurer un noeud AirVisual Pro"
},
"reauth_confirm": {
"data": {
"api_key": "Cl\u00e9 d'API"

View File

@ -22,13 +22,6 @@
"api_key": "\u05de\u05e4\u05ea\u05d7 API"
}
},
"node_pro": {
"data": {
"ip_address": "\u05de\u05d0\u05e8\u05d7",
"password": "\u05e1\u05d9\u05e1\u05de\u05d4"
},
"description": "\u05e2\u05e7\u05d5\u05d1 \u05d0\u05d7\u05e8 \u05d9\u05d7\u05d9\u05d3\u05ea AirVisual \u05d0\u05d9\u05e9\u05d9\u05ea. \u05e0\u05d9\u05ea\u05df \u05dc\u05d0\u05d7\u05d6\u05e8 \u05d0\u05ea \u05d4\u05e1\u05d9\u05e1\u05de\u05d4 \u05de\u05de\u05e9\u05e7 \u05d4\u05de\u05e9\u05ea\u05de\u05e9 \u05e9\u05dc \u05d4\u05d9\u05d7\u05d9\u05d3\u05d4."
},
"reauth_confirm": {
"data": {
"api_key": "\u05de\u05e4\u05ea\u05d7 API"

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