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: env:
BUILD_TYPE: core BUILD_TYPE: core
DEFAULT_PYTHON: 3.9 DEFAULT_PYTHON: "3.10"
jobs: jobs:
init: init:
@ -24,12 +24,12 @@ jobs:
publish: ${{ steps.version.outputs.publish }} publish: ${{ steps.version.outputs.publish }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Python ${{ env.DEFAULT_PYTHON }} - name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0 uses: actions/setup-python@v4.5.0
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
@ -67,10 +67,10 @@ jobs:
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true' if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }} - name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v4.4.0 uses: actions/setup-python@v4.5.0
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
@ -100,7 +100,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }} arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Download nightly wheels of frontend - name: Download nightly wheels of frontend
if: needs.init.outputs.channel == 'dev' if: needs.init.outputs.channel == 'dev'
@ -113,9 +113,20 @@ jobs:
workflow_conclusion: success workflow_conclusion: success
name: wheels 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 }} - name: Set up Python ${{ env.DEFAULT_PYTHON }}
if: needs.init.outputs.channel == 'dev' if: needs.init.outputs.channel == 'dev'
uses: actions/setup-python@v4.4.0 uses: actions/setup-python@v4.5.0
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
@ -140,6 +151,24 @@ jobs:
python -m script.gen_requirements_all python -m script.gen_requirements_all
fi 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 - name: Write meta info file
shell: bash shell: bash
run: | run: |
@ -198,7 +227,7 @@ jobs:
- yellow - yellow
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Set build additional args - name: Set build additional args
run: | run: |
@ -241,7 +270,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Initialize git - name: Initialize git
uses: home-assistant/actions/helpers/git-init@master uses: home-assistant/actions/helpers/git-init@master
@ -280,7 +309,7 @@ jobs:
- "homeassistant" - "homeassistant"
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Login to DockerHub - name: Login to DockerHub
if: matrix.registry == 'homeassistant' if: matrix.registry == 'homeassistant'

View File

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

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' if: github.repository_owner == 'home-assistant'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# The 90 day stale policy # The 90 day stale policy for PRs
# Used for: # Used for:
# - Issues & PRs # - PRs
# - No PRs marked as no-stale # - No PRs marked as no-stale
# - No issues marked as no-stale or help-wanted # - No issues (-1)
- name: 90 days stale issues & PRs policy - name: 90 days stale PRs policy
uses: actions/stale@v7.0.0 uses: actions/stale@v7.0.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90 days-before-stale: 90
days-before-close: 7 days-before-close: 7
days-before-issue-stale: -1
days-before-issue-close: -1
operations-per-run: 150 operations-per-run: 150
remove-stale-when-updated: true 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" stale-pr-label: "stale"
exempt-pr-labels: "no-stale" exempt-pr-labels: "no-stale"
stale-pr-message: > stale-pr-message: >
@ -48,30 +35,47 @@ jobs:
Thank you for your contributions. 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: # Used for:
# - PRs # - Issues
# - No PRs marked as no-stale or new-integrations # - No issues marked as no-stale or help-wanted
# - No issues (-1) # - No PRs (-1)
- name: 30 days stale PRs policy - name: 90 days stale issues
uses: actions/stale@v7.0.0 uses: actions/stale@v7.0.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ steps.token.outputs.token }}
days-before-stale: 30 days-before-stale: 90
days-before-close: 7 days-before-close: 7
days-before-issue-close: -1 days-before-pr-stale: -1
operations-per-run: 50 days-before-pr-close: -1
operations-per-run: 250
remove-stale-when-updated: true remove-stale-when-updated: true
stale-pr-label: "stale" stale-issue-label: "stale"
# Exempt new integrations, these often take more time. exempt-issue-labels: "no-stale,help-wanted,needs-more-information"
# They will automatically be handled by the 90 day version above. stale-issue-message: >
exempt-pr-labels: "no-stale,new-integration" There hasn't been any activity on this issue recently. Due to the
stale-pr-message: > high number of incoming GitHub notifications, we have to clean some
There hasn't been any activity on this pull request recently. This of the old issues, as many of them have already been resolved with
pull request has been automatically marked as stale because of that the latest updates.
and will be closed if no further activity occurs within 7 days.
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 # The 30 day stale policy for issues
# Used for: # Used for:
@ -81,12 +85,13 @@ jobs:
- name: Needs more information stale issues policy - name: Needs more information stale issues policy
uses: actions/stale@v7.0.0 uses: actions/stale@v7.0.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ steps.token.outputs.token }}
only-labels: "needs-more-information" only-labels: "needs-more-information"
days-before-stale: 14 days-before-stale: 14
days-before-close: 7 days-before-close: 7
days-before-pr-stale: -1
days-before-pr-close: -1 days-before-pr-close: -1
operations-per-run: 50 operations-per-run: 250
remove-stale-when-updated: true remove-stale-when-updated: true
stale-issue-label: "stale" stale-issue-label: "stale"
exempt-issue-labels: "no-stale,help-wanted" exempt-issue-labels: "no-stale,help-wanted"

View File

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

View File

@ -22,7 +22,7 @@ jobs:
architectures: ${{ steps.info.outputs.architectures }} architectures: ${{ steps.info.outputs.architectures }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Get information - name: Get information
id: info id: info
@ -57,13 +57,13 @@ jobs:
) > .env_file ) > .env_file
- name: Upload env_file - name: Upload env_file
uses: actions/upload-artifact@v3.1.1 uses: actions/upload-artifact@v3.1.2
with: with:
name: env_file name: env_file
path: ./.env_file path: ./.env_file
- name: Upload requirements_diff - name: Upload requirements_diff
uses: actions/upload-artifact@v3.1.1 uses: actions/upload-artifact@v3.1.2
with: with:
name: requirements_diff name: requirements_diff
path: ./requirements_diff.txt path: ./requirements_diff.txt
@ -79,7 +79,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }} arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Download env_file - name: Download env_file
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
@ -116,7 +116,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }} arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.3.0
- name: Download env_file - name: Download env_file
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
@ -144,6 +144,14 @@ jobs:
sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file} sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file}
done done
- 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 - name: Adjust build env
run: | run: |
if [ "${{ matrix.arch }}" = "i386" ]; then if [ "${{ matrix.arch }}" = "i386" ]; then
@ -159,7 +167,7 @@ jobs:
# Do not pin numpy in wheels building # Do not pin numpy in wheels building
sed -i "/numpy/d" homeassistant/package_constraints.txt sed -i "/numpy/d" homeassistant/package_constraints.txt
- name: Build wheels - name: Build wheels (part 1)
uses: home-assistant/wheels@2022.10.1 uses: home-assistant/wheels@2022.10.1
with: with:
abi: cp310 abi: cp310
@ -172,4 +180,19 @@ jobs:
legacy: true legacy: true
constraints: "homeassistant/package_constraints.txt" constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.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: repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.231
hooks:
- id: ruff
args:
- --fix
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.3.1 rev: v3.3.1
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py39-plus] args: [--py310-plus]
stages: [manual]
- repo: https://github.com/PyCQA/autoflake - repo: https://github.com/PyCQA/autoflake
rev: v2.0.0 rev: v2.0.0
hooks: hooks:
@ -11,6 +18,7 @@ repos:
args: args:
- --in-place - --in-place
- --remove-all-unused-imports - --remove-all-unused-imports
stages: [manual]
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.12.0 rev: 22.12.0
hooks: hooks:
@ -36,11 +44,12 @@ repos:
- pycodestyle==2.10.0 - pycodestyle==2.10.0
- pyflakes==3.0.1 - pyflakes==3.0.1
- flake8-docstrings==1.6.0 - flake8-docstrings==1.6.0
- pydocstyle==6.1.1 - pydocstyle==6.2.3
- flake8-comprehensions==3.10.1 - flake8-comprehensions==3.10.1
- flake8-noqa==1.3.0 - flake8-noqa==1.3.0
- mccabe==0.7.0 - mccabe==0.7.0
files: ^(homeassistant|script|tests)/.+\.py$ exclude: docs/source/conf.py
stages: [manual]
- repo: https://github.com/PyCQA/bandit - repo: https://github.com/PyCQA/bandit
rev: 1.7.4 rev: 1.7.4
hooks: hooks:
@ -51,11 +60,11 @@ repos:
- --configfile=tests/bandit.yaml - --configfile=tests/bandit.yaml
files: ^(homeassistant|script|tests)/.+\.py$ files: ^(homeassistant|script|tests)/.+\.py$
- repo: https://github.com/PyCQA/isort - repo: https://github.com/PyCQA/isort
rev: 5.11.4 rev: 5.12.0
hooks: hooks:
- id: isort - id: isort
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0 rev: v4.4.0
hooks: hooks:
- id: check-executables-have-shebangs - id: check-executables-have-shebangs
stages: [manual] stages: [manual]
@ -84,7 +93,7 @@ repos:
- id: python-typing-update - id: python-typing-update
stages: [manual] stages: [manual]
args: args:
- --py39-plus - --py310-plus
- --force - --force
- --keep-updates - --keep-updates
files: ^(homeassistant|tests|script)/.+\.py$ files: ^(homeassistant|tests|script)/.+\.py$

View File

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

14
.vscode/tasks.json vendored
View File

@ -41,6 +41,20 @@
}, },
"problemMatcher": [] "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", "label": "Pylint",
"type": "shell", "type": "shell",

View File

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

View File

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

View File

@ -6,19 +6,37 @@ coverage:
default: default:
target: 90 target: 90
threshold: 0.09 threshold: 0.09
config-flows: required:
target: auto target: auto
threshold: 1 threshold: 1
paths: paths:
- homeassistant/components/*/config_flow.py - 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: patch:
default: default:
target: auto target: auto
config-flows: required:
target: 100 target: 100
threshold: 0 threshold: 0
paths: paths:
- homeassistant/components/*/config_flow.py - 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 comment: false
# To make partial tests possible, # To make partial tests possible,

View File

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

View File

@ -1,21 +1,20 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# """Home Assistant documentation build configuration file.
# 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.
# 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.
# 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.
# 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 inspect
import os import os
import sys import sys
@ -25,7 +24,7 @@ from homeassistant.const import __short_version__, __version__
PROJECT_NAME = "Home Assistant" PROJECT_NAME = "Home Assistant"
PROJECT_PACKAGE_NAME = "homeassistant" PROJECT_PACKAGE_NAME = "homeassistant"
PROJECT_AUTHOR = "The Home Assistant Authors" PROJECT_AUTHOR = "The Home Assistant Authors"
PROJECT_COPYRIGHT = f" 2013-2020, {PROJECT_AUTHOR}" PROJECT_COPYRIGHT = PROJECT_AUTHOR
PROJECT_LONG_DESCRIPTION = ( PROJECT_LONG_DESCRIPTION = (
"Home Assistant is an open-source " "Home Assistant is an open-source "
"home automation platform running on Python 3. " "home automation platform running on Python 3. "
@ -110,17 +109,17 @@ def linkcode_resolve(domain, info):
for part in fullname.split("."): for part in fullname.split("."):
try: try:
obj = getattr(obj, part) obj = getattr(obj, part)
except: except Exception: # pylint: disable=broad-except
return None return None
try: try:
fn = inspect.getsourcefile(obj) fn = inspect.getsourcefile(obj)
except: except Exception: # pylint: disable=broad-except
fn = None fn = None
if not fn: if not fn:
return None return None
try: try:
source, lineno = inspect.findsource(obj) source, lineno = inspect.findsource(obj)
except: except Exception: # pylint: disable=broad-except
lineno = None lineno = None
if lineno: if lineno:
linespec = "#L%d" % (lineno + 1) linespec = "#L%d" % (lineno + 1)

View File

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

View File

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

View File

@ -555,7 +555,9 @@ class AuthStore:
"client_icon": refresh_token.client_icon, "client_icon": refresh_token.client_icon,
"token_type": refresh_token.token_type, "token_type": refresh_token.token_type,
"created_at": refresh_token.created_at.isoformat(), "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, "token": refresh_token.token,
"jwt_key": refresh_token.jwt_key, "jwt_key": refresh_token.jwt_key,
"last_used_at": refresh_token.last_used_at.isoformat() "last_used_at": refresh_token.last_used_at.isoformat()

View File

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

View File

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

View File

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

View File

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

View File

@ -346,7 +346,7 @@ def async_enable_logging(
if not log_no_color: if not log_no_color:
try: try:
# pylint: disable=import-outside-toplevel # pylint: disable-next=import-outside-toplevel
from colorlog import ColoredFormatter from colorlog import ColoredFormatter
# basicConfig must be called after importing colorlog in order to # 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( threading.excepthook = lambda args: logging.getLogger(None).exception(
"Uncaught thread 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 # 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) 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: if log_rotate_days:
err_handler = logging.handlers.TimedRotatingFileHandler( err_handler = logging.handlers.TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days 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: 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 loop_count = 0
setup_started: dict[str, datetime] = hass.data[DATA_SETUP_STARTED] setup_started: dict[str, datetime] = hass.data[DATA_SETUP_STARTED]
previous_was_empty = True previous_was_empty = True

View File

@ -1,5 +1,5 @@
{ {
"domain": "amazon", "domain": "amazon",
"name": "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_assistant_sdk",
"google_cloud", "google_cloud",
"google_domains", "google_domains",
"google_mail",
"google_maps", "google_maps",
"google_pubsub", "google_pubsub",
"google_sheets", "google_sheets",

View File

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

View File

@ -1,7 +1,7 @@
"""Support for Abode Security System alarm control panels.""" """Support for Abode Security System alarm control panels."""
from __future__ import annotations 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 import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature

View File

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

View File

@ -4,9 +4,9 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any, cast from typing import Any, cast
from abodepy.devices import CONST, AbodeDevice as AbodeDev from jaraco.abode.devices.base import Device as AbodeDev
from abodepy.devices.camera import AbodeCamera as AbodeCam from jaraco.abode.devices.camera import Camera as AbodeCam
import abodepy.helpers.timeline as TIMELINE from jaraco.abode.helpers import constants as CONST, timeline as TIMELINE
import requests import requests
from requests.models import Response from requests.models import Response
@ -30,7 +30,7 @@ async def async_setup_entry(
data: AbodeSystem = hass.data[DOMAIN] data: AbodeSystem = hass.data[DOMAIN]
async_add_entities( 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) 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 http import HTTPStatus
from typing import Any, cast from typing import Any, cast
from abodepy import Abode from jaraco.abode.client import Client as Abode
from abodepy.exceptions import AbodeAuthenticationException, AbodeException from jaraco.abode.exceptions import (
from abodepy.helpers.errors import MFA_CODE_REQUIRED AuthenticationException as AbodeAuthenticationException,
Exception as AbodeException,
)
from jaraco.abode.helpers.errors import MFA_CODE_REQUIRED
from requests.exceptions import ConnectTimeout, HTTPError from requests.exceptions import ConnectTimeout, HTTPError
import voluptuous as vol import voluptuous as vol
@ -15,7 +18,7 @@ from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.data_entry_flow import FlowResult 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" CONF_MFA = "mfa_code"
@ -35,7 +38,6 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
vol.Required(CONF_MFA): str, vol.Required(CONF_MFA): str,
} }
self._cache: str | None = None
self._mfa_code: str | None = None self._mfa_code: str | None = None
self._password: str | None = None self._password: str | None = None
self._polling: bool = False 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: async def _async_abode_login(self, step_id: str) -> FlowResult:
"""Handle login with Abode.""" """Handle login with Abode."""
self._cache = self.hass.config.path(DEFAULT_CACHEDB)
errors = {} errors = {}
try: try:
await self.hass.async_add_executor_job( 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: except AbodeException as ex:
@ -77,12 +78,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle multi-factor authentication (MFA) login with Abode.""" """Handle multi-factor authentication (MFA) login with Abode."""
try: try:
# Create instance to access login method for passing MFA code # Create instance to access login method for passing MFA code
abode = Abode( abode = Abode(auto_login=False, get_devices=False, get_automations=False)
auto_login=False,
get_devices=False,
get_automations=False,
cache_path=self._cache,
)
await self.hass.async_add_executor_job( await self.hass.async_add_executor_job(
abode.login, self._username, self._password, self._mfa_code abode.login, self._username, self._password, self._mfa_code
) )

View File

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

View File

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

View File

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

View File

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

View File

@ -3,11 +3,11 @@
"name": "Abode", "name": "Abode",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/abode", "documentation": "https://www.home-assistant.io/integrations/abode",
"requirements": ["abodepy==1.2.0"], "requirements": ["jaraco.abode==3.2.1"],
"codeowners": ["@shred86"], "codeowners": ["@shred86"],
"homekit": { "homekit": {
"models": ["Abode", "Iota"] "models": ["Abode", "Iota"]
}, },
"iot_class": "cloud_push", "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 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 ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,

View File

@ -3,7 +3,8 @@ from __future__ import annotations
from typing import Any, cast 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.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry 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.""" """Diagnostics support for AccuWeather."""
from __future__ import annotations from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE 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( async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: ConfigEntry
) -> dict: ) -> dict[str, Any]:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
coordinator: AccuWeatherDataUpdateCoordinator = hass.data[DOMAIN][ coordinator: AccuWeatherDataUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id config_entry.entry_id

View File

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

View File

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

View File

@ -1,5 +1,8 @@
{ {
"config": { "config": {
"abort": {
"already_configured": "Ier\u012bce jau pievienota Home Assistant."
},
"step": { "step": {
"cloud": { "cloud": {
"data": { "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( return DeviceInfo(
entry_type=DeviceEntryType.SERVICE, entry_type=DeviceEntryType.SERVICE,
identifiers={ 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", manufacturer="AdGuard Team",
name="AdGuard Home", 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", "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" "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.""" """Initialize."""
self.latitude = latitude self.latitude = latitude
self.longitude = longitude 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 self.use_nearest = use_nearest
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval) 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"], user_input["longitude"],
) )
if not location_point_valid: if not location_point_valid:
await test_location( location_nearest_valid = await test_location(
websession, websession,
user_input["api_key"], user_input["api_key"],
user_input["latitude"], user_input["latitude"],
@ -60,6 +60,8 @@ class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
errors["base"] = "wrong_location" errors["base"] = "wrong_location"
else: else:
if not location_point_valid: if not location_point_valid:
if not location_nearest_valid:
return self.async_abort(reason="wrong_location")
use_nearest = True use_nearest = True
return self.async_create_entry( return self.async_create_entry(
title=user_input[CONF_NAME], title=user_input[CONF_NAME],

View File

@ -1,6 +1,8 @@
"""Diagnostics support for Airly.""" """Diagnostics support for Airly."""
from __future__ import annotations from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( 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( async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: ConfigEntry
) -> dict: ) -> dict[str, Any]:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
coordinator: AirlyDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] 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%]" "invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]"
}, },
"abort": { "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": { "system_health": {

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Clau API inv\u00e0lida", "invalid_api_key": "Clau API inv\u00e0lida",

View File

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

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "\u0386\u03ba\u03c5\u03c1\u03bf API \u03ba\u03bb\u03b5\u03b9\u03b4\u03af", "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", "longitude": "\u0393\u03b5\u03c9\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03cc \u03bc\u03ae\u03ba\u03bf\u03c2",
"name": "\u038c\u03bd\u03bf\u03bc\u03b1" "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": { "config": {
"abort": { "abort": {
"already_configured": "Location is already configured" "already_configured": "Location is already configured",
"wrong_location": "No Airly measuring stations in this area."
}, },
"error": { "error": {
"invalid_api_key": "Invalid API key", "invalid_api_key": "Invalid API key",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Clave API no v\u00e1lida", "invalid_api_key": "Clave API no v\u00e1lida",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Vigane API v\u00f5ti", "invalid_api_key": "Vigane API v\u00f5ti",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "\u00c9rv\u00e9nytelen API kulcs", "invalid_api_key": "\u00c9rv\u00e9nytelen API kulcs",

View File

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

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Chiave API non valida", "invalid_api_key": "Chiave API non valida",

View File

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

View File

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

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Nieprawid\u0142owy klucz API", "invalid_api_key": "Nieprawid\u0142owy klucz API",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Chave de API inv\u00e1lida", "invalid_api_key": "Chave de API inv\u00e1lida",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.", "invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d", "invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "Ge\u00e7ersiz API anahtar\u0131", "invalid_api_key": "Ge\u00e7ersiz API anahtar\u0131",

View File

@ -1,7 +1,8 @@
{ {
"config": { "config": {
"abort": { "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": { "error": {
"invalid_api_key": "API \u91d1\u9470\u7121\u6548", "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", "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)" "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, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airthings_ble", "documentation": "https://www.home-assistant.io/integrations/airthings_ble",
"requirements": ["airthings-ble==0.5.3"], "requirements": ["airthings-ble==0.5.3"],
"dependencies": ["bluetooth"], "dependencies": ["bluetooth_adapters"],
"codeowners": ["@vincegio"], "codeowners": ["@vincegio"],
"iot_class": "local_polling", "iot_class": "local_polling",
"bluetooth": [ "bluetooth": [

View File

@ -154,7 +154,7 @@ class AirthingsSensor(
def __init__( def __init__(
self, self,
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator[AirthingsDevice],
airthings_device: AirthingsDevice, airthings_device: AirthingsDevice,
entity_description: SensorEntityDescription, entity_description: SensorEntityDescription,
) -> None: ) -> 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}", "flow_title": "{name}",
"step": { "step": {
"bluetooth_confirm": { "bluetooth_confirm": {
"description": "{name} kurulumunu yapmak istiyor musunuz?" "description": "{name} 'i kurmak istiyor musunuz?"
}, },
"user": { "user": {
"data": { "data": {
"address": "Cihaz" "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": { "data": {
"host": "\u039a\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03cc\u03c2 \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ae\u03c2" "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] PLATFORMS = [Platform.SENSOR]
DEFAULT_ATTRIBUTION = "Data provided by AirVisual" DEFAULT_ATTRIBUTION = "Data provided by AirVisual"
DEFAULT_NODE_PRO_UPDATE_INTERVAL = timedelta(minutes=1)
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False) 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.async_create_task(
hass.config_entries.flow.async_init( hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": source}, context={"source": SOURCE_IMPORT},
data={CONF_API_KEY: entry.data[CONF_API_KEY], **geography}, 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) LOGGER.error(err)
errors["base"] = "unknown" errors["base"] = "unknown"
valid_keys.add(user_input[CONF_API_KEY])
if errors: if errors:
return self.async_show_form( return self.async_show_form(
step_id=error_step, data_schema=error_schema, errors=errors step_id=error_step, data_schema=error_schema, errors=errors
) )
existing_entry = await self.async_set_unique_id(self._geo_id) valid_keys.add(user_input[CONF_API_KEY])
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.config_entries.async_update_entry(existing_entry, data=user_input)
self.hass.async_create_task( self.hass.async_create_task(
self.hass.config_entries.async_reload(existing_entry.entry_id) 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.""" """Define the config flow to handle options."""
return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW) 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( async def async_step_geography_by_coords(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> FlowResult: ) -> FlowResult:

View File

@ -19,11 +19,8 @@ from homeassistant.const import (
CONF_LONGITUDE, CONF_LONGITUDE,
CONF_SHOW_ON_MAP, CONF_SHOW_ON_MAP,
CONF_STATE, CONF_STATE,
PERCENTAGE,
UnitOfTemperature,
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
@ -37,17 +34,8 @@ ATTR_POLLUTANT_UNIT = "pollutant_unit"
ATTR_REGION = "region" ATTR_REGION = "region"
SENSOR_KIND_AQI = "air_quality_index" 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_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_POLLUTANT = "main_pollutant"
SENSOR_KIND_SENSOR_LIFE = "sensor_life"
SENSOR_KIND_TEMPERATURE = "temperature"
SENSOR_KIND_VOC = "voc"
GEOGRAPHY_SENSOR_DESCRIPTIONS = ( GEOGRAPHY_SENSOR_DESCRIPTIONS = (
SensorEntityDescription( SensorEntityDescription(
@ -82,70 +70,6 @@ GEOGRAPHY_SENSOR_DESCRIPTIONS = (
) )
GEOGRAPHY_SENSOR_LOCALES = {"cn": "Chinese", "us": "U.S."} 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_CO = "co"
STATE_POLLUTANT_LABEL_N2 = "n2" STATE_POLLUTANT_LABEL_N2 = "n2"

View File

@ -22,12 +22,6 @@
"country": "\u0421\u0442\u0440\u0430\u043d\u0430" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "API \u043a\u043b\u044e\u0447" "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", "description": "Utilitza l'API d'AirVisual per monitoritzar un/a ciutat/estat/pa\u00eds",
"title": "Configura una ubicaci\u00f3 geogr\u00e0fica" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "Clau API" "api_key": "Clau API"

View File

@ -24,13 +24,6 @@
"country": "Zem\u011b" "country": "Zem\u011b"
} }
}, },
"node_pro": {
"data": {
"ip_address": "Hostitel",
"password": "Heslo"
},
"title": "Nastaven\u00ed AirVisual Node/Pro"
},
"reauth_confirm": { "reauth_confirm": {
"data": { "data": {
"api_key": "Kl\u00ed\u010d API" "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.", "description": "Verwende die AirVisual Cloud API, um ein(e) Stadt/Bundesland/Land zu \u00fcberwachen.",
"title": "Konfiguriere einen Standort" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "API-Schl\u00fcssel" "api_key": "API-Schl\u00fcssel"

View File

@ -1,7 +1,7 @@
{ {
"config": { "config": {
"abort": { "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" "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": { "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.", "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" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "\u039a\u03bb\u03b5\u03b9\u03b4\u03af API" "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.", "description": "Use the AirVisual cloud API to monitor a city/state/country.",
"title": "Configure a Geography" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "API Key" "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.", "description": "Utilice la API en la nube de AirVisual para monitorear una ciudad/estado/pa\u00eds.",
"title": "Configurar una geograf\u00eda" "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": { "reauth_confirm": {
"title": "Vuelva a autenticar AirVisual" "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.", "description": "Usar la API de la nube de AirVisual para supervisar una ciudad/estado/pa\u00eds.",
"title": "Configurar una geograf\u00eda" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "Clave API" "api_key": "Clave API"

View File

@ -30,14 +30,6 @@
"description": "Kasuta AirVisual pilve API-t linna/osariigi/riigi j\u00e4lgimiseks.", "description": "Kasuta AirVisual pilve API-t linna/osariigi/riigi j\u00e4lgimiseks.",
"title": "Seadista Geography sidumine" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "API v\u00f5ti" "api_key": "API v\u00f5ti"

View File

@ -2,13 +2,6 @@
"config": { "config": {
"error": { "error": {
"general_error": "Tapahtui tuntematon virhe." "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.", "description": "Utilisez l'API cloud AirVisual pour surveiller une ville / un \u00e9tat / un pays.",
"title": "Configurer un lieu g\u00e9ographique" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "Cl\u00e9 d'API" "api_key": "Cl\u00e9 d'API"

View File

@ -22,13 +22,6 @@
"api_key": "\u05de\u05e4\u05ea\u05d7 API" "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": { "reauth_confirm": {
"data": { "data": {
"api_key": "\u05de\u05e4\u05ea\u05d7 API" "api_key": "\u05de\u05e4\u05ea\u05d7 API"

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